Example #1
0
        public void CorruptHeader_InvalidMessageSize()
        {
            MqttHeader inputHeader = new MqttHeader()
            {
                Duplicate = true,
                Retain = false,
                MessageSize = 268435455, // the max message size, which we will fudge later in the test
                MessageType = MqttMessageType.Connect,
                Qos = MqttQos.AtLeastOnce
            };

            MqttHeader outputHeader;

            using (MemoryStream stream = new MemoryStream())
            {
                inputHeader.WriteTo(268435455, stream);

                // fudge the header by making the last bit of the 4th message size byte a 1, therefore making the header
                // invalid because the last bit of the 4th size byte should always be 0 (according to the spec). It's how 
                // we know to stop processing the header when reading a full message).
                stream.Seek(4, SeekOrigin.Begin);
                byte existingByte = (byte)stream.ReadByte();
                stream.Seek(4, SeekOrigin.Begin);
                stream.WriteByte((byte)(existingByte | 0xFF));
                stream.Seek(0, SeekOrigin.Begin);

                Assert.Throws<InvalidHeaderException>(() => outputHeader = new MqttHeader(stream));
            }
        }
Example #2
0
        public void HeaderRoundtrip()
        {
            MqttHeader inputHeader = new MqttHeader()
            {
                Duplicate = true,
                Retain = false,
                MessageSize = 1,
                MessageType = MqttMessageType.Connect,
                Qos = MqttQos.AtLeastOnce
            };

            MqttHeader outputHeader;

            using (MemoryStream stream = new MemoryStream())
            {
                inputHeader.WriteTo(0, stream);

                // the stream will be chock full-o-bytes, rewind it so we can read it back
                stream.Seek(0, SeekOrigin.Begin);

                outputHeader = new MqttHeader(stream);
            }

            Assert.Equal<bool>(inputHeader.Duplicate, outputHeader.Duplicate);
            Assert.Equal<bool>(inputHeader.Retain, outputHeader.Retain);
            Assert.Equal<MqttQos>(inputHeader.Qos, outputHeader.Qos);
            Assert.Equal<MqttMessageType>(inputHeader.MessageType, outputHeader.MessageType);
        }
Example #3
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="MqttSubscribeAckPayload" /> class.
        /// </summary>
        /// <param name="header">The header to use for the message.</param>
        /// <param name="variableHeader">The variable header to use for the message.</param>
        /// <param name="payloadStream">The payload stream.</param>
        public MqttSubscribeAckPayload(MqttHeader header, MqttSubscribeAckVariableHeader variableHeader,
                                       Stream payloadStream) {
            this.header = header;
            this.variableHeader = variableHeader;

            ReadFrom(payloadStream);
        }
Example #4
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="MqttSubscribePayload" /> class.
        /// </summary>
        /// <param name="header">The header to use for the message.</param>
        /// <param name="variableHeader">The variable header to use for the message.</param>
        /// <param name="payloadStream">The payload stream.</param>
        public MqttSubscribePayload(MqttHeader header, MqttSubscribeVariableHeader variableHeader, Stream payloadStream)
        {
            this.header         = header;
            this.variableHeader = variableHeader;

            ReadFrom(payloadStream);
        }
Example #5
0
        /// <summary>
        ///     Gets an instance of an MqttMessage based on the message type requested.
        /// </summary>
        /// <param name="header">The message header.</param>
        /// <param name="messageStream">The content of the message, including variable header where applicable.</param>
        /// <returns>An instance of the desired message type.</returns>
        public static MqttMessage GetMessage(MqttHeader header, Stream messageStream)
        {
            switch (header.MessageType)
            {
            case MqttMessageType.Connect:
                return(new MqttConnectMessage(header, messageStream));

            case MqttMessageType.ConnectAck:
                return(new MqttConnectAckMessage(header, messageStream));

            case MqttMessageType.Publish:
                return(new MqttPublishMessage(header, messageStream));

            case MqttMessageType.PublishAck:
                return(new MqttPublishAckMessage(header, messageStream));

            case MqttMessageType.PublishComplete:
                return(new MqttPublishCompleteMessage(header, messageStream));

            case MqttMessageType.PublishReceived:
                return(new MqttPublishReceivedMessage(header, messageStream));

            case MqttMessageType.PublishRelease:
                return(new MqttPublishReleaseMessage(header, messageStream));

            case MqttMessageType.Subscribe:
                return(new MqttSubscribeMessage(header, messageStream));

            case MqttMessageType.SubscribeAck:
                return(new MqttSubscribeAckMessage(header, messageStream));

            case MqttMessageType.Unsubscribe:
                return(new MqttUnsubscribeMessage(header, messageStream));

            case MqttMessageType.UnsubscribeAck:
                return(new MqttUnsubscribeAckMessage(header, messageStream));

            case MqttMessageType.PingRequest:
                return(new MqttPingRequestMessage(header));

            case MqttMessageType.PingResponse:
                return(new MqttPingResponseMessage(header));

            case MqttMessageType.Disconnect:
                return(new MqttDisconnectMessage(header));

            default:
                throw new InvalidHeaderException(
                          String.Format(
                              "The Message Type specified ({0}) is not a valid MQTT Message type or currently not supported.",
                              (int)header.MessageType));
            }
        }
