예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
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())
            {
#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();
                }
            }
        }