Ejemplo n.º 1
0
        void OnAcceptTransport(TransportListener transportListener, TransportAsyncCallbackArgs args)
        {
            if (args.Exception != null)
            {
                Events.AcceptTransportInputError(args.Exception);
                ExceptionDispatchInfo.Capture(args.Exception).Throw();
            }

            AmqpConnection connection = null;

            try
            {
                connection = this.amqpSettings.RuntimeProvider.CreateConnection(
                    args.Transport,
                    (ProtocolHeader)args.UserToken,
                    false,
                    this.amqpSettings.Clone(),
                    this.connectionSettings.Clone());

                // Open the connection async but don't block waiting on it.
                this.OpenAmqpConnectionAsync(connection, AmqpConstants.DefaultTimeout)
                .ContinueWith(
                    task =>
                {
                    if (task.Exception != null)
                    {
                        Events.OpenConnectionError(task.Exception);
                    }
                },
                    TaskContinuationOptions.OnlyOnFaulted);
            }
            catch (Exception ex) when(ex.IsFatal() == false)
            {
                Events.AcceptTransportError(ex);
                connection?.SafeClose(ex);
            }
        }
Ejemplo n.º 2
0
        private async Task <AmqpConnection> EnsureConnection(TimeSpan timeout)
        {
            if (Logging.IsEnabled)
            {
                Logging.Enter(this, timeout, $"{nameof(EnsureConnection)}");
            }
            AmqpConnection amqpConnection = null;
            IAmqpAuthenticationRefresher amqpAuthenticationRefresher = null;
            AmqpCbsLink amqpCbsLink = null;
            bool        gain        = await Lock.WaitAsync(timeout).ConfigureAwait(false);

            if (!gain)
            {
                throw new TimeoutException();
            }
            try
            {
                if (AmqpConnection == null)
                {
                    if (Logging.IsEnabled)
                    {
                        Logging.Info(this, "Creating new AmqpConnection", $"{nameof(EnsureConnection)}");
                    }
                    // Create AmqpConnection
                    amqpConnection = await Connector.OpenConnectionAsync(timeout).ConfigureAwait(false);

                    if (DeviceIdentity.AuthenticationModel != AuthenticationModel.X509)
                    {
                        if (AmqpCbsLink == null)
                        {
                            if (Logging.IsEnabled)
                            {
                                Logging.Info(this, "Creating new AmqpCbsLink", $"{nameof(EnsureConnection)}");
                            }
                            amqpCbsLink = new AmqpCbsLink(amqpConnection);
                        }
                        else
                        {
                            amqpCbsLink = AmqpCbsLink;
                        }

                        if (DeviceIdentity.AuthenticationModel == AuthenticationModel.SasGrouped)
                        {
                            if (Logging.IsEnabled)
                            {
                                Logging.Info(this, "Creating connection width AmqpAuthenticationRefresher", $"{nameof(EnsureConnection)}");
                            }
                            amqpAuthenticationRefresher = new AmqpAuthenticationRefresher(DeviceIdentity, amqpCbsLink);
                            await amqpAuthenticationRefresher.InitLoopAsync(timeout).ConfigureAwait(false);
                        }
                    }
                    AmqpConnection = amqpConnection;
                    AmqpCbsLink    = amqpCbsLink;
                    AmqpAuthenticationRefresher = amqpAuthenticationRefresher;
                    AmqpConnection.Closed      += OnConnectionClosed;
                    if (Logging.IsEnabled)
                    {
                        Logging.Associate(this, AmqpConnection, $"{nameof(AmqpConnection)}");
                    }
                    if (Logging.IsEnabled)
                    {
                        Logging.Associate(this, AmqpCbsLink, $"{nameof(AmqpCbsLink)}");
                    }
                }
                else if (AmqpConnection.IsClosing())
                {
                    throw new IotHubCommunicationException("AMQP connection is closing.");
                }
                else
                {
                    amqpConnection = AmqpConnection;
                }
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                amqpCbsLink?.Close();
                amqpAuthenticationRefresher?.StopLoop();
                amqpConnection?.SafeClose();
                throw;
            }
            finally
            {
                Lock.Release();
            }
            if (Logging.IsEnabled)
            {
                Logging.Exit(this, timeout, $"{nameof(EnsureConnection)}");
            }
            return(amqpConnection);
        }
Ejemplo n.º 3
0
 static void CloseConnection(AmqpConnection connection)
 {
     MessagingEventSource.Log.AmqpConnectionClosed(connection);
     connection.SafeClose();
 }
 static void CloseConnection(AmqpConnection connection)
 {
     connection.SafeClose();
 }
 /// <summary>
 ///   Performs the tasks needed to close a connection.
 /// </summary>
 ///
 /// <param name="connection">The connection to close.</param>
 ///
 protected virtual void CloseConnection(AmqpConnection connection) => connection.SafeClose();
