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)); } }
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); }
/// <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); }
/// <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); }
/// <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)); } }
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); }
/// <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)); } } }
/// <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); } }
/// <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); } }
/// <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)); } }
/// <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); }
/// <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; }
/// <summary> /// Initializes a new instance of the <see cref="MqttConnectVariableHeader" /> class. /// </summary> public MqttPublishVariableHeader(MqttHeader header) { this.header = header; }
/// <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; }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
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)); } }
public void SettingMessageType() { MqttHeader header = new MqttHeader().AsType(MqttMessageType.PublishComplete); Assert.Equal<MqttMessageType>(MqttMessageType.PublishComplete, header.MessageType); }
public void SettingRetain() { MqttHeader header = new MqttHeader().ShouldBeRetained(); Assert.True(header.Retain); }
/// <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; }
/// <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; }
public void PayloadSizeOutOfLowerRange() { MqttHeader header = new MqttHeader(); Assert.Throws<InvalidPayloadSizeException>(() => header.MessageSize = -1); }
/// <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; }
/// <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); }
/// <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; }
/// <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); }
public void SettingDuplicate() { MqttHeader header = new MqttHeader().IsDuplicate(); Assert.True(header.Duplicate); }
/// <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)); } } }
public void SettingQos() { MqttHeader header = new MqttHeader().WithQos(MqttQos.AtMostOnce); Assert.Equal<MqttQos>(MqttQos.AtMostOnce, header.Qos); }
/// <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); }
/// <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; }
/// <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); }
/// <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); }