/// <summary> /// Parse bytes for a PUBREC message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>PUBREC message instance</returns> public static MqttMsgPubrec Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; int index = 0; MqttMsgPubrec msg = new MqttMsgPubrec(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREC_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... channel.Receive(buffer); // message id msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00); msg.messageId |= (buffer[index++]); return(msg); }
/// <summary> /// Parse bytes for a CONNACK message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>CONNACK message instance</returns> public static MqttMsgConnack Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; MqttMsgConnack msg = new MqttMsgConnack(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_CONNACK_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... channel.Receive(buffer); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] ... set session present flag ... msg.sessionPresent = (buffer[CONN_ACK_FLAGS_BYTE_OFFSET] & SESSION_PRESENT_FLAG_MASK) != 0x00; } // ...and set return code from broker msg.returnCode = buffer[CONN_RETURN_CODE_BYTE_OFFSET]; return(msg); }
/// <summary> /// Parse bytes for a PINGREQ message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>PINGREQ message instance</returns> public static MqttMsgPingReq Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { MqttMsgPingReq msg = new MqttMsgPingReq(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGREQ_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // already know remaininglength is zero (MQTT specification), // so it isn't necessary to read other data from socket int remainingLength = MqttMsgBase.decodeRemainingLength(channel); return(msg); }
/// <summary> /// Parse bytes for a DISCONNECT message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>DISCONNECT message instance</returns> public static MqttMsgDisconnect Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { MqttMsgDisconnect msg = new MqttMsgDisconnect(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_DISCONNECT_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); // NOTE : remainingLength must be 0 return(msg); }
/// <summary> /// Parse bytes for a PUBREL message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>PUBREL message instance</returns> public static MqttMsgPubrel Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; int index = 0; MqttMsgPubrel msg = new MqttMsgPubrel(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBREL_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... channel.Receive(buffer); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1) { // only 3.1.0 // read QoS level from fixed header (would be QoS Level 1) msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); // read DUP flag from fixed header msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01); } // message id msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00); msg.messageId |= (buffer[index++]); return(msg); }
/// <summary> /// Parse bytes for a SUBACK message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>SUBACK message instance</returns> public static MqttMsgSuback Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; int index = 0; MqttMsgSuback msg = new MqttMsgSuback(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBACK_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... channel.Receive(buffer); // message id msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00); msg.messageId |= (buffer[index++]); // payload contains QoS levels granted msg.grantedQosLevels = new byte[remainingLength - MESSAGE_ID_SIZE]; int qosIdx = 0; do { msg.grantedQosLevels[qosIdx++] = buffer[index++]; } while (index < remainingLength); return(msg); }
/// <summary> /// Parse bytes for a SUBSCRIBE message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>SUBSCRIBE message instance</returns> public static MqttMsgSubscribe Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; int index = 0; byte[] topicUtf8; int topicUtf8Length; MqttMsgSubscribe msg = new MqttMsgSubscribe(); if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1_1) { // [v3.1.1] check flag bits if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_SUBSCRIBE_FLAG_BITS) { throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits); } } // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... #pragma warning disable 219 int received = channel.Receive(buffer); #pragma warning restore 219 if (protocolVersion == MqttMsgConnect.PROTOCOL_VERSION_V3_1) { // only 3.1.0 // read QoS level from fixed header msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); // read DUP flag from fixed header msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01); // retain flag not used msg.retain = false; } // message id msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00); msg.messageId |= (buffer[index++]); // payload contains topics and QoS levels // NOTE : before, I don't know how many topics will be in the payload (so use List) // if .Net Micro Framework #if (MF_FRAMEWORK_VERSION_V4_2 || MF_FRAMEWORK_VERSION_V4_3) IList tmpTopics = new ArrayList(); IList tmpQosLevels = new ArrayList(); // else other frameworks (.Net, .Net Compact, Mono, Windows Phone) #else IList <String> tmpTopics = new List <String>(); IList <byte> tmpQosLevels = new List <byte>(); #endif do { // topic name topicUtf8Length = ((buffer[index++] << 8) & 0xFF00); topicUtf8Length |= buffer[index++]; topicUtf8 = new byte[topicUtf8Length]; Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length); index += topicUtf8Length; tmpTopics.Add(new String(Encoding.UTF8.GetChars(topicUtf8))); // QoS level tmpQosLevels.Add(buffer[index++]); } while (index < remainingLength); // copy from list to array msg.topics = new string[tmpTopics.Count]; msg.qosLevels = new byte[tmpQosLevels.Count]; for (int i = 0; i < tmpTopics.Count; i++) { msg.topics[i] = (string)tmpTopics[i]; msg.qosLevels[i] = (byte)tmpQosLevels[i]; } return(msg); }
/// <summary> /// Parse bytes for a CONNECT message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>CONNECT message instance</returns> public static MqttMsgConnect Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; int index = 0; int protNameUtf8Length; byte[] protNameUtf8; bool isUsernameFlag; bool isPasswordFlag; int clientIdUtf8Length; byte[] clientIdUtf8; int willTopicUtf8Length; byte[] willTopicUtf8; int willMessageUtf8Length; byte[] willMessageUtf8; int usernameUtf8Length; byte[] usernameUtf8; int passwordUtf8Length; byte[] passwordUtf8; MqttMsgConnect msg = new MqttMsgConnect(); // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... channel.Receive(buffer); // protocol name protNameUtf8Length = ((buffer[index++] << 8) & 0xFF00); protNameUtf8Length |= buffer[index++]; protNameUtf8 = new byte[protNameUtf8Length]; Array.Copy(buffer, index, protNameUtf8, 0, protNameUtf8Length); index += protNameUtf8Length; msg.protocolName = new String(Encoding.UTF8.GetChars(protNameUtf8)); // [v3.1.1] wrong protocol name if (!msg.protocolName.Equals(PROTOCOL_NAME_V3_1) && !msg.protocolName.Equals(PROTOCOL_NAME_V3_1_1)) { throw new MqttClientException(MqttClientErrorCode.InvalidProtocolName); } // protocol version msg.protocolVersion = buffer[index]; index += PROTOCOL_VERSION_SIZE; // connect flags // [v3.1.1] check lsb (reserved) must be 0 if ((msg.protocolVersion == PROTOCOL_VERSION_V3_1_1) && ((buffer[index] & RESERVED_FLAG_MASK) != 0x00)) { throw new MqttClientException(MqttClientErrorCode.InvalidConnectFlags); } isUsernameFlag = (buffer[index] & USERNAME_FLAG_MASK) != 0x00; isPasswordFlag = (buffer[index] & PASSWORD_FLAG_MASK) != 0x00; msg.willRetain = (buffer[index] & WILL_RETAIN_FLAG_MASK) != 0x00; msg.willQosLevel = (byte)((buffer[index] & WILL_QOS_FLAG_MASK) >> WILL_QOS_FLAG_OFFSET); msg.willFlag = (buffer[index] & WILL_FLAG_MASK) != 0x00; msg.cleanSession = (buffer[index] & CLEAN_SESSION_FLAG_MASK) != 0x00; index += CONNECT_FLAGS_SIZE; // keep alive timer msg.keepAlivePeriod = (ushort)((buffer[index++] << 8) & 0xFF00); msg.keepAlivePeriod |= buffer[index++]; // client identifier [v3.1.1] it may be zero bytes long (empty string) clientIdUtf8Length = ((buffer[index++] << 8) & 0xFF00); clientIdUtf8Length |= buffer[index++]; clientIdUtf8 = new byte[clientIdUtf8Length]; Array.Copy(buffer, index, clientIdUtf8, 0, clientIdUtf8Length); index += clientIdUtf8Length; msg.clientId = new String(Encoding.UTF8.GetChars(clientIdUtf8)); // [v3.1.1] if client identifier is zero bytes long, clean session must be true if ((msg.protocolVersion == PROTOCOL_VERSION_V3_1_1) && (clientIdUtf8Length == 0) && (!msg.cleanSession)) { throw new MqttClientException(MqttClientErrorCode.InvalidClientId); } // will topic and will message if (msg.willFlag) { willTopicUtf8Length = ((buffer[index++] << 8) & 0xFF00); willTopicUtf8Length |= buffer[index++]; willTopicUtf8 = new byte[willTopicUtf8Length]; Array.Copy(buffer, index, willTopicUtf8, 0, willTopicUtf8Length); index += willTopicUtf8Length; msg.willTopic = new String(Encoding.UTF8.GetChars(willTopicUtf8)); willMessageUtf8Length = ((buffer[index++] << 8) & 0xFF00); willMessageUtf8Length |= buffer[index++]; willMessageUtf8 = new byte[willMessageUtf8Length]; Array.Copy(buffer, index, willMessageUtf8, 0, willMessageUtf8Length); index += willMessageUtf8Length; msg.willMessage = new String(Encoding.UTF8.GetChars(willMessageUtf8)); } // username if (isUsernameFlag) { usernameUtf8Length = ((buffer[index++] << 8) & 0xFF00); usernameUtf8Length |= buffer[index++]; usernameUtf8 = new byte[usernameUtf8Length]; Array.Copy(buffer, index, usernameUtf8, 0, usernameUtf8Length); index += usernameUtf8Length; msg.username = new String(Encoding.UTF8.GetChars(usernameUtf8)); } // password if (isPasswordFlag) { passwordUtf8Length = ((buffer[index++] << 8) & 0xFF00); passwordUtf8Length |= buffer[index++]; passwordUtf8 = new byte[passwordUtf8Length]; Array.Copy(buffer, index, passwordUtf8, 0, passwordUtf8Length); index += passwordUtf8Length; msg.password = new String(Encoding.UTF8.GetChars(passwordUtf8)); } return(msg); }
/// <summary> /// Parse bytes for a PUBLISH message /// </summary> /// <param name="fixedHeaderFirstByte">First fixed header byte</param> /// <param name="protocolVersion">Protocol Version</param> /// <param name="channel">Channel connected to the broker</param> /// <returns>PUBLISH message instance</returns> public static MqttMsgPublish Parse(byte fixedHeaderFirstByte, byte protocolVersion, IMqttNetworkChannel channel) { byte[] buffer; int index = 0; byte[] topicUtf8; int topicUtf8Length; MqttMsgPublish msg = new MqttMsgPublish(); // get remaining length and allocate buffer int remainingLength = MqttMsgBase.decodeRemainingLength(channel); buffer = new byte[remainingLength]; // read bytes from socket... int received = channel.Receive(buffer); // topic name topicUtf8Length = ((buffer[index++] << 8) & 0xFF00); topicUtf8Length |= buffer[index++]; topicUtf8 = new byte[topicUtf8Length]; Array.Copy(buffer, index, topicUtf8, 0, topicUtf8Length); index += topicUtf8Length; msg.topic = new String(Encoding.UTF8.GetChars(topicUtf8)); // read QoS level from fixed header msg.qosLevel = (byte)((fixedHeaderFirstByte & QOS_LEVEL_MASK) >> QOS_LEVEL_OFFSET); // check wrong QoS level (both bits can't be set 1) if (msg.qosLevel > QOS_LEVEL_EXACTLY_ONCE) { throw new MqttClientException(MqttClientErrorCode.QosNotAllowed); } // read DUP flag from fixed header msg.dupFlag = (((fixedHeaderFirstByte & DUP_FLAG_MASK) >> DUP_FLAG_OFFSET) == 0x01); // read retain flag from fixed header msg.retain = (((fixedHeaderFirstByte & RETAIN_FLAG_MASK) >> RETAIN_FLAG_OFFSET) == 0x01); // message id is valid only with QOS level 1 or QOS level 2 if ((msg.qosLevel == QOS_LEVEL_AT_LEAST_ONCE) || (msg.qosLevel == QOS_LEVEL_EXACTLY_ONCE)) { // message id msg.messageId = (ushort)((buffer[index++] << 8) & 0xFF00); msg.messageId |= (buffer[index++]); } // get payload with message data int messageSize = remainingLength - index; int remaining = messageSize; int messageOffset = 0; msg.message = new byte[messageSize]; // BUG FIX 26/07/2013 : receiving large payload // copy first part of payload data received Array.Copy(buffer, index, msg.message, messageOffset, received - index); remaining -= (received - index); messageOffset += (received - index); // if payload isn't finished while (remaining > 0) { // receive other payload data received = channel.Receive(buffer); Array.Copy(buffer, 0, msg.message, messageOffset, received); remaining -= received; messageOffset += received; } return(msg); }