Example #6
0
        public void UseAll()
        {
            MqttHeader header
                = new MqttHeader()
                    .AsType(MqttMessageType.PublishComplete)
                    .WithQos(MqttQos.AtMostOnce)
                    .IsDuplicate()
                    .ShouldBeRetained();

            Assert.Equal<MqttMessageType>(MqttMessageType.PublishComplete, header.MessageType);
            Assert.True(header.Retain);
            Assert.Equal<MqttQos>(MqttQos.AtMostOnce, header.Qos);
            Assert.True(header.Duplicate);
        }
Example #7
0
        /// <summary>
        ///     Callback for when data is available for reading from the underlying stream.
        /// </summary>
        /// <param name="asyncResult">The async result from the read.</param>
        private void ReadComplete(IAsyncResult asyncResult)
        {
            int bytesRead;
            var dataStream = (NetworkStream)asyncResult.AsyncState;

            try {
                if (tcpClient.Connected && dataStream.CanRead && dataStream.DataAvailable)
                {
                    bytesRead = dataStream.EndRead(asyncResult);

                    if (bytesRead == 1)
                    {
                        var messageBytes = new Collection <byte>();
                        messageBytes.Add(headerByte[0]);

                        Collection <byte> lengthBytes = MqttHeader.ReadLengthBytes(dataStream);
                        int length = MqttHeader.CalculateLength(lengthBytes);
                        messageBytes.AddRange(lengthBytes);

                        // we've got the bytes that make up the header, inc the size, read the .
                        var remainingMessage = new byte[length];
                        int messageBytesRead = dataStream.Read(remainingMessage, 0, length);
                        if (messageBytesRead < length)
                        {
                            // we haven't got all the message, need to figure oput what to do.
                        }
                        messageBytes.AddRange(remainingMessage);

                        FireDataAvailableEvent(messageBytes);
                    }
                }

                // initiate a read for the next byte which will be the header bytes so long as
                // we're still connected to the underlying client
                if (tcpClient.Connected && networkStream.CanRead)
                {
                    dataStream.BeginRead(headerByte, 0, 1, ReadComplete, dataStream);
                }
            } catch (IOException ex) {
                // close the underlying connection
                this.Disconnect();

                if (ConnectionDropped != null)
                {
                    ConnectionDropped(this, new ConnectionDroppedEventArgs(ex));
                }
            }
        }
Example #8
0
        /// <summary>
        ///     Creates a new instance of an MQTT Message based on a raw message stream.
        /// </summary>
        /// <param name="messageStream">The message stream.</param>
        /// <returns>An MqttMessage containing details of the message.</returns>
        public static MqttMessage CreateFrom(Stream messageStream) {
            try {
                var header = new MqttHeader();

                // pass the input stream sequentially through the component deserialization(create) methods
                // to build a full MqttMessage.
                header = new MqttHeader(messageStream);

                MqttMessage message = MqttMessageFactory.GetMessage(header, messageStream);

                return message;
            } catch (InvalidHeaderException ex) {
                throw new InvalidMessageException(
                    "The data provided in the message stream was not a valid MQTT Message", ex);
            }
        }
Example #9
0
        /// <summary>
        ///     Creates a new instance of an MQTT Message based on a raw message stream.
        /// </summary>
        /// <param name="messageStream">The message stream.</param>
        /// <returns>An MqttMessage containing details of the message.</returns>
        public static MqttMessage CreateFrom(Stream messageStream)
        {
            try {
                var header = new MqttHeader();

                // pass the input stream sequentially through the component deserialization(create) methods
                // to build a full MqttMessage.
                header = new MqttHeader(messageStream);

                MqttMessage message = MqttMessageFactory.GetMessage(header, messageStream);

                return(message);
            } catch (InvalidHeaderException ex) {
                throw new InvalidMessageException(
                          "The data provided in the message stream was not a valid MQTT Message", ex);
            }
        }
