< 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: 275_13775359185
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{
 25413    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)
 22024    {
 25        try
 22026        {
 22027            Socket acceptedSocket = await _socket.AcceptAsync(cancellationToken).ConfigureAwait(false);
 28
 16829            var tcpConnection = new TcpServerConnection(
 16830                acceptedSocket,
 16831                _authenticationOptions,
 16832                _pool,
 16833                _minSegmentSize);
 16834            return (tcpConnection, acceptedSocket.RemoteEndPoint!);
 35        }
 636        catch (SocketException exception)
 637        {
 638            if (exception.SocketErrorCode == SocketError.OperationAborted)
 639            {
 640                ObjectDisposedException.ThrowIf(_disposed == 1, this);
 041            }
 042            throw exception.ToIceRpcException();
 43        }
 16844    }
 45
 46    public ValueTask DisposeAsync()
 37647    {
 37648        if (Interlocked.Exchange(ref _disposed, 1) == 0)
 23049        {
 23050            _socket.Dispose();
 23051        }
 37652        return default;
 37653    }
 54
 24255    internal TcpListener(
 24256        ServerAddress serverAddress,
 24257        DuplexConnectionOptions options,
 24258        SslServerAuthenticationOptions? authenticationOptions,
 24259        TcpServerTransportOptions tcpOptions)
 24260    {
 24261        if (!IPAddress.TryParse(serverAddress.Host, out IPAddress? ipAddress))
 662        {
 663            throw new ArgumentException(
 664                $"Listening on the DNS name '{serverAddress.Host}' is not allowed; an IP address is required.",
 665                nameof(serverAddress));
 66        }
 67
 23668        _authenticationOptions = authenticationOptions?.Clone();
 23669        _minSegmentSize = options.MinSegmentSize;
 23670        _pool = options.Pool;
 71
 23672        if (_authenticationOptions is not null && _authenticationOptions.ApplicationProtocols is null)
 8073        {
 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.
 8077            _authenticationOptions.ApplicationProtocols = new List<SslApplicationProtocol>
 8078            {
 8079                new SslApplicationProtocol(serverAddress.Protocol.Name)
 8080            };
 8081        }
 82
 23683        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.
 23687        _socket = ipAddress.AddressFamily == AddressFamily.InterNetwork ?
 23688            new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp) :
 23689            new Socket(SocketType.Stream, ProtocolType.Tcp);
 90        try
 23691        {
 23692            _socket.ExclusiveAddressUse = true;
 23693            _socket.Configure(tcpOptions);
 23694            _socket.Bind(address);
 23095            address = (IPEndPoint)_socket.LocalEndPoint!;
 23096            _socket.Listen(tcpOptions.ListenBacklog);
 23097        }
 698        catch (SocketException exception)
 699        {
 6100            _socket.Dispose();
 6101            throw exception.ToIceRpcException();
 102        }
 0103        catch
 0104        {
 0105            _socket.Dispose();
 0106            throw;
 107        }
 108
 230109        ServerAddress = serverAddress with { Port = (ushort)address.Port };
 230110    }
 111}