Ejemplo n.º 6
0
        protected virtual async Task<AmqpSession> CreateSessionAsync(TimeSpan timeout, CancellationToken token)
        {
            this.OnCreateSession();

            var timeoutHelper = new TimeoutHelper(timeout);

            AmqpSettings amqpSettings = CreateAmqpSettings();
            TransportBase transport;

            token.ThrowIfCancellationRequested();

            switch (this.AmqpTransportSettings.GetTransportType())
            {
                case TransportType.Amqp_WebSocket_Only:
                    transport = await this.CreateClientWebSocketTransportAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                    break;
                case TransportType.Amqp_Tcp_Only:
                    TlsTransportSettings tlsTransportSettings = this.CreateTlsTransportSettings();
                    var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings);
                    transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                    break;
                default:
                    throw new InvalidOperationException("AmqpTransportSettings must specify WebSocketOnly or TcpOnly");
            }

            var amqpConnectionSettings = new AmqpConnectionSettings()
            {
                MaxFrameSize = AmqpConstants.DefaultMaxFrameSize,
                ContainerId = Guid.NewGuid().ToString("N"),
                HostName = this.hostName
            };

            var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings);
            try
            {
                token.ThrowIfCancellationRequested();
                await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                var sessionSettings = new AmqpSessionSettings()
                {
                    Properties = new Fields()
                };

                AmqpSession amqpSession = amqpConnection.CreateSession(sessionSettings);
                token.ThrowIfCancellationRequested();
                await amqpSession.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                // This adds itself to amqpConnection.Extensions
                var cbsLink = new AmqpCbsLink(amqpConnection);
                return amqpSession;
            }
            catch (Exception ex) when (!ex.IsFatal())
            {
                if (amqpConnection.TerminalException != null)
                {
                    throw AmqpClientHelper.ToIotHubClientContract(amqpConnection.TerminalException);
                }

                amqpConnection.SafeClose(ex);
                throw;
            }
        }
Ejemplo n.º 7
0
        async Task OpenAmqpConnectionAsync(AmqpConnection amqpConnection, TimeSpan defaultTimeout)
        {
            if (await SafeOpenConnectionAsync())
            {
                try
                {
                    if (this.incomingConnectionMap.TryAdd(amqpConnection.Identifier.Value, amqpConnection))
                    {
                        amqpConnection.SafeAddClosed((s, e) => this.incomingConnectionMap.TryRemove(amqpConnection.Identifier.Value, out AmqpConnection _));
                    }
                    else
                    {
                        Events.ConnectionContextAddFailed(amqpConnection.Identifier.Value);
                    }
                }
                catch (Exception e) when(!e.IsFatal())
                {
                    Events.OpenConnectionError(e);
                    amqpConnection.SafeClose(e);
                }
            }

            async Task <bool> SafeOpenConnectionAsync()
            {
                try
                {
                    await amqpConnection.OpenAsync(defaultTimeout);

                    return(true);
                }
                catch (Exception e) when(!e.IsFatal())
                {
                    Events.AmqpConnectionOpenAsyncFailed(e);

                    switch (e)
                    {
                    case OperationCanceledException _:
                        amqpConnection.SafeClose(new EdgeHubConnectionException("Operation Canceled Exception"));
                        break;

                    case TimeoutException _:
                        amqpConnection.SafeClose(new EdgeHubConnectionException("Timeout Exception"));
                        break;

                    case IOException _:
                        amqpConnection.SafeClose(new EdgeHubConnectionException("IO Exception"));
                        break;

                    case SocketException _:
                        amqpConnection.SafeClose(new EdgeHubConnectionException("Socket Exception"));
                        break;

                    case AmqpException ae when ae.Error.Condition.Equals(AmqpErrorCode.ConnectionForced):
                        amqpConnection.SafeClose(new EdgeHubConnectionException("AMQP connection forced exception"));

                        break;

                    default:
                        amqpConnection.SafeClose(e);
                        break;
                    }

                    return(false);
                }
            }
        }