Example #10
0
 /// <summary>
 /// Gets an instance of an MqttMessage based on the message type requested.
 /// </summary>
 /// <param name="messageType">Type of message to retrieve an instance of.</param>
 /// <returns>An instance of the desired message type.</returns>
 public static MqttMessage GetMessage(MqttHeader header, Stream messageStream)
 {
     switch (header.MessageType)
     {
         case MqttMessageType.Connect:
             return new MqttConnectMessage(header, messageStream);
         case MqttMessageType.ConnectAck:
             return new MqttConnectAckMessage(header, messageStream);
         case MqttMessageType.Publish:
             return new MqttPublishMessage(header, messageStream);
         case MqttMessageType.PublishAck:
             return new MqttPublishAckMessage(header, messageStream);
         case MqttMessageType.PublishComplete:
             return new MqttPublishCompleteMessage(header, messageStream);
         case MqttMessageType.PublishReceived:
             return new MqttPublishReceivedMessage(header, messageStream);
         case MqttMessageType.PublishRelease:
             return new MqttPublishReleaseMessage(header, messageStream);
         case MqttMessageType.Subscribe:
             return new MqttSubscribeMessage(header, messageStream);
         case MqttMessageType.SubscribeAck:
             return new MqttSubscribeAckMessage(header, messageStream);
         case MqttMessageType.Unsubscribe:
             return new MqttUnsubscribeMessage(header, messageStream);
         case MqttMessageType.UnsubscribeAck:
             return new MqttUnsubscribeAckMessage(header, messageStream);
         case MqttMessageType.PingRequest:
             return new MqttPingRequestMessage(header);
         case MqttMessageType.PingResponse:
             return new MqttPingResponseMessage(header);
         case MqttMessageType.Disconnect:
             return new MqttDisconnectMessage(header);
         default:
             throw new InvalidHeaderException(
                 String.Format("The Message Type specified ({0}) is not a valid MQTT Message type or currently not supported.", (int)header.MessageType));
     }
 }
Example #11
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The header to use for the message.</param>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttUnsubscribeAckMessage(MqttHeader header, Stream messageStream) {
     this.Header = header;
     ReadFrom(messageStream);
 }
Example #12
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The ping message's header.</param>
 internal MqttPingResponseMessage(MqttHeader header) {
     this.Header = header;
 }
Example #13
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectVariableHeader" /> class.
 /// </summary>
 public MqttPublishVariableHeader(MqttHeader header)
 {
     this.header = header;
 }
Example #14
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The message header.</param>
 internal MqttPingRequestMessage(MqttHeader header) {
     this.Header = header;
 }
Example #15
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The header to use for the message.</param>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPublishAckMessage(MqttHeader header, Stream messageStream)
 {
     this.Header         = header;
     this.VariableHeader = new MqttPublishAckVariableHeader(messageStream);
 }
Example #16
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The header to use for the message.</param>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPublishMessage(MqttHeader header, Stream messageStream)
 {
     this.Header = header;
     ReadFrom(messageStream);
 }
Example #17
0
        /// <summary>
        /// Test helper method to call Get Remaining Bytes with a specific value
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        private List<byte> CallGetRemainingBytesWithValue(int value)
        {
            // validates a payload size of a single byte using the example values supplied in the MQTT spec
            MqttHeader header = new MqttHeader();
            header.MessageSize = value;

            MethodInfo mi = typeof(MqttHeader).GetMethod("GetRemainingLengthBytes", ReflectionBindingConstants.NonpublicMethod);
            return (List<byte>)mi.Invoke(header, null);
        }
Example #18
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectAckMessage" /> class.
 /// </summary>
 /// <param name="header">The header.</param>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttConnectAckMessage(MqttHeader header, Stream messageStream) {
     this.Header = header;
     ReadFrom(messageStream);
 }
Example #19
0
 public void CorruptHeader_Undersize()
 {
     MqttHeader outputHeader;
     using (MemoryStream stream = new MemoryStream())
     {
         stream.WriteByte(0);
         stream.Seek(0, SeekOrigin.Begin);
         Assert.Throws<InvalidHeaderException>(() => outputHeader = new MqttHeader(stream));
     }
 }
