Example #1
0
        /// <summary>
        /// Parse bytes for a PUBACK 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>PUBACK message instance</returns>
        public static MqttMsgPuback Parse(byte[] data)
        {
            byte[]        buffer;
            int           index = 0;
            MqttMsgPuback msg   = new MqttMsgPuback();
            byte          fixedHeaderFirstByte = data[0];

            // [v3.1.1] check flag bits
            if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PUBACK_FLAG_BITS)
            {
                throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
            }
            // get remaining length and allocate buffer
            int remainingLength = MqttMsgBase.decodeRemainingLength(data);

            buffer = new byte[remainingLength];
            // buffer is filled with remaing lenght...
            for (int i = 2, j = 0; j < remainingLength; i++, j++)
            {
                buffer[j] = data[i];
            }

            // message id
            msg.messageId  = (ushort)((buffer[index++] << 8) & 0xFF00);
            msg.messageId |= (buffer[index++]);
            CrestronLogger.WriteToLog("PARSE PUBACK SUCCESS", 5);
            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[] data)
        {
            byte fixedHeaderFirstByte = data[0];

            byte[]         buffer;
            MqttMsgConnack msg = new MqttMsgConnack();

            // [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(data);

            buffer = new byte[remainingLength];
            // buffer is filled with remaing lenght...
            for (int i = 2, j = 0; j < remainingLength; i++, j++)
            {
                buffer[j] = data[i];
            }
            // [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);
        }
Example #3
0
        /// <summary>
        /// Parse bytes for a UNSUBSCRIBE 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>UNSUBSCRIBE message instance</returns>
        public static MqttMsgUnsubscribe Parse(byte[] data)
        {
            byte[] buffer;
            int    index = 0;

            byte[]             topicUtf8;
            int                topicUtf8Length;
            MqttMsgUnsubscribe msg = new MqttMsgUnsubscribe();
            byte               fixedHeaderFirstByte = data[0];

            // [v3.1.1] check flag bits
            if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_UNSUBSCRIBE_FLAG_BITS)
            {
                throw new MqttClientException(MqttClientErrorCode.InvalidFlagBits);
            }

            // get remaining length and allocate buffer
            int remainingLength = MqttMsgBase.decodeRemainingLength(data);

            buffer = new byte[remainingLength];
            // buffer is filled with remaing lenght...
            for (int i = 2, j = 0; j < remainingLength; i++, j++)
            {
                buffer[j] = data[i];
            }
            // read bytes from socket...
            int received = data.Length;

            // message id
            msg.messageId  = (ushort)((buffer[index++] << 8) & 0xFF00);
            msg.messageId |= (buffer[index++]);

            // payload contains topics
            // NOTE : before, I don't know how many topics will be in the payload (so use List)

            IList <String> tmpTopics = new List <String>();

            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)));
            } while (index < remainingLength);

            // copy from list to array
            msg.topics = new string[tmpTopics.Count];
            for (int i = 0; i < tmpTopics.Count; i++)
            {
                msg.topics[i] = (string)tmpTopics[i];
            }
            CrestronLogger.WriteToLog("UNSIBSCRIBER PARSE SUCCESS", 6);
            return(msg);
        }
        /// <summary>
        /// Parse bytes for a PINGRESP 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>PINGRESP message instance</returns>
        public static MqttMsgPingResp Parse(byte[] data)
        {
            byte            fixedHeaderFirstByte = data[0];
            MqttMsgPingResp msg = new MqttMsgPingResp();

            // [v3.1.1] check flag bits
            if ((fixedHeaderFirstByte & MSG_FLAG_BITS_MASK) != MQTT_MSG_PINGRESP_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(data);

            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[] data)
        {
            MqttMsgDisconnect msg     = new MqttMsgDisconnect();
            byte fixedHeaderFirstByte = data[0];

            // [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(data);

            // NOTE : remainingLength must be 0
            CrestronLogger.WriteToLog("DISCONNECT PARSE SUCCESS", 8);
            return(msg);
        }
Example #6
0
        /// <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[] data)
        {
            byte fixedHeaderFirstByte = data[0];

            byte[]        buffer;
            int           index = 0;
            MqttMsgSuback msg   = new MqttMsgSuback();

            // [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(data);

            buffer = new byte[remainingLength];

            // buffer is filled with remaing lenght...
            for (int i = 2, j = 0; j < remainingLength; i++, j++)
            {
                buffer[j] = data[i];
            }

            // 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 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[] data)
        {
            byte[] buffer;
            int    index = 0;

            byte[]         topicUtf8;
            int            topicUtf8Length;
            MqttMsgPublish msg = new MqttMsgPublish();
            byte           fixedHeaderFirstByte = data[0];

            // get remaining length and allocate buffer
            int remainingLength = MqttMsgBase.decodeRemainingLength(data);

            buffer = new byte[remainingLength];
            // buffer is filled with remaing lenght...
            for (int i = 2, j = 0; j < remainingLength; i++, j++)
            {
                buffer[j] = data[i];
            }
            //Skipping bytes indicating the lenght of payload
            index += remainingLength > 127 ? 1 : (remainingLength > 16383 ? 2 : (remainingLength > 2097151 ? 3 : 0));
            // read bytes lenght
            int received = data.Length;

            // 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 dataS
            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, messageSize);

            /*     remaining -= (received - index);
             *   messageOffset += (received - index);
             *
             *   //TODO:  if payload is large a lot , do multiple readings
             * 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);
        }
        /// <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[] data)
        {
            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();
            byte           fixedHeaderFirstByte = data[0];
            //Protocol Version is in the 7th byte of the data
            byte protocolVersion = data[6];
            // get remaining length and allocate buffer
            int remainingLength = MqttMsgBase.decodeRemainingLength(data);

            buffer = new byte[remainingLength];
            // buffer is filled with remaing lenght...
            for (int i = 2, j = 0; j < remainingLength; i++, j++)
            {
                buffer[j] = data[i];
            }
            // 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));
            }
            CrestronLogger.WriteToLog("MQTTMSGCONNECT - CONNECT PARSE SUCCESS", 1);
            return(msg);
        }