public async Task<SendingAmqpLink> CreateSendingLinkAsync(string path, IotHubConnectionString connectionString, TimeSpan timeout) { this.OnCreateSendingLink(connectionString); var timeoutHelper = new TimeoutHelper(timeout); AmqpSession session; if (!this.FaultTolerantSession.TryGetOpenedObject(out session)) { session = await this.FaultTolerantSession.GetOrCreateAsync(timeoutHelper.RemainingTime()); } var linkAddress = this.BuildLinkAddress(connectionString, path); var linkSettings = new AmqpLinkSettings() { Role = false, InitialDeliveryCount = 0, Target = new Target() { Address = linkAddress.AbsoluteUri }, SndSettleMode = null, // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire) RcvSettleMode = null, // (byte)ReceiverSettleMode.First (null as it is the default and to avoid bytes on the wire) LinkName = Guid.NewGuid().ToString("N") // Use a human readable link name to help with debugging }; SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime()); var link = new SendingAmqpLink(linkSettings); link.AttachTo(session); var audience = this.BuildAudience(connectionString, path); await this.OpenLinkAsync(link, connectionString, audience, timeoutHelper.RemainingTime()); return link; }
/// <summary> /// Creates an AMQP link for use with publishing operations. /// </summary> /// /// <param name="connection">The active and opened AMQP connection to use for this link.</param> /// <param name="endpoint">The fully qualified endpoint to open the link for.</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 for operations related to receiving events.</returns> /// protected virtual async Task <SendingAmqpLink> CreateSendingLinkAsync(AmqpConnection connection, Uri endpoint, TimeSpan timeout, CancellationToken cancellationToken) { Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope)); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); var session = default(AmqpSession); var stopWatch = Stopwatch.StartNew(); try { // Perform the initial authorization for the link. var authClaims = new[] { EventHubsClaim.Send }; var authExpirationUtc = await RequestAuthorizationUsingCbsAsync(connection, TokenProvider, endpoint, endpoint.AbsoluteUri, endpoint.AbsoluteUri, authClaims, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); // Create and open the AMQP session associated with the link. var sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; session = connection.CreateSession(sessionSettings); await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); // Create and open the link. var linkSettings = new AmqpLinkSettings { Role = false, InitialDeliveryCount = 0, Source = new Source { Address = Guid.NewGuid().ToString() }, Target = new Target { Address = endpoint.AbsolutePath } }; linkSettings.AddProperty(AmqpProperty.Timeout, (uint)timeout.CalculateRemaining(stopWatch.Elapsed).TotalMilliseconds); linkSettings.AddProperty(AmqpProperty.EntityType, (int)AmqpProperty.Entity.EventHub); var link = new SendingAmqpLink(linkSettings); linkSettings.LinkName = $"{ Id };{ connection.Identifier }:{ session.Identifier }:{ link.Identifier }"; link.AttachTo(session); stopWatch.Stop(); // Configure refresh for authorization of the link. var refreshTimer = default(Timer); var refreshHandler = CreateAuthorizationRefreshHandler ( connection, link, TokenProvider, endpoint, endpoint.AbsoluteUri, endpoint.AbsoluteUri, authClaims, AuthorizationRefreshTimeout, () => refreshTimer ); refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan); // Track the link before returning it, so that it can be managed with the scope. BeginTrackingLinkAsActive(link, refreshTimer); return(link); } catch { // Aborting the session will perform any necessary cleanup of // the associated link as well. session?.Abort(); throw; } }
public async Task <SendingAmqpLink> CreateSendingLinkAsync( string path, IotHubConnectionString connectionString, string corrId, SendingLinkType linkType, TimeSpan timeout, ProductInfo productInfo, CancellationToken cancellationToken) { this.OnCreateSendingLink(connectionString); var timeoutHelper = new TimeoutHelper(timeout); AmqpSession session = await this.GetSessionAsync(timeoutHelper, cancellationToken); var linkAddress = this.BuildLinkAddress(connectionString, path); var linkSettings = new AmqpLinkSettings() { Role = false, InitialDeliveryCount = 0, Target = new Target() { Address = linkAddress.AbsoluteUri }, LinkName = Guid.NewGuid().ToString("N") // Use a human readable link name to help with debugging }; switch (linkType) { case SendingLinkType.TelemetryEvents: linkSettings.SndSettleMode = null; // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire) linkSettings.RcvSettleMode = null; // (byte)ReceiverSettleMode.First (null as it is the default and to avoid bytes on the wire) break; case SendingLinkType.Methods: case SendingLinkType.Twin: linkSettings.SndSettleMode = (byte)SenderSettleMode.Settled; linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.First; break; } SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime(), productInfo); if (linkType == SendingLinkType.Methods) { SetLinkSettingsCommonPropertiesForMethod(linkSettings, corrId); } else if (linkType == SendingLinkType.Twin) { SetLinkSettingsCommonPropertiesForTwin(linkSettings, corrId); } var link = new SendingAmqpLink(linkSettings); link.AttachTo(session); var audience = this.BuildAudience(connectionString, path); await this.OpenLinkAsync(link, connectionString, audience, timeoutHelper.RemainingTime(), cancellationToken); return(link); }
/// <summary> /// Creates an AMQP link for use with publishing operations. /// </summary> /// <param name="entityPath"></param> /// <param name="viaEntityPath">The entity path to route the message through. Useful when using transactions.</param> /// <param name="connection">The active and opened AMQP connection to use for this link.</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 for operations related to receiving events.</returns> /// protected virtual async Task <SendingAmqpLink> CreateSendingLinkAsync( string entityPath, string viaEntityPath, AmqpConnection connection, TimeSpan timeout, CancellationToken cancellationToken) { Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope)); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); var session = default(AmqpSession); var stopWatch = ValueStopwatch.StartNew(); try { string[] audience; Uri destinationEndpoint = null; // if there is a via entityPath, include that in the audience if (!string.IsNullOrEmpty(viaEntityPath)) { destinationEndpoint = new Uri(ServiceEndpoint, viaEntityPath); var finalDestinationEndpoint = new Uri(ServiceEndpoint, entityPath); audience = new string[] { finalDestinationEndpoint.AbsoluteUri, destinationEndpoint.AbsoluteUri }; } else { destinationEndpoint = new Uri(ServiceEndpoint, entityPath); audience = new string[] { destinationEndpoint.AbsoluteUri }; } // Perform the initial authorization for the link. var authClaims = new[] { ServiceBusClaim.Send }; DateTime authExpirationUtc = await RequestAuthorizationUsingCbsAsync( connection, TokenProvider, destinationEndpoint, audience, authClaims, timeout.CalculateRemaining(stopWatch.GetElapsedTime())) .ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); // Create and open the AMQP session associated with the link. var sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; session = connection.CreateSession(sessionSettings); await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); // Create and open the link. var linkSettings = new AmqpLinkSettings { Role = false, InitialDeliveryCount = 0, Source = new Source { Address = Guid.NewGuid().ToString() }, Target = new Target { Address = destinationEndpoint.AbsolutePath } }; if (!string.IsNullOrEmpty(viaEntityPath)) { linkSettings.AddProperty(AmqpClientConstants.TransferDestinationAddress, entityPath); } linkSettings.AddProperty(AmqpProperty.Timeout, (uint)timeout.CalculateRemaining(stopWatch.GetElapsedTime()).TotalMilliseconds); var link = new SendingAmqpLink(linkSettings); linkSettings.LinkName = $"{ Id };{ connection.Identifier }:{ session.Identifier }:{ link.Identifier }"; link.AttachTo(session); // Configure refresh for authorization of the link. var refreshTimer = default(Timer); TimerCallback refreshHandler = CreateAuthorizationRefreshHandler ( entityPath, connection, link, TokenProvider, destinationEndpoint, audience, authClaims, AuthorizationRefreshTimeout, () => refreshTimer ); refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan); // Track the link before returning it, so that it can be managed with the scope. BeginTrackingLinkAsActive(entityPath, link, refreshTimer); return(link); } catch (Exception exception) { // Aborting the session will perform any necessary cleanup of // the associated link as well. session?.Abort(); throw AmqpExceptionHelper.TranslateException( exception, null, session.GetInnerException(), connection.IsClosing()); } }
async Task <SendingAmqpLink> CreateLinkAsync(TimeSpan timeout) { var amqpEventHubClient = ((AmqpEventHubClient)this.EventHubClient); var timeoutHelper = new TimeoutHelper(timeout); AmqpConnection connection = await amqpEventHubClient.ConnectionManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Authenticate over CBS var cbsLink = connection.Extensions.Find <AmqpCbsLink>(); ICbsTokenProvider cbsTokenProvider = amqpEventHubClient.CbsTokenProvider; Uri address = new Uri(amqpEventHubClient.ConnectionStringBuilder.Endpoint, this.Path); string audience = address.AbsoluteUri; string resource = address.AbsoluteUri; var expiresAt = await cbsLink.SendTokenAsync( cbsTokenProvider, address, audience, resource, new[] { ClaimConstants.Send }, timeoutHelper.RemainingTime()).ConfigureAwait(false); AmqpSession session = null; try { // Create our Session var sessionSettings = new AmqpSessionSettings { Properties = new Fields() }; session = connection.CreateSession(sessionSettings); await session.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); // Create our Link var linkSettings = new AmqpLinkSettings(); linkSettings.AddProperty(AmqpClientConstants.TimeoutName, (uint)timeoutHelper.RemainingTime().TotalMilliseconds); linkSettings.AddProperty(AmqpClientConstants.EntityTypeName, (int)MessagingEntityType.EventHub); linkSettings.Role = false; linkSettings.InitialDeliveryCount = 0; linkSettings.Target = new Target { Address = address.AbsolutePath }; linkSettings.Source = new Source { Address = this.ClientId }; var link = new SendingAmqpLink(linkSettings); linkSettings.LinkName = $"{amqpEventHubClient.ContainerId};{connection.Identifier}:{session.Identifier}:{link.Identifier}"; link.AttachTo(session); await link.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); var activeClientLink = new ActiveClientLink( link, audience, // audience this.EventHubClient.ConnectionStringBuilder.Endpoint.AbsoluteUri, // endpointUri new[] { ClaimConstants.Send }, true, expiresAt); this.MaxMessageSize = (long)activeClientLink.Link.Settings.MaxMessageSize(); this.clientLinkManager.SetActiveLink(activeClientLink); this.linkCreated = true; return(link); } catch { // Cleanup any session (and thus link) in case of exception. session?.Abort(); throw; } }
private static async Task <AmqpIotSendingLink> OpenSendingAmqpLinkAsync( IDeviceIdentity deviceIdentity, AmqpSession amqpSession, byte?senderSettleMode, byte?receiverSettleMode, string deviceTemplate, string moduleTemplate, string linkSuffix, string correlationId, CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(typeof(AmqpIotSession), deviceIdentity, nameof(OpenSendingAmqpLinkAsync)); } var amqpLinkSettings = new AmqpLinkSettings { LinkName = linkSuffix, Role = false, InitialDeliveryCount = 0, Target = new Target { Address = BuildLinkAddress(deviceIdentity, deviceTemplate, moduleTemplate) }, Source = new Source { Address = deviceIdentity.IotHubConnectionString.DeviceId }, SndSettleMode = senderSettleMode, RcvSettleMode = receiverSettleMode, }; amqpLinkSettings.AddProperty(AmqpIotConstants.ClientVersion, deviceIdentity.ProductInfo.ToString()); if (correlationId != null) { amqpLinkSettings.AddProperty(AmqpIotConstants.ChannelCorrelationId, correlationId); } if (!deviceIdentity.AmqpTransportSettings.AuthenticationChain.IsNullOrWhiteSpace()) { amqpLinkSettings.AddProperty(AmqpIotConstants.AuthChain, deviceIdentity.AmqpTransportSettings.AuthenticationChain); } // This check is added to enable the device or module client to available plug and play features. For devices or modules that pass in the model Id, // the SDK will enable plug and play features by setting the modelId to AMQP link settings. if (!string.IsNullOrWhiteSpace(deviceIdentity.Options?.ModelId)) { amqpLinkSettings.AddProperty(AmqpIotConstants.ModelId, deviceIdentity.Options.ModelId); } amqpLinkSettings.AddProperty(AmqpIotConstants.ApiVersion, ClientApiVersionHelper.ApiVersionString); try { var sendingLink = new SendingAmqpLink(amqpLinkSettings); sendingLink.AttachTo(amqpSession); await sendingLink.OpenAsync(cancellationToken).ConfigureAwait(false); return(new AmqpIotSendingLink(sendingLink)); } catch (Exception e) when(!e.IsFatal()) { Exception ex = AmqpIotExceptionAdapter.ConvertToIotHubException(e, amqpSession); if (ReferenceEquals(e, ex)) { throw; } else { if (ex is AmqpIotResourceException) { amqpSession.SafeClose(); throw new IotHubCommunicationException(ex.Message, ex); } throw ex; } } finally { if (Logging.IsEnabled) { Logging.Exit(typeof(AmqpIotSession), deviceIdentity, nameof(OpenSendingAmqpLinkAsync)); } } }
private static async Task <AmqpIoTSendingLink> OpenSendingAmqpLinkAsync( DeviceIdentity deviceIdentity, AmqpSession amqpSession, byte?senderSettleMode, byte?receiverSettleMode, string deviceTemplate, string moduleTemplate, string linkSuffix, string CorrelationId, TimeSpan timeout ) { if (Logging.IsEnabled) { Logging.Enter(typeof(AmqpIoTSession), deviceIdentity, $"{nameof(OpenSendingAmqpLinkAsync)}"); } AmqpLinkSettings amqpLinkSettings = new AmqpLinkSettings { LinkName = linkSuffix, Role = false, InitialDeliveryCount = 0, Target = new Target() { Address = BuildLinkAddress(deviceIdentity, deviceTemplate, moduleTemplate) }, Source = new Source() { Address = deviceIdentity.IotHubConnectionString.DeviceId } }; amqpLinkSettings.SndSettleMode = senderSettleMode; amqpLinkSettings.RcvSettleMode = receiverSettleMode; amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.TimeoutName, timeout.TotalMilliseconds); amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.ClientVersion, deviceIdentity.ProductInfo.ToString()); amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.ApiVersion, ClientApiVersionHelper.ApiVersionString); if (CorrelationId != null) { amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.ChannelCorrelationId, CorrelationId); } try { SendingAmqpLink sendingLink = new SendingAmqpLink(amqpLinkSettings); sendingLink.AttachTo(amqpSession); await sendingLink.OpenAsync(timeout).ConfigureAwait(false); return(new AmqpIoTSendingLink(sendingLink)); } catch (Exception e) when(!e.IsFatal()) { Exception ex = AmqpIoTExceptionAdapter.ConvertToIoTHubException(e, amqpSession); if (ReferenceEquals(e, ex)) { throw; } else { if (ex is AmqpIoTResourceException) { amqpSession.SafeClose(); throw new IotHubCommunicationException(ex.Message, ex); } throw ex; } } finally { if (Logging.IsEnabled) { Logging.Exit(typeof(AmqpIoTSession), deviceIdentity, $"{nameof(OpenSendingAmqpLinkAsync)}"); } } }