public async Task <SendingAmqpLink> CreateSendingLinkAsync( string path, IotHubConnectionString connectionString, string deviceId, SendingLinkType linkType, TimeSpan timeout, 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()); if (linkType == SendingLinkType.Methods) { SetLinkSettingsCommonPropertiesForMethod(linkSettings, deviceId); } else if (linkType == SendingLinkType.Twin) { SetLinkSettingsCommonPropertiesForTwin(linkSettings); } 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); }
public async Task <ReceivingAmqpLink> CreateReceivingLinkAsync( string path, IotHubConnectionString connectionString, string deviceId, ReceivingLinkType linkType, uint prefetchCount, TimeSpan timeout, CancellationToken cancellationToken) { this.OnCreateReceivingLink(connectionString); var timeoutHelper = new TimeoutHelper(timeout); AmqpSession session = await this.GetSessionAsync(timeoutHelper, cancellationToken); var linkAddress = this.BuildLinkAddress(connectionString, path); var linkSettings = new AmqpLinkSettings() { Role = true, TotalLinkCredit = prefetchCount, AutoSendFlow = prefetchCount > 0, Source = new Source() { Address = linkAddress.AbsoluteUri }, LinkName = Guid.NewGuid().ToString("N") // Use a human readable link name to help with debuggin }; switch (linkType) { case ReceivingLinkType.C2DMessages: linkSettings.SndSettleMode = null; // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire) linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.Second; break; case ReceivingLinkType.Methods: case ReceivingLinkType.Twin: linkSettings.SndSettleMode = (byte)SenderSettleMode.Settled; linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.First; break; } SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime()); if (linkType == ReceivingLinkType.Methods) { SetLinkSettingsCommonPropertiesForMethod(linkSettings, deviceId); } else if (linkType == ReceivingLinkType.Twin) { SetLinkSettingsCommonPropertiesForTwin(linkSettings); } var link = new ReceivingAmqpLink(linkSettings); link.AttachTo(session); var audience = this.BuildAudience(connectionString, path); await this.OpenLinkAsync(link, connectionString, audience, timeoutHelper.RemainingTime(), cancellationToken); return(link); }
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()) { #if !WINDOWS_UWP && !PCL case TransportType.Amqp_WebSocket_Only: transport = await this.CreateClientWebSocketTransportAsync(timeoutHelper.RemainingTime()); break; #endif case TransportType.Amqp_Tcp_Only: TlsTransportSettings tlsTransportSettings = this.CreateTlsTransportSettings(); var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings); 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.hostName }; var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings); try { token.ThrowIfCancellationRequested(); await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()); var sessionSettings = new AmqpSessionSettings() { Properties = new Fields() }; AmqpSession amqpSession = amqpConnection.CreateSession(sessionSettings); token.ThrowIfCancellationRequested(); await amqpSession.OpenAsync(timeoutHelper.RemainingTime()); // 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; } }
public async Task <int> ReceiveAsync(byte[] buffer, int offset, int size, TimeSpan timeout) { byte[] header = new byte[2]; Fx.AssertAndThrow(this.State == WebSocketState.Open, ClientWebSocketNotInOpenStateDuringReceive); this.TcpClient.ReceiveTimeout = TimeoutHelper.ToMilliseconds(timeout); bool succeeded = false; try { byte payloadLength; bool pongFrame; // TODO: rewrite this section to handle all control frames (including ping) int totalBytesRead; int bytesRead; do { // Ignore pong frame and start over totalBytesRead = 0; do { bytesRead = await this.WebSocketStream.ReadAsync(header, totalBytesRead, header.Length - totalBytesRead); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; }while (totalBytesRead < header.Length); if (!ParseWebSocketFrameHeader(header, out payloadLength, out pongFrame)) { // Encountered a close frame or error in parsing frame from server. Close connection var closeHeader = PrepareWebSocketHeader(0, WebSocketMessageType.Close); await this.WebSocketStream.WriteAsync(closeHeader, 0, closeHeader.Length); this.State = WebSocketState.Closed; this.WebSocketStream?.Close(); this.TcpClient?.Close(); return(0); // TODO: throw exception? } if (pongFrame && payloadLength > 0) { totalBytesRead = 0; var tempBuffer = new byte[payloadLength]; while (totalBytesRead < payloadLength) { bytesRead = await this.WebSocketStream.ReadAsync(tempBuffer, totalBytesRead, payloadLength - totalBytesRead); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; } } }while (pongFrame); totalBytesRead = 0; if (buffer.Length < payloadLength) { throw Fx.Exception.AsError(new InvalidOperationException(Resources.SizeExceedsRemainingBufferSpace)); } if (payloadLength < MediumSizeFrame) { while (totalBytesRead < payloadLength) { bytesRead = await this.WebSocketStream.ReadAsync(buffer, offset + totalBytesRead, payloadLength - totalBytesRead); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; } } else { switch (payloadLength) { case MediumSizeFrame: // read payload length (< 64K) do { bytesRead = await this.WebSocketStream.ReadAsync(header, totalBytesRead, header.Length - totalBytesRead); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; }while (totalBytesRead < header.Length); totalBytesRead = 0; ushort extendedPayloadLength = (ushort)((header[0] << 8) | header[1]); // read payload if (buffer.Length >= extendedPayloadLength) { while (totalBytesRead < extendedPayloadLength) { bytesRead = await this.WebSocketStream.ReadAsync(buffer, offset + totalBytesRead, extendedPayloadLength - totalBytesRead); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; } } else { throw Fx.Exception.AsError(new InvalidOperationException(Resources.SizeExceedsRemainingBufferSpace)); } break; case LargeSizeFrame: // read payload length (>= 64K) var payloadLengthBuffer = new byte[8]; do { bytesRead = await this.WebSocketStream.ReadAsync(payloadLengthBuffer, totalBytesRead, payloadLengthBuffer.Length - totalBytesRead); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; }while (totalBytesRead < payloadLengthBuffer.Length); totalBytesRead = 0; // ignore bytes 0-3 - length cannot be larger than a 32-bit number uint superExtendedPayloadLength = (uint)((payloadLengthBuffer[4] << 24) | (payloadLengthBuffer[5] << 16) | (payloadLengthBuffer[6] << 8) | payloadLengthBuffer[7]); // read payload if (buffer.Length >= superExtendedPayloadLength) { while (totalBytesRead < superExtendedPayloadLength) { bytesRead = await this.WebSocketStream.ReadAsync(buffer, offset + totalBytesRead, (int)(superExtendedPayloadLength - totalBytesRead)); if (bytesRead == 0) { throw new IOException(FramingPrematureEOF, new InvalidDataException("IotHubClientWebSocket was expecting more bytes")); } totalBytesRead += bytesRead; } } else { throw Fx.Exception.AsError(new InvalidOperationException(Resources.SizeExceedsRemainingBufferSpace)); } break; } } succeeded = true; return(totalBytesRead); } finally { if (!succeeded) { this.Fault(); } } }