< Summary

Information
Class: IceRpc.ClientProtocolConnectionFactory
Assembly: IceRpc
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/ClientProtocolConnectionFactory.cs
Tag: 1321_24790053727
Line coverage
82%
Covered lines: 76
Uncovered lines: 16
Coverable lines: 92
Total lines: 156
Line coverage: 82.6%
Branch coverage
83%
Covered branches: 25
Total branches: 30
Branch coverage: 83.3%
Method coverage
100%
Covered methods: 3
Fully covered methods: 1
Total methods: 3
Method coverage: 100%
Full method coverage: 33.3%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)87.5%161690.9%
CreateConnection(...)78.57%171474.46%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/ClientProtocolConnectionFactory.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Internal;
 4using IceRpc.Transports;
 5using IceRpc.Transports.Internal;
 6using Microsoft.Extensions.Logging;
 7using Microsoft.Extensions.Logging.Abstractions;
 8using System.Net.Security;
 9
 10namespace IceRpc;
 11
 12/// <summary>Default implementation of <see cref="IClientProtocolConnectionFactory" />.</summary>
 13public sealed class ClientProtocolConnectionFactory : IClientProtocolConnectionFactory
 14{
 215    private static readonly string[] _iceParams = ["t", "z"];
 16
 17    private readonly ConnectionOptions _connectionOptions;
 18    private readonly IDuplexClientTransport _duplexClientTransport;
 19    private readonly DuplexConnectionOptions _duplexConnectionOptions;
 20    private readonly SslClientAuthenticationOptions? _iceClientAuthenticationOptions;
 21    private readonly SslClientAuthenticationOptions? _iceRpcClientAuthenticationOptions;
 22    private readonly ILogger _logger;
 23    private readonly IMultiplexedClientTransport _multiplexedClientTransport;
 24    private readonly MultiplexedConnectionOptions _multiplexedConnectionOptions;
 25
 26    /// <summary>Constructs a client protocol connection factory.</summary>
 27    /// <param name="connectionOptions">The connection options.</param>
 28    /// <param name="connectTimeout">The connect timeout.</param>
 29    /// <param name="clientAuthenticationOptions">The client authentication options.</param>
 30    /// <param name="duplexClientTransport">The duplex client transport. <see langword="null" /> is equivalent to <see
 31    /// cref="IDuplexClientTransport.Default" />.</param>
 32    /// <param name="multiplexedClientTransport">The multiplexed client transport. <see langword="null" /> is equivalent
 33    /// to <see cref="IMultiplexedClientTransport.Default" />.</param>
 34    /// <param name="logger">The logger. <see langword="null" /> is equivalent to <see cref="NullLogger.Instance" />.
 35    /// </param>
 9836    public ClientProtocolConnectionFactory(
 9837        ConnectionOptions connectionOptions,
 9838        TimeSpan connectTimeout,
 9839        SslClientAuthenticationOptions? clientAuthenticationOptions = null,
 9840        IDuplexClientTransport? duplexClientTransport = null,
 9841        IMultiplexedClientTransport? multiplexedClientTransport = null,
 9842        ILogger? logger = null)
 9843    {
 9844        if (clientAuthenticationOptions?.ApplicationProtocols is not null)
 045        {
 046            throw new ArgumentException(
 047                "The ApplicationProtocols property of the SSL client authentication options must be null. The ALPN is se
 048                nameof(clientAuthenticationOptions));
 49        }
 50
 9851        _connectionOptions = connectionOptions;
 52
 9853        _duplexClientTransport = duplexClientTransport ?? IDuplexClientTransport.Default;
 9854        _duplexConnectionOptions = new DuplexConnectionOptions
 9855        {
 9856            Pool = connectionOptions.Pool,
 9857            MinSegmentSize = connectionOptions.MinSegmentSize,
 9858        };
 59
 9860        _multiplexedClientTransport = multiplexedClientTransport ?? IMultiplexedClientTransport.Default;
 61
 62        // If the dispatcher is null, we don't allow the peer to open streams for incoming requests. The only stream
 63        // which is accepted locally is the control stream created by the peer.
 9864        _multiplexedConnectionOptions = new MultiplexedConnectionOptions
 9865        {
 9866            HandshakeTimeout = connectTimeout,
 9867
 9868            MaxBidirectionalStreams = connectionOptions.Dispatcher is null ? 0 :
 9869                connectionOptions.MaxIceRpcBidirectionalStreams,
 9870
 9871            // Add an additional stream for the icerpc protocol control stream.
 9872            MaxUnidirectionalStreams = connectionOptions.Dispatcher is null ? 1 :
 9873                connectionOptions.MaxIceRpcUnidirectionalStreams + 1,
 9874
 9875            Pool = connectionOptions.Pool,
 9876            MinSegmentSize = connectionOptions.MinSegmentSize,
 9877        };
 78
 79        // Clone and set ALPN for each protocol.
 9880        if (clientAuthenticationOptions is not null)
 581        {
 582            _iceClientAuthenticationOptions = clientAuthenticationOptions.ShallowClone();
 583            _iceClientAuthenticationOptions.ApplicationProtocols = [Protocol.Ice.AlpnProtocol];
 84
 585            _iceRpcClientAuthenticationOptions = clientAuthenticationOptions.ShallowClone();
 586            _iceRpcClientAuthenticationOptions.ApplicationProtocols = [Protocol.IceRpc.AlpnProtocol];
 587        }
 88
 9889        _logger = logger ?? NullLogger.Instance;
 9890    }
 91
 92    /// <summary>Creates a protocol connection to the specified server address.</summary>
 93    /// <param name="serverAddress">The address of the server.</param>
 94    /// <returns>The new protocol connection.</returns>
 95    /// <remarks>The protocol connection returned by this factory method is not connected. The caller must call
 96    /// <see cref="IProtocolConnection.ConnectAsync" /> exactly once on this connection before calling
 97    /// <see cref="IInvoker.InvokeAsync" />.</remarks>
 98    public IProtocolConnection CreateConnection(ServerAddress serverAddress)
 9999    {
 99100        var transportAddress = new TransportAddress
 99101            {
 99102                Host = serverAddress.Host,
 99103                Port = serverAddress.Port,
 99104                TransportName = serverAddress.Transport,
 99105                Params = serverAddress.Params
 99106            };
 107
 108        IProtocolConnection connection;
 99109        if (serverAddress.Protocol == Protocol.Ice)
 27110        {
 27111            SslClientAuthenticationOptions? clientAuthenticationOptions = _iceClientAuthenticationOptions;
 27112            if (clientAuthenticationOptions is null && _duplexClientTransport.IsSslRequired(serverAddress.Transport))
 0113            {
 0114                clientAuthenticationOptions = new SslClientAuthenticationOptions
 0115                {
 0116                    ApplicationProtocols = [Protocol.Ice.AlpnProtocol]
 0117                };
 0118            }
 119
 120            // Strip Ice-specific params ("t", "z") before passing to transport. These params have no
 121            // effect with IceRPC transports.
 27122            transportAddress = transportAddress with
 27123            {
 27124                Params = transportAddress.Params.RemoveRange(_iceParams)
 27125            };
 126
 27127            connection = new IceProtocolConnection(
 27128                _duplexClientTransport.CreateConnection(transportAddress, _duplexConnectionOptions, clientAuthentication
 27129                transportConnectionInformation: null,
 27130                _connectionOptions);
 27131        }
 132        else
 72133        {
 72134            SslClientAuthenticationOptions? clientAuthenticationOptions = _iceRpcClientAuthenticationOptions;
 72135            if (clientAuthenticationOptions is null && _multiplexedClientTransport.IsSslRequired(serverAddress.Transport
 0136            {
 0137                clientAuthenticationOptions = new SslClientAuthenticationOptions
 0138                {
 0139                    ApplicationProtocols = [Protocol.IceRpc.AlpnProtocol]
 0140                };
 0141            }
 142
 72143            connection = new IceRpcProtocolConnection(
 72144                _multiplexedClientTransport.CreateConnection(transportAddress, _multiplexedConnectionOptions, clientAuth
 72145                transportConnectionInformation: null,
 72146                _connectionOptions,
 72147                taskExceptionObserver: _logger == NullLogger.Instance ? null :
 72148                    new LogTaskExceptionObserver(_logger));
 72149        }
 150
 99151        connection = new MetricsProtocolConnectionDecorator(connection, Metrics.ClientMetrics, connectStarted: false);
 152
 99153        return _logger == NullLogger.Instance ? connection :
 99154            new LogProtocolConnectionDecorator(connection, serverAddress, remoteNetworkAddress: null, _logger);
 99155    }
 156}