Ejemplo n.º 8
0
        private async Task <AmqpSession> CreateSessionAsync(TimeSpan timeout)
        {
            Logging.Enter(this, timeout, nameof(CreateSessionAsync));

            TransportBase transport = null;

            try
            {
                var timeoutHelper = new TimeoutHelper(timeout);
                _refreshTokenTimer.Cancel();

                AmqpSettings amqpSettings = CreateAmqpSettings();
                if (_useWebSocketOnly)
                {
                    // Try only AMQP transport over WebSocket
                    transport = _clientWebSocketTransport = (ClientWebSocketTransport) await CreateClientWebSocketTransportAsync(timeoutHelper.RemainingTime())
                                                            .ConfigureAwait(false);
                }
                else
                {
                    TlsTransportSettings tlsTransportSettings = CreateTlsTransportSettings();
                    var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings);
                    try
                    {
                        transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                    }
                    catch (Exception e) when(!(e is AuthenticationException))
                    {
                        Logging.Error(this, e, nameof(CreateSessionAsync));

                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }

                        // AMQP transport over TCP failed. Retry AMQP transport over WebSocket
                        if (timeoutHelper.RemainingTime() != TimeSpan.Zero)
                        {
                            transport = _clientWebSocketTransport = (ClientWebSocketTransport) await CreateClientWebSocketTransportAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                Logging.Info(this, $"Initialized {nameof(TransportBase)}, ws={_useWebSocketOnly}");

                var amqpConnectionSettings = new AmqpConnectionSettings
                {
                    MaxFrameSize = AmqpConstants.DefaultMaxFrameSize,
                    ContainerId  = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), // Use a human readable link name to help with debugging
                    HostName     = Credential.AmqpEndpoint.Host,
                };

                var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings);
                await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                Logging.Info(this, $"{nameof(AmqpConnection)} opened.");

                var sessionSettings = new AmqpSessionSettings
                {
                    Properties = new Fields(),
                };

                try
                {
                    AmqpSession amqpSession = amqpConnection.CreateSession(sessionSettings);
                    await amqpSession.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                    Logging.Info(this, $"{nameof(AmqpSession)} opened.");

                    // This adds itself to amqpConnection.Extensions
                    var cbsLink = new AmqpCbsLink(amqpConnection);
                    await SendCbsTokenAsync(cbsLink, timeoutHelper.RemainingTime()).ConfigureAwait(false);

                    return(amqpSession);
                }
                catch (Exception ex) when(!ex.IsFatal())
                {
                    Logging.Error(this, ex, nameof(CreateSessionAsync));

                    _clientWebSocketTransport?.Dispose();
                    _clientWebSocketTransport = null;

                    if (amqpConnection.TerminalException != null)
                    {
                        throw AmqpClientHelper.ToIotHubClientContract(amqpConnection.TerminalException);
                    }

                    amqpConnection.SafeClose(ex);
                    throw;
                }
            }
            finally
            {
                Logging.Exit(this, timeout, nameof(CreateSessionAsync));
            }
        }
        async Task <AmqpSession> CreateSessionAsync(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);

            this.refreshTokenTimer.Cancel();

            var           amqpSettings = CreateAmqpSettings();
            TransportBase transport;

            if (this.useWebSocketOnly)
            {
                // Try only Amqp transport over WebSocket
                transport = await this.CreateClientWebSocketTransport(timeoutHelper.RemainingTime());
            }
            else
            {
                var tlsTransportSettings   = this.CreateTlsTransportSettings();
                var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings);
                try
                {
                    transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime());
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }

                    // Amqp transport over TCP failed. Retry Amqp transport over WebSocket
                    if (timeoutHelper.RemainingTime() != TimeSpan.Zero)
                    {
                        transport = await this.CreateClientWebSocketTransport(timeoutHelper.RemainingTime());
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            AmqpConnectionSettings amqpConnectionSettings = new AmqpConnectionSettings()
            {
                MaxFrameSize = AmqpConstants.DefaultMaxFrameSize,
                ContainerId  = Guid.NewGuid().ToString("N"),
                HostName     = this.connectionString.AmqpEndpoint.Host
            };

            var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings);
            await amqpConnection.OpenAsync(timeoutHelper.RemainingTime());

            var sessionSettings = new AmqpSessionSettings()
            {
                Properties = new Fields()
            };

            try
            {
                var amqpSession = amqpConnection.CreateSession(sessionSettings);
                await amqpSession.OpenAsync(timeoutHelper.RemainingTime());

                // This adds itself to amqpConnection.Extensions
                var cbsLink = new AmqpCbsLink(amqpConnection);
                await this.SendCbsTokenAsync(cbsLink, timeoutHelper.RemainingTime());

                return(amqpSession);
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                if (amqpConnection.TerminalException != null)
                {
                    throw AmqpClientHelper.ToIotHubClientContract(amqpConnection.TerminalException);
                }

                amqpConnection.SafeClose(ex);
                throw;
            }
        }