public async Task ConstructorCreatesTheConnection() { var endpoint = new Uri("amqp://test.service.gov"); var eventHub = "myHub"; var credential = Mock.Of <TokenCredential>(); var transport = TransportType.AmqpTcp; var identifier = "customIdentIFIER"; var mockConnection = new AmqpConnection(new MockTransport(), CreateMockAmqpSettings(), new AmqpConnectionSettings()); var mockScope = new Mock <AmqpConnectionScope>(endpoint, eventHub, credential, transport, null, identifier) { CallBase = true }; mockScope .Protected() .Setup <Task <AmqpConnection> >("CreateConnectionAsync", ItExpr.IsAny <Version>(), ItExpr.Is <Uri>(value => value == endpoint), ItExpr.Is <TransportType>(value => value == transport), ItExpr.Is <IWebProxy>(value => value == null), ItExpr.Is <string>(value => value == identifier), ItExpr.IsAny <TimeSpan>()) .Returns(Task.FromResult(mockConnection)) .Verifiable(); var connection = await GetActiveConnection(mockScope.Object).GetOrCreateAsync(TimeSpan.FromDays(1)); Assert.That(connection, Is.SameAs(mockConnection), "The connection instance should have been returned"); mockScope.VerifyAll(); }
public async Task <AmqpConnection> OpenConnectionAsync(TimeSpan timeout) { if (Logging.IsEnabled) { Logging.Enter(this, timeout, $"{nameof(OpenConnectionAsync)}"); } TransportBase transportBase = null; try { transportBase = await InitializeTransport(timeout).ConfigureAwait(false); AmqpConnection amqpConnection = new AmqpConnection(transportBase, AmqpSettings, AmqpConnectionSettings); await amqpConnection.OpenAsync(timeout).ConfigureAwait(false); if (Logging.IsEnabled) { Logging.Exit(this, timeout, $"{nameof(OpenConnectionAsync)}"); } return(amqpConnection); } catch (Exception) { transportBase?.Close(); throw; } }
/// <summary> /// Creates the timer event handler to support refreshing AMQP link authorization /// on a recurring basis. /// </summary> /// /// <param name="connection">The AMQP connection to which the link being refreshed is bound to.</param> /// <param name="amqpLink">The AMQO link to refresh authorization for.</param> /// <param name="tokenProvider">The <see cref="CbsTokenProvider" /> to use for obtaining access tokens.</param> /// <param name="endpoint">The Event Hubs service endpoint that the AMQP link is communicating with.</param> /// <param name="audience">The audience associated with the authorization. This is likely the <paramref name="endpoint"/> absolute URI.</param> /// <param name="resource">The resource associated with the authorization. This is likely the <paramref name="endpoint"/> absolute URI.</param> /// <param name="requiredClaims">The set of claims required to support the operations of the AMQP link.</param> /// <param name="refreshTimeout">The timeout to apply when requesting authorization refresh.</param> /// <param name="refreshTimerFactory">A function to allow retrieving the <see cref="Timer" /> associated with the link authorization.</param> /// /// <returns>A <see cref="TimerCallback"/> delegate to perform the refresh when a timer is due.</returns> /// protected virtual TimerCallback CreateAuthorizationRefreshHandler(AmqpConnection connection, AmqpObject amqpLink, CbsTokenProvider tokenProvider, Uri endpoint, string audience, string resource, string[] requiredClaims, TimeSpan refreshTimeout, Func <Timer> refreshTimerFactory) { return(async _ => { EventHubsEventSource.Log.AmqpLinkAuthorizationRefreshStart(EventHubName, endpoint.AbsoluteUri); var refreshTimer = refreshTimerFactory(); try { var authExpirationUtc = await RequestAuthorizationUsingCbsAsync(connection, tokenProvider, endpoint, audience, resource, requiredClaims, refreshTimeout).ConfigureAwait(false); // Reset the timer for the next refresh. if (authExpirationUtc >= DateTimeOffset.UtcNow) { refreshTimer.Change(CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan); } EventHubsEventSource.Log.AmqpLinkAuthorizationRefreshComplete(EventHubName, endpoint.AbsoluteUri); } catch (Exception ex) { EventHubsEventSource.Log.AmqpLinkAuthorizationRefreshError(EventHubName, endpoint.AbsoluteUri, ex.Message); refreshTimer.Change(Timeout.Infinite, Timeout.Infinite); } }); }
private async Task <Controller> CreateControllerAsync(TimeSpan timeout) { var stopWatch = ValueStopwatch.StartNew(); AmqpConnection connection = await ActiveConnection.GetOrCreateAsync(timeout.CalculateRemaining(stopWatch.GetElapsedTime())).ConfigureAwait(false); var sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; AmqpSession amqpSession = null; Controller controller; try { amqpSession = connection.CreateSession(sessionSettings); await amqpSession.OpenAsync(timeout.CalculateRemaining(stopWatch.GetElapsedTime())).ConfigureAwait(false); controller = new Controller(amqpSession, timeout.CalculateRemaining(stopWatch.GetElapsedTime())); await controller.OpenAsync(timeout.CalculateRemaining(stopWatch.GetElapsedTime())).ConfigureAwait(false); } catch (Exception exception) { if (amqpSession != null) { await amqpSession.CloseAsync(timeout).ConfigureAwait(false); } ServiceBusEventSource.Log.CreateControllerException(ActiveConnection.ToString(), exception.ToString()); throw; } return(controller); }
public async Task OpenAsync(TimeSpan timeout, bool useWebSocket, X509Certificate2 clientCert) { var hostName = _uri.Host; var tcpSettings = new TcpTransportSettings { Host = hostName, Port = _uri.Port != -1 ? _uri.Port : AmqpConstants.DefaultSecurePort }; TransportSettings = new TlsTransportSettings(tcpSettings) { TargetHost = hostName, CertificateValidationCallback = (sender, cert, chain, errors) => true, Certificate = clientCert }; TransportBase transport; if (useWebSocket) { transport = await CreateClientWebSocketTransportAsync(timeout).ConfigureAwait(false); } else { var tcpInitiator = new AmqpTransportInitiator(_amqpSettings, TransportSettings); transport = await tcpInitiator.ConnectTaskAsync(timeout).ConfigureAwait(false); } AmqpConnection = new AmqpConnection(transport, _amqpSettings, AmqpConnectionSettings); await AmqpConnection.OpenAsync(timeout).ConfigureAwait(false); _isConnectionClosed = false; AmqpConnection.Closed += OnConnectionClosed; }
void OnAcceptTransport(TransportListener listener, TransportAsyncCallbackArgs args) { AmqpConnectionSettings connectionSettings = new AmqpConnectionSettings() { ContainerId = this.containerId, MaxFrameSize = this.maxFrameSize }; AmqpConnection connection = null; try { connection = this.CreateConnection( args.Transport, (ProtocolHeader)args.UserToken, false, this.settings, connectionSettings); connection.BeginOpen(connection.DefaultOpenTimeout, this.OnConnectionOpenComplete, connection); } catch (Exception ex) { if (connection != null) { connection.SafeClose(ex); } } }
public void AmqpSessionCreationException(string entityPath, AmqpConnection connection, Exception exception) { if (this.IsEnabled()) { this.AmqpSessionCreationException(entityPath, connection.ToString(), connection.State.ToString(), exception.ToString()); } }
/// <summary> /// Opens an AMQP link for use with producer operations. /// </summary> /// <param name="entityPath"></param> /// <param name="viaEntityPath">The entity path to route the message through. Useful when using transactions.</param> /// <param name="timeout">The timeout to apply when creating the link.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// /// <returns>A link for use with producer operations.</returns> /// public virtual async Task <SendingAmqpLink> OpenSenderLinkAsync( string entityPath, string viaEntityPath, TimeSpan timeout, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); var stopWatch = Stopwatch.StartNew(); AmqpConnection connection = await ActiveConnection.GetOrCreateAsync(timeout).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); SendingAmqpLink link = await CreateSendingLinkAsync( entityPath, viaEntityPath, connection, timeout.CalculateRemaining(stopWatch.Elapsed), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); await OpenAmqpObjectAsync(link, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); stopWatch.Stop(); return(link); }
public void AmqpConnectionCreated(string hostName, AmqpConnection connection) { if (this.IsEnabled()) { this.AmqpConnectionCreated(hostName, connection.ToString(), connection.State.ToString()); } }
public void AmqpConnectionClosed(AmqpConnection connection) { if (this.IsEnabled()) { this.AmqpConnectionClosed(connection.RemoteEndpoint.ToString(), connection.ToString(), connection.State.ToString()); } }
protected override AmqpObject OnCreateAmqpLink(AmqpConnection connection, AmqpLinkSettings linkSettings, AmqpSession amqpSession) { AmqpObject link = new RequestResponseAmqpLink(AmqpClientConstants.EntityTypeManagement, amqpSession, this.entityPath, linkSettings.Properties); linkSettings.LinkName = $"{connection.Settings.ContainerId};{connection.Identifier}:{amqpSession.Identifier}:{link.Identifier}:{this.ClientId}"; return(link); }
private async Task <AmqpConnection> CreateConnectionAsync(TimeSpan timeout) { string hostName = ConnectionStringBuilder.Endpoint.Host; int port = ConnectionStringBuilder.Endpoint.Port; bool useWebSockets = ConnectionStringBuilder.TransportType == TrackOne.TransportType.AmqpWebSockets; var timeoutHelper = new TimeoutHelper(timeout); AmqpSettings amqpSettings = CreateAmqpSettings( amqpVersion: AmqpVersion, useSslStreamSecurity: true, hasTokenProvider: true, useWebSockets: useWebSockets); TransportSettings tpSettings = useWebSockets ? CreateWebSocketsTransportSettings(hostName, WebProxy) : CreateTcpTlsTransportSettings(hostName, port); var initiator = new AmqpTransportInitiator(amqpSettings, tpSettings); TransportBase transport = await initiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); AmqpConnectionSettings connectionSettings = CreateAmqpConnectionSettings(MaxFrameSize, ContainerId, hostName); var connection = new AmqpConnection(transport, amqpSettings, connectionSettings); await connection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Always create the CBS Link + Session var cbsLink = new AmqpCbsLink(connection); if (connection.Extensions.Find <AmqpCbsLink>() == null) { connection.Extensions.Add(cbsLink); } return(connection); }
async Task <AmqpConnection> CreateConnectionAsync(TimeSpan timeout) { var hostName = this.Endpoint.Host; var timeoutHelper = new TimeoutHelper(timeout); var amqpSettings = AmqpConnectionHelper.CreateAmqpSettings( amqpVersion: AmqpVersion, useSslStreamSecurity: true, hasTokenProvider: true, useWebSockets: TransportType == TransportType.AmqpWebSockets); var transportSettings = CreateTransportSettings(); var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, transportSettings); var transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); var containerId = Guid.NewGuid().ToString(); var amqpConnectionSettings = AmqpConnectionHelper.CreateAmqpConnectionSettings(AmqpConstants.DefaultMaxFrameSize, containerId, hostName); var connection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings); await connection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Always create the CBS Link + Session var cbsLink = new AmqpCbsLink(connection); if (connection.Extensions.Find <AmqpCbsLink>() == null) { connection.Extensions.Add(cbsLink); } MessagingEventSource.Log.AmqpConnectionCreated(hostName, connection); return(connection); }
public async Task <AmqpObject> CreateAndOpenAmqpLinkAsync() { TimeoutHelper timeoutHelper = new TimeoutHelper(this.serviceBusConnection.OperationTimeout); AmqpConnection connection = await this.serviceBusConnection.ConnectionManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Authenticate over CBS AmqpCbsLink cbsLink = connection.Extensions.Find <AmqpCbsLink>(); Uri address = new Uri(this.serviceBusConnection.Endpoint, this.entityPath); string audience = address.AbsoluteUri; string resource = address.AbsoluteUri; await cbsLink.SendTokenAsync(this.cbsTokenProvider, address, audience, resource, this.requiredClaims, timeoutHelper.RemainingTime()).ConfigureAwait(false); AmqpSession session = null; try { // Create our Session AmqpSessionSettings sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; session = connection.CreateSession(sessionSettings); await session.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Create our Link AmqpObject link = this.OnCreateAmqpLink(connection, this.amqpLinkSettings, session); await link.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); return(link); } catch (Exception) { session?.Abort(); throw; } }
private async Task <Controller> CreateControllerAsync(TimeSpan timeout) { var timeoutHelper = new TimeoutHelper(timeout, true); AmqpConnection connection = await ActiveConnection.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); var sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; AmqpSession amqpSession = null; Controller controller; try { amqpSession = connection.CreateSession(sessionSettings); await amqpSession.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); controller = new Controller(amqpSession, timeoutHelper.RemainingTime()); await controller.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); } catch (Exception exception) { if (amqpSession != null) { await amqpSession.CloseAsync(timeout).ConfigureAwait(false); } MessagingEventSource.Log.AmqpCreateControllerException(ActiveConnection.ToString(), exception); throw; } return(controller); }
async Task <AmqpConnection> CreateConnectionAsync(TimeSpan timeout) { string hostName = this.ConnectionStringBuilder.Endpoint.Host; string networkHost = this.ConnectionStringBuilder.Endpoint.Host; int port = this.ConnectionStringBuilder.Endpoint.Port; var timeoutHelper = new TimeoutHelper(timeout); var amqpSettings = CreateAmqpSettings( amqpVersion: this.AmqpVersion, useSslStreamSecurity: true, hasTokenProvider: true); TransportSettings tpSettings = CreateTcpTransportSettings( networkHost: networkHost, hostName: hostName, port: port, useSslStreamSecurity: true); var initiator = new AmqpTransportInitiator(amqpSettings, tpSettings); var transport = await initiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); var connectionSettings = CreateAmqpConnectionSettings(this.MaxFrameSize, this.ContainerId, hostName); var connection = new AmqpConnection(transport, amqpSettings, connectionSettings); await connection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Always create the CBS Link + Session var cbsLink = new AmqpCbsLink(connection); if (connection.Extensions.Find <AmqpCbsLink>() == null) { connection.Extensions.Add(cbsLink); } return(connection); }
internal async Task <AmqpIoTConnection> OpenConnectionAsync(TimeSpan timeout) { if (Logging.IsEnabled) { Logging.Enter(this, $"{nameof(OpenConnectionAsync)}"); } TransportBase transportBase = await _amqpIoTTransport.Initialize(timeout).ConfigureAwait(false); try { _amqpConnection = new AmqpConnection(transportBase, _amqpSettings, _amqpConnectionSettings); _amqpConnection.Closed += _amqpConnectionClosed; await _amqpConnection.OpenAsync(timeout).ConfigureAwait(false); if (Logging.IsEnabled) { Logging.Exit(this, timeout, $"{nameof(OpenConnectionAsync)}"); } return(this); } catch (Exception) { transportBase?.Close(); throw; } finally { if (Logging.IsEnabled) { Logging.Exit(this, $"{nameof(OpenConnectionAsync)}"); } } }
protected override AmqpObject OnCreateAmqpLink(AmqpConnection connection, AmqpLinkSettings linkSettings, AmqpSession amqpSession) { AmqpObject link = (linkSettings.IsReceiver()) ? (AmqpObject) new ReceivingAmqpLink(linkSettings) : (AmqpObject) new SendingAmqpLink(linkSettings); linkSettings.LinkName = $"{connection.Settings.ContainerId};{connection.Identifier}:{amqpSession.Identifier}:{link.Identifier}"; ((AmqpLink)link).AttachTo(amqpSession); return(link); }
static void UnsharedIdleConnectionHandler(Object sender, EventArgs empty) { if (sender is AmqpConnection) { AmqpConnection connection = (AmqpConnection)sender; connection.Close(); } }
public async Task <Tuple <AmqpObject, DateTime> > CreateAndOpenAmqpLinkAsync() { TimeoutHelper timeoutHelper = new TimeoutHelper(this.serviceBusConnection.OperationTimeout); MessagingEventSource.Log.AmqpGetOrCreateConnectionStart(); AmqpConnection connection = await this.serviceBusConnection.ConnectionManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); MessagingEventSource.Log.AmqpGetOrCreateConnectionStop(this.entityPath, connection.ToString(), connection.State.ToString()); // Authenticate over CBS AmqpCbsLink cbsLink = connection.Extensions.Find <AmqpCbsLink>(); string resource = this.endpointAddress.AbsoluteUri; MessagingEventSource.Log.AmqpSendAuthenticanTokenStart(this.endpointAddress, resource, resource, this.requiredClaims); DateTime cbsTokenExpiresAtUtc = await cbsLink.SendTokenAsync(this.cbsTokenProvider, this.endpointAddress, resource, resource, this.requiredClaims, timeoutHelper.RemainingTime()).ConfigureAwait(false); MessagingEventSource.Log.AmqpSendAuthenticanTokenStop(); AmqpSession session = null; try { // Create Session AmqpSessionSettings sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; session = connection.CreateSession(sessionSettings); await session.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); } catch (Exception exception) { MessagingEventSource.Log.AmqpSessionCreationException(this.entityPath, connection, exception); session?.Abort(); throw AmqpExceptionHelper.GetClientException(exception, null, session.GetInnerException()); } AmqpObject link = null; try { // Create Link link = this.OnCreateAmqpLink(connection, this.amqpLinkSettings, session); await link.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); return(new Tuple <AmqpObject, DateTime>(link, cbsTokenExpiresAtUtc)); } catch (Exception exception) { MessagingEventSource.Log.AmqpLinkCreationException( this.entityPath, session, connection, exception); throw AmqpExceptionHelper.GetClientException(exception, null, link?.GetInnerException(), session.IsClosing()); } }
public async Task <AmqpIoTConnection> OpenConnectionAsync(TimeSpan timeout) { if (Logging.IsEnabled) { Logging.Enter(this, timeout, $"{nameof(OpenConnectionAsync)}"); } var amqpSettings = new AmqpSettings(); var amqpTransportProvider = new AmqpTransportProvider(); amqpTransportProvider.Versions.Add(s_amqpVersion_1_0_0); amqpSettings.TransportProviders.Add(amqpTransportProvider); var amqpConnectionSettings = new AmqpConnectionSettings() { MaxFrameSize = AmqpConstants.DefaultMaxFrameSize, ContainerId = CommonResources.GetNewStringGuid(), HostName = _hostName }; TimeSpan idleTimeout = _amqpTransportSettings.IdleTimeout; if (idleTimeout != null) { amqpConnectionSettings.IdleTimeOut = Convert.ToUInt32(idleTimeout.TotalMilliseconds); } var amqpIoTTransport = new AmqpIoTTransport(amqpSettings, _amqpTransportSettings, _hostName, s_disableServerCertificateValidation); TransportBase transportBase = await amqpIoTTransport.InitializeAsync(timeout).ConfigureAwait(false); try { var amqpConnection = new AmqpConnection(transportBase, amqpSettings, amqpConnectionSettings); AmqpIoTConnection amqpIoTConnection = new AmqpIoTConnection(amqpConnection); amqpConnection.Closed += amqpIoTConnection.AmqpConnectionClosed; await amqpConnection.OpenAsync(timeout).ConfigureAwait(false); if (Logging.IsEnabled) { Logging.Exit(this, timeout, $"{nameof(OpenConnectionAsync)}"); } return(amqpIoTConnection); } catch (Exception e) when(!e.IsFatal()) { transportBase?.Close(); throw; } finally { if (Logging.IsEnabled) { Logging.Exit(this, $"{nameof(OpenConnectionAsync)}"); } } }
public void Close() { AmqpConnection connection = AmqpConnection; if (connection != null) { connection.Close(); } }
public async Task CloseAsync(CancellationToken cancellationToken) { AmqpConnection connection = AmqpConnection; if (connection != null) { await connection.CloseAsync(cancellationToken).ConfigureAwait(false); } }
public async Task CloseAsync(TimeSpan timeout) { AmqpConnection connection = AmqpConnection; if (connection != null) { await connection.CloseAsync(timeout).ConfigureAwait(false); } }
private async Task <ActiveClientRequestResponseLink> OpenRequestResponseLinkAsync( string type, string address, MessagingEntityType?entityType, string[] requiredClaims, TimeSpan timeout) { var timeoutHelper = new TimeoutHelper(timeout, true); AmqpSession session = null; try { // Don't need to get token for namespace scope operations, included in request bool isNamespaceScope = address.Equals(AmqpClientConstants.ManagementAddress, StringComparison.OrdinalIgnoreCase); AmqpConnection connection = await eventHubClient.ConnectionManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); var sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; session = connection.CreateSession(sessionSettings); await session.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); var linkSettings = new AmqpLinkSettings(); linkSettings.AddProperty(AmqpClientConstants.TimeoutName, (uint)timeoutHelper.RemainingTime().TotalMilliseconds); if (entityType != null) { linkSettings.AddProperty(AmqpClientConstants.EntityTypeName, (int)entityType.Value); } // Create the link var link = new RequestResponseAmqpLink(type, session, address, linkSettings.Properties); DateTime authorizationValidToUtc = DateTime.MaxValue; if (!isNamespaceScope) { // TODO: Get Entity level token here } await link.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Redirected scenario requires entityPath as the audience, otherwise we // should always use the full EndpointUri as audience. return(new ActiveClientRequestResponseLink( link, eventHubClient.ConnectionStringBuilder.Endpoint.AbsoluteUri, // audience eventHubClient.ConnectionStringBuilder.Endpoint.AbsoluteUri, // endpointUri requiredClaims, false, authorizationValidToUtc)); } catch (Exception) { // Aborting the session will cleanup the link as well. session?.Abort(); throw; } }
/// <summary> /// Creates the timer event handler to support refreshing AMQP link authorization /// on a recurring basis. /// </summary> /// <param name="entityPath"></param> /// /// <param name="connection">The AMQP connection to which the link being refreshed is bound to.</param> /// <param name="amqpLink">The AMQO link to refresh authorization for.</param> /// <param name="tokenProvider">The <see cref="CbsTokenProvider" /> to use for obtaining access tokens.</param> /// <param name="endpoint">The Service Bus service endpoint that the AMQP link is communicating with.</param> /// <param name="audience">The audience associated with the authorization. This is likely the <paramref name="endpoint"/> absolute URI.</param> /// <param name="resource">The resource associated with the authorization. This is likely the <paramref name="endpoint"/> absolute URI.</param> /// <param name="requiredClaims">The set of claims required to support the operations of the AMQP link.</param> /// <param name="refreshTimeout">The timeout to apply when requesting authorization refresh.</param> /// <param name="refreshTimerFactory">A function to allow retrieving the <see cref="Timer" /> associated with the link authorization.</param> /// /// <returns>A <see cref="TimerCallback"/> delegate to perform the refresh when a timer is due.</returns> /// protected virtual TimerCallback CreateAuthorizationRefreshHandler( string entityPath, AmqpConnection connection, AmqpObject amqpLink, CbsTokenProvider tokenProvider, Uri endpoint, string audience, string resource, string[] requiredClaims, TimeSpan refreshTimeout, Func <Timer> refreshTimerFactory) { return(async _ => { ServiceBusEventSource.Log.AmqpLinkAuthorizationRefreshStart(entityPath, endpoint.AbsoluteUri); Timer refreshTimer = refreshTimerFactory(); try { if (refreshTimer == null) { return; } DateTime authExpirationUtc = await RequestAuthorizationUsingCbsAsync(connection, tokenProvider, endpoint, audience, resource, requiredClaims, refreshTimeout).ConfigureAwait(false); // Reset the timer for the next refresh. if (authExpirationUtc >= DateTimeOffset.UtcNow) { refreshTimer.Change(CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan); } } catch (ObjectDisposedException) { // This can occur if the connection is closed or the scope disposed after the factory // is called but before the timer is updated. The callback may also fire while the timer is // in the act of disposing. Do not consider it an error. } catch (Exception ex) { ServiceBusEventSource.Log.AmqpLinkAuthorizationRefreshError(entityPath, endpoint.AbsoluteUri, ex.Message); // Attempt to unset the timer; there's a decent chance that it has been disposed at this point or // that the connection has been closed. Ignore potential exceptions, as they won't impact operation. // At worse, another timer tick will occur and the operation will be retried. try { refreshTimer.Change(Timeout.Infinite, Timeout.Infinite); } catch {} } finally { ServiceBusEventSource.Log.AmqpLinkAuthorizationRefreshComplete(entityPath, endpoint.AbsoluteUri); } }); }
/// <summary> /// Requests authorization for a connection or link using a connection via the CBS mechanism. /// </summary> /// /// <param name="connection">The AMQP connection for which the authorization is associated.</param> /// <param name="tokenProvider">The <see cref="CbsTokenProvider" /> to use for obtaining access tokens.</param> /// <param name="endpoint">The Event Hubs service endpoint that the authorization is requested for.</param> /// <param name="audience">The audience associated with the authorization. This is likely the <paramref name="endpoint"/> absolute URI.</param> /// <param name="resource">The resource associated with the authorization. This is likely the <paramref name="endpoint"/> absolute URI.</param> /// <param name="requiredClaims">The set of claims required to support the operations of the AMQP link.</param> /// <param name="timeout">The timeout to apply when requesting authorization.</param> /// /// <returns>The date/time, in UTC, when the authorization expires.</returns> /// /// <remarks> /// It is assumed that there is a valid <see cref="AmqpCbsLink" /> already associated /// with the connection; this will be used as the transport for the authorization /// credentials. /// </remarks> /// protected virtual Task <DateTime> RequestAuthorizationUsingCbsAsync(AmqpConnection connection, CbsTokenProvider tokenProvider, Uri endpoint, string audience, string resource, string[] requiredClaims, TimeSpan timeout) { var authLink = connection.Extensions.Find <AmqpCbsLink>(); return(authLink.SendTokenAsync(TokenProvider, endpoint, audience, resource, requiredClaims, timeout)); }
/// <summary> /// Opens an AMQP link for use with management operations. /// </summary> /// /// <param name="timeout">The timeout to apply when creating the link.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// /// <returns>A link for use with management operations.</returns> /// /// <remarks> /// The authorization for this link does not require periodic /// refreshing. /// </remarks> /// public async Task <RequestResponseAmqpLink> OpenManagementLinkAsync(TimeSpan timeout, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); var stopWatch = Stopwatch.StartNew(); AmqpConnection connection = await ActiveConnection.GetOrCreateAsync(timeout).ConfigureAwait(false); stopWatch.Stop(); return(await OpenManagementLinkAsync(connection, timeout.CalculateRemaining(stopWatch.Elapsed), cancellationToken).ConfigureAwait(false)); }
async Task <AmqpSession> CreateSessionAsync(TimeSpan timeout) { var timeoutHelper = new TimeoutHelper(timeout); this.refreshTokenTimer.Cancel(); AmqpSettings amqpSettings = this.CreateAmqpSettings(); TlsTransportSettings tlsTransportSettings = this.CreateTlsTransportSettings(); var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings); TransportBase transport; switch (this.amqpTransportSettings.GetTransportType()) { case TransportType.Amqp_WebSocket_Only: transport = await this.CreateClientWebSocketTransport(timeoutHelper.RemainingTime()); break; case TransportType.Amqp_Tcp_Only: transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()); 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.connectionString.AmqpEndpoint.Host }; var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings); await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()); var sessionSettings = new AmqpSessionSettings() { Properties = new Fields() }; 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); }
public void AmqpWebSocketTransportTest() { string address = "ws://localhost:28088"; var broker = new TestAmqpBroker(new string[] { address }, null, null, null); try { broker.Start(); string queue = "AmqpWebSocketTransportTest"; broker.AddQueue(queue); AmqpConnection connection = AmqpConnection.Factory.OpenConnectionAsync(address).GetAwaiter().GetResult(); AmqpSession session = connection.CreateSession(new AmqpSessionSettings()); session.Open(); SendingAmqpLink sLink = new SendingAmqpLink(session, AmqpUtils.GetLinkSettings(true, queue, SettleMode.SettleOnSend)); sLink.Open(); int messageCount = 100; for (int i = 0; i < messageCount; i++) { AmqpMessage message = AmqpMessage.Create(new AmqpValue() { Value = "message" + i }); sLink.SendMessageAsync(message, AmqpConstants.EmptyBinary, AmqpConstants.NullBinary, TimeSpan.FromSeconds(10)).Wait(); } sLink.Close(); ReceivingAmqpLink rLink = new ReceivingAmqpLink(session, AmqpUtils.GetLinkSettings(false, queue, SettleMode.SettleOnReceive, 100)); rLink.Open(); for (int i = 0; i < messageCount; i++) { AmqpMessage message2 = rLink.ReceiveMessageAsync(TimeSpan.FromSeconds(60)).GetAwaiter().GetResult(); Assert.NotNull(message2); rLink.AcceptMessage(message2, false); message2.Dispose(); } rLink.Close(); connection.Close(); } finally { broker.Stop(); } }
void IdleConnectionHandler(Object sender, EventArgs empty) { lock (this) { if (sharedConnection != sender || sharedConnection == null) { return; } if (!sharedConnection.IsIdle) { // Another thread made the connection busy again. // That's OK. Another idle event will come along later. return; } sharedConnection.Close(); // also closes all child sessions sharedConnection = null; //sharedSessions = null; } }
public object GetLink(AmqpChannelProperties channelProperties, bool sessionSharing, string inputQueue, string outputQueue) { AmqpConnection connection = null; AmqpSession session = null; Object link = null; bool newConnection = false; //bool newSession = false; bool success = false; // when called in the non-shared case, only stack variables should be used for holding connections/sessions/links if (this.shared) { Monitor.Enter(this); // lock } try { if (this.shared) { // TODO: check shared connection not closed (i.e. network drop) and refresh this instance if needed if (sessionSharing) { throw new NotImplementedException("shared session"); /* * ... once we have a defined shared session config parameter: // lazilly create if (this.sharedSessions == null) { this.sharedSessions = new Dictionary<string, AmqpSession>(); } alreadydeclaredstring sessionKey = channelProperties.name_of_key_goes_here; this.sharedSessions.TryGetValue(sessionKey, out session); * */ } if (this.sharedConnection != null) { connection = this.sharedConnection; } } if (connection == null) { if (channelProperties.AmqpSecurityMode != AmqpSecurityMode.None) { string user = null; string passwd = null; bool ssl = false; bool saslPlain = false; AmqpTransportSecurity tsec = channelProperties.AmqpTransportSecurity; if (tsec.UseSSL) { ssl = true; } if (tsec.CredentialType == AmqpCredentialType.Plain) { saslPlain = true; AmqpCredential plainCred = channelProperties.AmqpCredential; if (plainCred != null) { user = plainCred.UserName; passwd = plainCred.Password; } } connection = new AmqpConnection(channelProperties.BrokerHost, channelProperties.BrokerPort, ssl, saslPlain, user, passwd); } else { connection = new AmqpConnection(channelProperties.BrokerHost, channelProperties.BrokerPort); } newConnection = true; if (this.shared) { connection.OnConnectionIdle += new ConnectionIdleEventHandler(this.IdleConnectionHandler); } else { connection.OnConnectionIdle += new ConnectionIdleEventHandler(UnsharedIdleConnectionHandler); } } if (session == null) { session = connection.CreateSession(); //newSession = true; } if (inputQueue != null) { link = session.CreateInputLink(inputQueue); } else { link = session.CreateOutputLink(outputQueue); } if (this.shared) { if (newConnection) { this.sharedConnection = connection; } /* if (newSession) { sharedSessions.Add(foo, session); } * */ } success = true; } finally { if (this.shared) { Monitor.Exit(this); } if (!success) { /* if (newSession) { session.Close(); } */ if (newConnection) { connection.Close(); } } } return link; }