Example #20
0
 public void SettingMessageType()
 {
     MqttHeader header = new MqttHeader().AsType(MqttMessageType.PublishComplete);
     Assert.Equal<MqttMessageType>(MqttMessageType.PublishComplete, header.MessageType);
 }
Example #21
0
 public void SettingRetain()
 {
     MqttHeader header = new MqttHeader().ShouldBeRetained();
     Assert.True(header.Retain);
 }
Example #22
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The header to use for the message.</param>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPublishMessage(MqttHeader header, Stream messageStream) {
     this.Header = header;
     ReadFrom(messageStream);
 }
Example #23
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttConnectMessage"/> class.
 /// </summary>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPingResponseMessage(MqttHeader header)
 {
     this.Header = header;
 }
Example #24
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttConnectMessage"/> class.
 /// </summary>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPingRequestMessage(MqttHeader header)
 {
     this.Header = header;
 }
Example #25
0
 public void PayloadSizeOutOfLowerRange()
 {
     MqttHeader header = new MqttHeader();
     Assert.Throws<InvalidPayloadSizeException>(() => header.MessageSize = -1);
 }
Example #26
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttConnectMessage"/> class.
 /// </summary>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttDisconnectMessage(MqttHeader header)
 {
     this.Header = header;
 }
Example #27
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectVariableHeader" /> class.
 /// </summary>
 public MqttPublishVariableHeader(MqttHeader header) {
     this.header = header;
 }
Example #28
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttUnsubscribeMessage"/> class.
 /// </summary>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttUnsubscribeMessage(MqttHeader header, Stream messageStream)
 {
     this.Header = header;
     ReadFrom(messageStream);
 }
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttPublishReceivedMessage" /> class.
 /// </summary>
 /// <param name="header">The header to use for the message.</param>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPublishReceivedMessage(MqttHeader header, Stream messageStream) {
     this.Header = header;
     this.VariableHeader = new MqttPublishReceivedVariableHeader(messageStream);
 }
Example #30
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttConnectPayload"/> class.
 /// </summary>
 /// <param name="header">The header of the message being process.</param>
 /// <param name="variableHeader">The variable header of the message being processed.</param>
 /// <param name="payloadStream">The payload stream.</param>
 public MqttPublishPayload(MqttHeader header, MqttPublishVariableHeader variableHeader, Stream payloadStream)
 {
     this.header = header;
     this.variableHeader = variableHeader;
     ReadFrom(payloadStream);
 }
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectMessage" /> class.
 /// </summary>
 /// <param name="header">The message header.</param>
 internal MqttDisconnectMessage(MqttHeader header)
 {
     this.Header = header;
 }
Example #32
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectVariableHeader" /> class.
 /// </summary>
 /// <param name="header">The messages header.</param>
 /// <param name="variableHeaderStream">A stream containing the header of the message.</param>
 public MqttPublishVariableHeader(MqttHeader header, Stream variableHeaderStream)
     : this(header) {
     ReadFrom(variableHeaderStream);
 }
Example #33
0
 public void SettingDuplicate()
 {
     MqttHeader header = new MqttHeader().IsDuplicate();
     Assert.True(header.Duplicate);
 }
