< Summary

Information
Class: IceRpc.Transports.Tcp.Internal.TcpListener
Assembly: IceRpc
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/Transports/Tcp/Internal/TcpListener.cs
Tag: 592_20856082467
Line coverage
91%
Covered lines: 61
Uncovered lines: 6
Coverable lines: 67
Total lines: 111
Line coverage: 91%
Branch coverage
92%
Covered branches: 13
Total branches: 14
Branch coverage: 92.8%
Method coverage
100%
Covered methods: 4
Total methods: 4
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_ServerAddress()100%11100%
AcceptAsync()50%2.01288.23%
DisposeAsync()100%22100%
.ctor(...)100%10.091090.47%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/Transports/Tcp/Internal/TcpListener.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Buffers;
 4using System.Net;
 5using System.Net.Security;
 6using System.Net.Sockets;
 7
 8namespace IceRpc.Transports.Tcp.Internal;
 9
 10/// <summary>The listener implementation for the TCP transport.</summary>
 11internal sealed class TcpListener : IListener<IDuplexConnection>
 12{
 12813    public ServerAddress ServerAddress { get; }
 14
 15    private readonly SslServerAuthenticationOptions? _authenticationOptions;
 16    private readonly int _minSegmentSize;
 17    private readonly MemoryPool<byte> _pool;
 18    private readonly Socket _socket;
 19
 20    // Set to 1 when the listener is disposed.
 21    private volatile int _disposed;
 22
 23    public async Task<(IDuplexConnection, EndPoint)> AcceptAsync(CancellationToken cancellationToken)
 11124    {
 25        try
 11126        {
 11127            Socket acceptedSocket = await _socket.AcceptAsync(cancellationToken).ConfigureAwait(false);
 28
 8529            var tcpConnection = new TcpServerConnection(
 8530                acceptedSocket,
 8531                _authenticationOptions,
 8532                _pool,
 8533                _minSegmentSize);
 8534            return (tcpConnection, acceptedSocket.RemoteEndPoint!);
 35        }
 336        catch (SocketException exception)
 337        {
 338            if (exception.SocketErrorCode == SocketError.OperationAborted)
 339            {
 340                ObjectDisposedException.ThrowIf(_disposed == 1, this);
 041            }
 042            throw exception.ToIceRpcException();
 43        }
 8544    }
 45
 46    public ValueTask DisposeAsync()
 18947    {
 18948        if (Interlocked.Exchange(ref _disposed, 1) == 0)
 11649        {
 11650            _socket.Dispose();
 11651        }
 18952        return default;
 18953    }
 54
 12255    internal TcpListener(
 12256        ServerAddress serverAddress,
 12257        DuplexConnectionOptions options,
 12258        SslServerAuthenticationOptions? authenticationOptions,
 12259        TcpServerTransportOptions tcpOptions)
 12260    {
 12261        if (!IPAddress.TryParse(serverAddress.Host, out IPAddress? ipAddress))
 362        {
 363            throw new ArgumentException(
 364                $"Listening on the DNS name '{serverAddress.Host}' is not allowed; an IP address is required.",
 365                nameof(serverAddress));
 66        }
 67
 11968        _authenticationOptions = authenticationOptions?.Clone();
 11969        _minSegmentSize = options.MinSegmentSize;
 11970        _pool = options.Pool;
 71
 11972        if (_authenticationOptions is not null && _authenticationOptions.ApplicationProtocols is null)
 4073        {
 74            // Set ApplicationProtocols to "ice" or "icerpc" in the common situation where the application does not
 75            // specify any application protocol. This way, a connection request that carries an ALPN protocol ID can
 76            // only succeed if this protocol ID is a match.
 4077            _authenticationOptions.ApplicationProtocols = new List<SslApplicationProtocol>
 4078            {
 4079                new SslApplicationProtocol(serverAddress.Protocol.Name)
 4080            };
 4081        }
 82
 11983        var address = new IPEndPoint(ipAddress, serverAddress.Port);
 84
 85        // When using IPv6 address family we use the socket constructor without AddressFamily parameter to ensure
 86        // dual-mode socket are used in platforms that support them.
 11987        _socket = ipAddress.AddressFamily == AddressFamily.InterNetwork ?
 11988            new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp) :
 11989            new Socket(SocketType.Stream, ProtocolType.Tcp);
 90        try
 11991        {
 11992            _socket.ExclusiveAddressUse = true;
 11993            _socket.Configure(tcpOptions);
 11994            _socket.Bind(address);
 11695            address = (IPEndPoint)_socket.LocalEndPoint!;
 11696            _socket.Listen(tcpOptions.ListenBacklog);
 11697        }
 398        catch (SocketException exception)
 399        {
 3100            _socket.Dispose();
 3101            throw exception.ToIceRpcException();
 102        }
 0103        catch
 0104        {
 0105            _socket.Dispose();
 0106            throw;
 107        }
 108
 116109        ServerAddress = serverAddress with { Port = (ushort)address.Port };
 116110    }
 111}