add new qloud-c-sdk component
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @file mqtt_packet_deserialize.c
|
||||
* @brief implements mqtt packet deserialize. Reference paho.mqtt.embedded-c &
|
||||
* http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.pdf
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-21
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-21 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "mqtt_packet.h"
|
||||
|
||||
/**
|
||||
* @brief Reads one character from the input buffer. See 1.5.1.
|
||||
*
|
||||
* @param[in,out] pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the character read
|
||||
*/
|
||||
static inline char _read_char(uint8_t** pptr)
|
||||
{
|
||||
char c = **pptr;
|
||||
(*pptr)++;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates an integer from two bytes read from the input buffer. See 1.5.2.
|
||||
*
|
||||
* @param[in,out] pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the integer value calculated
|
||||
*/
|
||||
static inline uint16_t _read_int(uint8_t** pptr)
|
||||
{
|
||||
uint8_t* ptr = *pptr;
|
||||
int len = 256 * (*ptr) + (*(ptr + 1));
|
||||
*pptr += 2;
|
||||
return (uint16_t)len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a UTF-8 encoded string pointer from the input buffer. See 1.5.3.
|
||||
*
|
||||
* @param[out] pstring the pointer of the C string to read.
|
||||
* @param[in,out] pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the length of string
|
||||
*/
|
||||
static inline int _read_string(char** pstring, uint8_t** pptr)
|
||||
{
|
||||
int str_len = _read_int(pptr);
|
||||
if (str_len > 0) {
|
||||
*pstring = (char*)*pptr;
|
||||
*pptr += str_len;
|
||||
}
|
||||
|
||||
return str_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check the mqtt type and get publish flags. See 2.2.
|
||||
*
|
||||
* @param[in] packet_type type of mqtt control packet, See 2.2.1
|
||||
* @param[in] pflags pointer to the flags of mqtt control packet fixed header. See 2.2.2
|
||||
* @param[in,out] pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
static int _mqtt_packet_type_check(MQTTPacketType packet_type, MQTTPublishFlags* pflags, uint8_t** pptr)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
|
||||
header.byte = _read_char(pptr);
|
||||
|
||||
switch (header.bits.type) {
|
||||
case PUBLISH:
|
||||
pflags->dup = header.bits.dup;
|
||||
pflags->qos = header.bits.qos;
|
||||
pflags->retain = header.bits.retain;
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
if ((header.byte & 0xf0) != 0x10) {
|
||||
return MQTT_ERR_INVALID_PACKET_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return packet_type != header.bits.type ? MQTT_ERR_INVALID_PACKET_TYPE : MQTT_RET_PACKET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize remaining length. See 2.2.3.
|
||||
*
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[in] plen the pointer to the remaining length
|
||||
* @param[in,out] pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
static int _mqtt_remaining_length_deserialize(int buf_len, int* plen, uint8_t** pptr)
|
||||
{
|
||||
uint8_t* buf = *pptr;
|
||||
uint8_t c = 0;
|
||||
uint32_t multiplier = 1;
|
||||
uint32_t count = 0;
|
||||
uint32_t len = 0;
|
||||
|
||||
do {
|
||||
if (++count > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
|
||||
return MQTT_ERR_INVALID_PACKET_TYPE;
|
||||
}
|
||||
c = *buf++;
|
||||
len += (c & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
|
||||
SHORT_BUFFER_CHECK(buf_len, count + 1 + len);
|
||||
} while (c & 128);
|
||||
|
||||
if (plen) {
|
||||
*plen = len;
|
||||
}
|
||||
|
||||
*pptr += count;
|
||||
return MQTT_RET_PACKET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize the supplied (wire) buffer into connack data. See 3.2.
|
||||
*
|
||||
* @param[in] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @param[out] session_present the session present flag returned (only for MQTT 3.1.1)
|
||||
* @param[out] connack_rc returned integer value of the connack return code
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
int mqtt_connack_packet_deserialize(uint8_t* buf, int buf_len, uint8_t* session_present, uint8_t* connack_rc)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
int rc = 0;
|
||||
MQTTConnackFlags flags = {0};
|
||||
|
||||
rc = _mqtt_packet_type_check(CONNACK, NULL, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = _mqtt_remaining_length_deserialize(buf_len, NULL, &ptr);
|
||||
if (rc < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
flags.all = _read_char(&ptr);
|
||||
*session_present = flags.bits.sessionpresent;
|
||||
*connack_rc = _read_char(&ptr);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize the supplied (wire) buffer into pingresp data. See 3.13.
|
||||
*
|
||||
* @param[in] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
int mqtt_pingresp_packet_deserialize(uint8_t* buf, int buf_len)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
int rc = 0;
|
||||
|
||||
rc = _mqtt_packet_type_check(PINGRESP, NULL, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = _mqtt_remaining_length_deserialize(buf_len, NULL, &ptr);
|
||||
if (rc < 0) {
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize the supplied (wire) buffer into publish data. See 3.3.
|
||||
*
|
||||
* @param[in] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @param[out] flags the MQTT dup, qos, retained flag
|
||||
* @param[out] packet_id returned integer - the MQTT packet identifier
|
||||
* @param[out] topic_name returned string - the MQTT topic in the publish
|
||||
* @param[out] topic_len returned integer - the length of the MQTT topic
|
||||
* @param[out] payload returned byte buffer - the MQTT publish payload
|
||||
* @param[out] payload_len returned integer - the length of the MQTT payload
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
int mqtt_publish_packet_deserialize(uint8_t* buf, int buf_len, MQTTPublishFlags* flags, uint16_t* packet_id,
|
||||
char** topic_name, int* topic_len, uint8_t** payload, int* payload_len)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
uint8_t* ptr_remain = NULL;
|
||||
int rc = 0;
|
||||
int len = 0;
|
||||
|
||||
rc = _mqtt_packet_type_check(PUBLISH, flags, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = _mqtt_remaining_length_deserialize(buf_len, &len, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ptr_remain = ptr;
|
||||
|
||||
rc = _read_string(topic_name, &ptr);
|
||||
if (rc <= 0) {
|
||||
rc = MQTT_ERR_INVALID_PACKET_TYPE;
|
||||
goto exit;
|
||||
}
|
||||
*topic_len = rc;
|
||||
|
||||
if (flags->qos > 0) {
|
||||
*packet_id = _read_int(&ptr);
|
||||
}
|
||||
|
||||
*payload_len = len - (ptr - ptr_remain);
|
||||
*payload = ptr;
|
||||
|
||||
rc = MQTT_RET_PACKET_OK;
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize the supplied (wire) buffer into an ack. See 3.4.
|
||||
*
|
||||
* @param[in] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @param[out] packet_id returned integer - the MQTT packet identifier
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
int mqtt_puback_packet_deserialize(uint8_t* buf, int buf_len, uint16_t* packet_id)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
int rc = 0;
|
||||
|
||||
rc = _mqtt_packet_type_check(PUBACK, 0, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = _mqtt_remaining_length_deserialize(buf_len, NULL, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*packet_id = _read_int(&ptr);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize the supplied (wire) buffer into suback data. See 3.9.
|
||||
*
|
||||
* @param[in] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @param[in] maxcount - the maximum number of members allowed in the grantedQoSs array
|
||||
* @param[out] count returned integer - number of members in the grantedQoSs array
|
||||
* @param[out] packet_id returned integer - the MQTT packet identifier
|
||||
* @param[out] granted_qos returned array of integers - the granted qualities of service
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
int mqtt_suback_packet_deserialize(uint8_t* buf, int buf_len, int maxcount, int* count, uint16_t* packet_id,
|
||||
int granted_qos[])
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
int rc = 0;
|
||||
int len = 0;
|
||||
|
||||
rc = _mqtt_packet_type_check(SUBACK, NULL, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = _mqtt_remaining_length_deserialize(buf_len, &len, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*packet_id = _read_int(&ptr);
|
||||
len -= 2;
|
||||
|
||||
*count = 0;
|
||||
while (len--) {
|
||||
if (*count > maxcount) {
|
||||
rc = MQTT_ERR_SUB_COUNT_EXCEED;
|
||||
goto exit;
|
||||
}
|
||||
granted_qos[(*count)++] = _read_char(&ptr);
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize the supplied (wire) buffer into unsuback data. See 3.11.
|
||||
*
|
||||
* @param[in] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @param[out] packet_id returned integer - the MQTT packet identifier
|
||||
* @return @see MQTTPacketErrCode
|
||||
*/
|
||||
int mqtt_unsuback_packet_deserialize(uint8_t* buf, int buf_len, uint16_t* packet_id)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
int rc = 0;
|
||||
|
||||
rc = _mqtt_packet_type_check(UNSUBACK, NULL, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = _mqtt_remaining_length_deserialize(buf_len, NULL, &ptr);
|
||||
if (rc) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*packet_id = _read_int(&ptr);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
* @copyright
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License(the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @file mqtt_packet_serialize.c
|
||||
* @brief implements mqtt packet serialize. Reference paho.mqtt.embedded-c &
|
||||
* http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.pdf
|
||||
* @author fancyxu (fancyxu@tencent.com)
|
||||
* @version 1.0
|
||||
* @date 2021-05-21
|
||||
*
|
||||
* @par Change Log:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2021-05-21 <td>1.0 <td>fancyxu <td>first commit
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#include "mqtt_packet.h"
|
||||
|
||||
/**
|
||||
* @brief Writes one character to an output buffer. See 1.5.1.
|
||||
*
|
||||
* @param[in] c the character to write
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static inline void _write_char(char c, uint8_t** pptr)
|
||||
{
|
||||
**pptr = c;
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes an integer as 2 bytes to an output buffer. See 1.5.2.
|
||||
*
|
||||
* @param[in] value the integer to write.
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned.
|
||||
*/
|
||||
static inline void _write_int(int value, uint8_t** pptr)
|
||||
{
|
||||
**pptr = (uint8_t)(value / 256);
|
||||
(*pptr)++;
|
||||
**pptr = (uint8_t)(value % 256);
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a UTF-8 encoded string to an output buffer. Converts C string to
|
||||
* length-delimited. See 1.5.3.
|
||||
*
|
||||
* @param[in] string the C string to write
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static inline void _write_string(const char* string, uint8_t** pptr)
|
||||
{
|
||||
int len = strlen(string);
|
||||
_write_int(len, pptr);
|
||||
memcpy(*pptr, string, len);
|
||||
*pptr += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize mqtt fixed header except remaining length. See 2.2.
|
||||
*
|
||||
* @param[in] packet_type type of mqtt control packet, See 2.2.1 MQTT Control Packet type
|
||||
* @param[in] pflags pointer to the flags of mqtt control packet fixed header. See 2.2.2 Flags
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static void _mqtt_header_serialize(MQTTPacketType packet_type, const MQTTPublishFlags* pflags, uint8_t** pptr)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
|
||||
switch (packet_type) {
|
||||
case PUBLISH:
|
||||
header.bits.dup = pflags->dup;
|
||||
header.bits.qos = pflags->qos;
|
||||
header.bits.retain = pflags->retain;
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
header.byte = 0x02;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
header.bits.type |= packet_type;
|
||||
_write_char(header.byte, pptr); /* write header */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize remaining length. See 2.2.3.
|
||||
*
|
||||
* @param[in] length the length to be encoded to remaining length
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static void _mqtt_remaining_length_serialize(int length, uint8_t** pptr)
|
||||
{
|
||||
char d;
|
||||
do {
|
||||
d = length % 128;
|
||||
length /= 128;
|
||||
|
||||
// if there are more digits to encode, set the top bit of this digit
|
||||
if (length > 0) {
|
||||
d |= 0x80;
|
||||
}
|
||||
|
||||
_write_char(d, pptr);
|
||||
} while (length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the remaining length of the MQTT connect packet that would be produced using the
|
||||
* supplied connect options. See 3.1.1.
|
||||
*
|
||||
* @param[in] options the options to be used to build the connect packet
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static int _mqtt_connect_remaining_length_serialize(const MQTTPacketConnectOption* options, int buf_len, uint8_t** pptr)
|
||||
{
|
||||
if (options->mqtt_version != 3 && options->mqtt_version != 4) {
|
||||
return MQTT_ERR_VERSION_UNSUPPORTED;
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
|
||||
len = options->mqtt_version == 3 ? 12 : 10;
|
||||
|
||||
len += strlen(options->client_id) + 2;
|
||||
|
||||
if (options->will_flag) {
|
||||
len += strlen(options->will.topic_name) + 2 + strlen(options->will.message) + 2;
|
||||
}
|
||||
|
||||
if (options->username) {
|
||||
len += strlen(options->username) + 2;
|
||||
}
|
||||
|
||||
if (options->password) {
|
||||
len += strlen(options->password) + 2;
|
||||
}
|
||||
|
||||
SHORT_BUFFER_CHECK(buf_len, len);
|
||||
|
||||
_mqtt_remaining_length_serialize(len, pptr);
|
||||
|
||||
return MQTT_RET_PACKET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the mqtt connect packet variable header. See 3.1.2.
|
||||
*
|
||||
* @param[in] options the options to be used to build the connect packet
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static int _mqtt_connect_variable_header_serialize(const MQTTPacketConnectOption* options, uint8_t** pptr)
|
||||
{
|
||||
if (options->password && !options->username) {
|
||||
return MQTT_ERR_INVALID_PACKET_TYPE;
|
||||
}
|
||||
|
||||
// 3.1.2.1 protocol name & 3.1.2.2 protocol level
|
||||
switch (options->mqtt_version) {
|
||||
case 3:
|
||||
_write_string("MQIsdp", pptr);
|
||||
_write_char((char)3, pptr);
|
||||
break;
|
||||
case 4:
|
||||
_write_string("MQTT", pptr);
|
||||
_write_char((char)4, pptr);
|
||||
break;
|
||||
}
|
||||
|
||||
// 3.1.2.3 Connect Flags
|
||||
MQTTConnectFlags flags = {
|
||||
.bits.clean_session = options->clean_session,
|
||||
.bits.will = options->will_flag,
|
||||
.bits.will_qos = options->will_flag ? options->will.qos : 0,
|
||||
.bits.will_retain = options->will_flag ? options->will.retained : 0,
|
||||
.bits.username = options->username ? 1 : 0,
|
||||
.bits.password = options->password ? 1 : 0,
|
||||
};
|
||||
_write_char(flags.all, pptr);
|
||||
|
||||
return MQTT_RET_PACKET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the remaining length of the MQTT publish packet that would be produced using the supplied
|
||||
* parameters. See 3.3.2 & 3.3.3.
|
||||
*
|
||||
* @param[in] qos the MQTT QoS of the publish (packet id is omitted for QoS 0)
|
||||
* @param[in] topic_name the topic name to be used in the publish
|
||||
* @param[in] payload_len the length of the payload to be sent
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static int _mqtt_publish_remaining_length_serialize(uint8_t qos, const char* topic_name, int payload_len, int buf_len,
|
||||
uint8_t** pptr)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len += 2 + strlen(topic_name) + payload_len;
|
||||
if (qos > 0) {
|
||||
len += 2; /* packet id */
|
||||
}
|
||||
|
||||
SHORT_BUFFER_CHECK(buf_len, len + MAX_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
_mqtt_remaining_length_serialize(len, pptr);
|
||||
return MQTT_RET_PACKET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the length of the MQTT subscribe/unsubscribe packet that would be produced using the
|
||||
* supplied parameters. See 3.8.1 & 3.10.1.
|
||||
*
|
||||
* @param[in] count the number of topic filter strings in topicFilters
|
||||
* @param[in] topic_filters the array of topic filter strings to be used in the publish
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[out] pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
*/
|
||||
static int _mqtt_sub_unsub_remaining_length_serialize(uint32_t count, char* topic_filters[], int buf_len,
|
||||
uint8_t** pptr, uint8_t is_sub)
|
||||
{
|
||||
int i = 0;
|
||||
int len = 2; /* packet id */
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
len += 2 + strlen(topic_filters[i]) + is_sub; /* length + topic */
|
||||
}
|
||||
|
||||
SHORT_BUFFER_CHECK(buf_len, len + MAX_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
_mqtt_remaining_length_serialize(len, pptr);
|
||||
return MQTT_RET_PACKET_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the connect options into the buffer. See 3.1.
|
||||
*
|
||||
* @param[out] buf the buffer into which the packet will be serialized
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[in] options the options to be used to build the connect packet
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_connect_packet_serialize(uint8_t* buf, int buf_len, const MQTTPacketConnectOption* options)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
int rc;
|
||||
uint8_t* ptr = buf;
|
||||
|
||||
// 3.1.1 Fixed header
|
||||
_mqtt_header_serialize(CONNECT, NULL, &ptr);
|
||||
|
||||
rc = _mqtt_connect_remaining_length_serialize(options, buf_len, &ptr);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 3.1.2 Variable header
|
||||
rc = _mqtt_connect_variable_header_serialize(options, &ptr);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 3.1.3 Payload
|
||||
_write_int(options->keep_alive_interval, &ptr);
|
||||
_write_string(options->client_id, &ptr);
|
||||
|
||||
if (options->will_flag) {
|
||||
_write_string(options->will.topic_name, &ptr);
|
||||
_write_string(options->will.message, &ptr);
|
||||
}
|
||||
|
||||
if (options->username) {
|
||||
_write_string(options->username, &ptr);
|
||||
}
|
||||
|
||||
if (options->password) {
|
||||
_write_string(options->password, &ptr);
|
||||
}
|
||||
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize a disconnect packet into the supplied buffer, ready for writing to a socket. See 3.14.
|
||||
*
|
||||
* @param[out] buf the buffer into which the packet will be serialized
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer, to avoid overruns
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_disconnect_packet_serialize(uint8_t* buf, int buf_len)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
_mqtt_header_serialize(DISCONNECT, 0, &ptr);
|
||||
_mqtt_remaining_length_serialize(0, &ptr);
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize a disconnect packet into the supplied buffer, ready for writing to a socket. See 3.12.
|
||||
*
|
||||
* @param[out] buf the buffer into which the packet will be serialized
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer, to avoid overruns
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_pingreq_packet_serialize(uint8_t* buf, int buf_len)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
_mqtt_header_serialize(PINGREQ, 0, &ptr);
|
||||
_mqtt_remaining_length_serialize(0, &ptr);
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the supplied publish data into the supplied buffer, ready for sending. See 3.3.
|
||||
*
|
||||
* @param[out] buf the buffer into which the packet will be serialized
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[in] flags the MQTT dup, qos, retained flag
|
||||
* @param[in] packet_id integer - the MQTT packet identifier
|
||||
* @param[in] topic_name char * - the MQTT topic in the publish
|
||||
* @param[in] payload byte buffer - the MQTT publish payload
|
||||
* @param[in] payload_len integer - the length of the MQTT payload
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_publish_packet_serialize(uint8_t* buf, int buf_len, const MQTTPublishFlags* flags, uint16_t packet_id,
|
||||
const char* topic_name, const uint8_t* payload, int payload_len)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
int rc;
|
||||
uint8_t* ptr = buf;
|
||||
|
||||
_mqtt_header_serialize(PUBLISH, flags, &ptr);
|
||||
|
||||
rc = _mqtt_publish_remaining_length_serialize(flags->qos, topic_name, payload_len, buf_len, &ptr);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
_write_string(topic_name, &ptr);
|
||||
|
||||
if (flags->qos > 0) {
|
||||
_write_int(packet_id, &ptr);
|
||||
}
|
||||
|
||||
memcpy(ptr, payload, payload_len);
|
||||
|
||||
ptr += payload_len;
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize a puback packet into the supplied buffer. See 3.4.
|
||||
*
|
||||
* @param[out] buf the buffer into which the packet will be serialized
|
||||
* @param[in] buf_len the length in bytes of the supplied buffer
|
||||
* @param[in] packet_id integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_puback_packet_serialize(uint8_t* buf, int buf_len, uint16_t packet_id)
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN + 2);
|
||||
|
||||
uint8_t* ptr = buf;
|
||||
|
||||
_mqtt_header_serialize(PUBACK, 0, &ptr);
|
||||
_mqtt_remaining_length_serialize(2, &ptr);
|
||||
_write_int(packet_id, &ptr);
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the supplied subscribe data into the supplied buffer, ready for sending. See 3.8.
|
||||
*
|
||||
* @param[out] buf the buffer into which the packet will be serialized
|
||||
* @param[in] buf_len the length in bytes of the supplied bufferr
|
||||
* @param[in] packet_id integer - the MQTT packet identifier
|
||||
* @param[in] count - number of members in the topicFilters and reqQos arrays
|
||||
* @param[in] topic_filters - array of topic filter names
|
||||
* @param[in] requested_qos - array of requested QoS
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_subscribe_packet_serialize(uint8_t* buf, int buf_len, uint16_t packet_id, uint32_t count,
|
||||
char* topic_filters[], const int requested_qos[])
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
int rc, i = 0;
|
||||
uint8_t* ptr = buf;
|
||||
|
||||
_mqtt_header_serialize(SUBSCRIBE, 0, &ptr);
|
||||
rc = _mqtt_sub_unsub_remaining_length_serialize(count, topic_filters, buf_len, &ptr, 1);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
_write_int(packet_id, &ptr);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
_write_string(topic_filters[i], &ptr);
|
||||
_write_char(requested_qos[i], &ptr);
|
||||
}
|
||||
|
||||
return ptr - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the supplied unsubscribe data into the supplied buffer, ready for sending. See 3.10.
|
||||
*
|
||||
* @param[out] buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param[in] buf_len the length in bytes of the data in the supplied buffer
|
||||
* @param[in] packet_id integer - the MQTT packet identifier
|
||||
* @param[in] count - number of members in the topicFilters array
|
||||
* @param[in] topic_filters - array of topic filter names
|
||||
* @return serialized length, or error if <= 0
|
||||
*/
|
||||
int mqtt_unsubscribe_packet_serialize(uint8_t* buf, int buf_len, uint16_t packet_id, int count, char* topic_filters[])
|
||||
{
|
||||
SHORT_BUFFER_CHECK(buf_len, MIN_MQTT_FIXED_HEADER_LEN);
|
||||
|
||||
int rc, i = 0;
|
||||
uint8_t* ptr = buf;
|
||||
|
||||
_mqtt_header_serialize(UNSUBSCRIBE, 0, &ptr);
|
||||
rc = _mqtt_sub_unsub_remaining_length_serialize(count, topic_filters, buf_len, &ptr, 0);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
_write_int(packet_id, &ptr);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
_write_string(topic_filters[i], &ptr);
|
||||
}
|
||||
|
||||
return ptr - buf;
|
||||
}
|
Reference in New Issue
Block a user