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); } }
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); }
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();
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; } }
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); } } }
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; } }