Example #34
0
        /// <summary>
        ///     Callback for when data has been read from the underlying network stream.
        /// </summary>
        /// <param name="asyncResult">The async result from the read.</param>
        private void ReadHeaderComplete(IAsyncResult asyncResult)
        {
            var readWrapper = (ReadWrapper)asyncResult.AsyncState;

            try {
                var bytesRead = readWrapper.Stream.EndRead(asyncResult);
                if (bytesRead == 0)
                {
                    // Nothing read, we will just try another read from the stream.
                    Log.Debug("Async network stream read returned 0 bytes, continuing to search for header.");
                    readWrapper.ReadState = ConnectionReadState.Header;
                }
                else if (tcpClient.Connected && readWrapper.Stream.CanRead)
                {
                    if (readWrapper.ReadState == ConnectionReadState.Header && readWrapper.Stream.DataAvailable)
                    {
                        Log.Info("Reading message arriving on the wire.");

                        readWrapper.MessageBytes.Add(readWrapper.Buffer[0]);

                        var lengthBytes     = MqttHeader.ReadLengthBytes(readWrapper.Stream);
                        var remainingLength = MqttHeader.CalculateLength(lengthBytes);

                        // update the read wrapper with the header bytes, and a resized read buffer
                        // to capture the remaining length.
                        readWrapper.MessageBytes.AddRange(lengthBytes);

                        // no content, so yield the message early, else transition to reading the content.
                        if (remainingLength == 0)
                        {
                            Log.Debug("Message receipt complete. Has empty content length so handing off now.");
                            FireDataAvailableEvent(readWrapper.MessageBytes);
                        }
                        else
                        {
                            // total bytes of content is the remaining length plus the header.
                            readWrapper.TotalBytes = remainingLength + readWrapper.MessageBytes.Count;
                            readWrapper.RecalculateNextReadSize();
                            readWrapper.ReadState = ConnectionReadState.Content;
                        }
                    }
                    else if (readWrapper.ReadState == ConnectionReadState.Content)
                    {
                        // stash what we've read.
                        readWrapper.MessageBytes.AddRange(readWrapper.Buffer.Take(bytesRead));
                        Log.Debug(m => m("Message Content read {0:n0} of {1:n0} expected remaining bytes.", bytesRead, readWrapper.TotalBytes));

                        // if we haven't yet read all of the message repeat the read otherwise if
                        // we're finished process the message and switch back to waiting for the next header.
                        if (readWrapper.IsReadComplete)
                        {
                            // reset the read buffer to accommodate the remaining length (last - what was read)
                            readWrapper.RecalculateNextReadSize();
                        }
                        else
                        {
                            Log.Debug(m => m("Message receipt complete ({0:n0} total bytes including all headers), handing off to handlers.", readWrapper.MessageBytes.Count));
                            readWrapper.ReadState = ConnectionReadState.Header;
                            FireDataAvailableEvent(readWrapper.MessageBytes);
                        }
                    }

                    // if we've switched to reading a header then recreate the read dwrapper for the next message
                    if (readWrapper.ReadState == ConnectionReadState.Header)
                    {
                        readWrapper = new ReadWrapper(readWrapper.Stream);
                    }
                    // we can still read etc
                    // initiate a read for the next set of bytes which will be the header bytes so long as
                    // we're still connected to the underlying client
                    readWrapper.Stream.BeginRead(readWrapper.Buffer, 0, readWrapper.NextReadSize, ReadHeaderComplete, readWrapper);
                }
            } catch (IOException ex) {
                Log.Debug("Error occurred during async read from broker network stream. Initiating broker disconnect", ex);

                // close the underlying connection
                this.Disconnect();

                if (ConnectionDropped != null)
                {
                    ConnectionDropped(this, new ConnectionDroppedEventArgs(ex));
                }
            }
        }
Example #35
0
 public void SettingQos()
 {
     MqttHeader header = new MqttHeader().WithQos(MqttQos.AtMostOnce);
     Assert.Equal<MqttQos>(MqttQos.AtMostOnce, header.Qos);
 }
Example #36
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectVariableHeader" /> class.
 /// </summary>
 /// <param name="header">The messages header.</param>
 /// <param name="variableHeaderStream">A stream containing the header of the message.</param>
 public MqttPublishVariableHeader(MqttHeader header, Stream variableHeaderStream)
     : this(header) {
     ReadFrom(variableHeaderStream);
 }
Example #37
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttMessage"/> class.
 /// </summary>
 /// <param name="header">The header of the message.</param>
 /// <param name="payload">The payload of the message.</param>
 public MqttMessage(MqttHeader header)
 {
     Header = header;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttPublishCompleteMessage"/> class.
 /// </summary>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttPublishCompleteMessage(MqttHeader header, Stream messageStream)
 {
     this.Header = header;
     this.VariableHeader = new MqttPublishCompleteVariableHeader(messageStream);
 }
Example #39
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttMessage" /> class.
 /// </summary>
 /// <param name="header">The header of the message.</param>
 public MqttMessage(MqttHeader header)
 {
     Header = header;
 }
Example #40
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MqttConnectMessage"/> class.
 /// </summary>
 /// <param name="messageStream">The message stream positioned after the header.</param>
 internal MqttConnectMessage(MqttHeader header, Stream messageStream)
 {
     this.Header = header;
     ReadFrom(messageStream);
 }
Example #41
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="MqttConnectPayload" /> class.
 /// </summary>
 /// <param name="header">The header of the message being process.</param>
 /// <param name="variableHeader">The variable header of the message being processed.</param>
 /// <param name="payloadStream">The payload stream.</param>
 public MqttPublishPayload(MqttHeader header, MqttPublishVariableHeader variableHeader, Stream payloadStream)
 {
     this.header         = header;
     this.variableHeader = variableHeader;
     ReadFrom(payloadStream);
 }