743 lines
18 KiB
C
743 lines
18 KiB
C
#include "packet.h"
|
|
|
|
lwmqtt_err_t lwmqtt_detect_packet_type(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t *packet_type) {
|
|
// set default packet type
|
|
*packet_type = LWMQTT_NO_PACKET;
|
|
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// prepare header
|
|
uint8_t header;
|
|
|
|
// read header
|
|
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// get packet type
|
|
*packet_type = (lwmqtt_packet_type_t)lwmqtt_read_bits(header, 4, 4);
|
|
|
|
// check if packet type is correct and can be received
|
|
switch (*packet_type) {
|
|
case LWMQTT_CONNACK_PACKET:
|
|
case LWMQTT_PUBLISH_PACKET:
|
|
case LWMQTT_PUBACK_PACKET:
|
|
case LWMQTT_PUBREC_PACKET:
|
|
case LWMQTT_PUBREL_PACKET:
|
|
case LWMQTT_PUBCOMP_PACKET:
|
|
case LWMQTT_SUBACK_PACKET:
|
|
case LWMQTT_UNSUBACK_PACKET:
|
|
case LWMQTT_PINGRESP_PACKET:
|
|
return LWMQTT_SUCCESS;
|
|
default:
|
|
*packet_type = LWMQTT_NO_PACKET;
|
|
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
|
}
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_detect_remaining_length(uint8_t *buf, size_t buf_len, uint32_t *rem_len) {
|
|
// prepare pointer
|
|
uint8_t *ptr = buf;
|
|
|
|
// attempt to decode remaining length
|
|
lwmqtt_err_t err = lwmqtt_read_varnum(&ptr, buf + buf_len, rem_len);
|
|
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
|
*rem_len = 0;
|
|
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
|
} else if (err != LWMQTT_SUCCESS) {
|
|
*rem_len = 0;
|
|
return err;
|
|
}
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_encode_connect(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_options_t options,
|
|
lwmqtt_will_t *will) {
|
|
// prepare pointers
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// fixed header is 10
|
|
uint32_t rem_len = 10;
|
|
|
|
// add client id to remaining length
|
|
rem_len += options.client_id.len + 2;
|
|
|
|
// add will if present to remaining length
|
|
if (will != NULL) {
|
|
rem_len += will->topic.len + 2 + will->payload.len + 2;
|
|
}
|
|
|
|
// add username if present to remaining length
|
|
if (options.username.len > 0) {
|
|
rem_len += options.username.len + 2;
|
|
|
|
// add password if present to remaining length
|
|
if (options.password.len > 0) {
|
|
rem_len += options.password.len + 2;
|
|
}
|
|
}
|
|
|
|
// check remaining length length
|
|
int rem_len_len;
|
|
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
|
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
|
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
|
}
|
|
|
|
// prepare header
|
|
uint8_t header = 0;
|
|
lwmqtt_write_bits(&header, LWMQTT_CONNECT_PACKET, 4, 4);
|
|
|
|
// write header
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write remaining length
|
|
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write version string
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, lwmqtt_string("MQTT"));
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write version number
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, 4);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// prepare flags
|
|
uint8_t flags = 0;
|
|
|
|
// set clean session
|
|
lwmqtt_write_bits(&flags, (uint8_t)(options.clean_session), 1, 1);
|
|
|
|
// set will flags if present
|
|
if (will != NULL) {
|
|
lwmqtt_write_bits(&flags, 1, 2, 1);
|
|
lwmqtt_write_bits(&flags, will->qos, 3, 2);
|
|
lwmqtt_write_bits(&flags, (uint8_t)(will->retained), 5, 1);
|
|
}
|
|
|
|
// set username flag if present
|
|
if (options.username.len > 0) {
|
|
lwmqtt_write_bits(&flags, 1, 7, 1);
|
|
|
|
// set password flag if present
|
|
if (options.password.len > 0) {
|
|
lwmqtt_write_bits(&flags, 1, 6, 1);
|
|
}
|
|
}
|
|
|
|
// write flags
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, flags);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write keep alive
|
|
err = lwmqtt_write_num(&buf_ptr, buf_end, options.keep_alive);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write client id
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, options.client_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write will if present
|
|
if (will != NULL) {
|
|
// write topic
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, will->topic);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write payload length
|
|
err = lwmqtt_write_num(&buf_ptr, buf_end, (uint16_t)will->payload.len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write payload
|
|
err = lwmqtt_write_data(&buf_ptr, buf_end, (uint8_t *)will->payload.data, will->payload.len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// write username if present
|
|
if (options.username.len > 0) {
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, options.username);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// write password if present
|
|
if (options.username.len > 0 && options.password.len > 0) {
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, options.password);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// set written length
|
|
*len = buf_ptr - buf;
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_decode_connack(uint8_t *buf, size_t buf_len, bool *session_present,
|
|
lwmqtt_return_code_t *return_code) {
|
|
// prepare pointers
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// read header
|
|
uint8_t header;
|
|
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check packet type
|
|
if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_CONNACK_PACKET) {
|
|
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
|
}
|
|
|
|
// read remaining length
|
|
uint32_t rem_len;
|
|
err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check remaining length
|
|
if (rem_len != 2) {
|
|
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
|
}
|
|
|
|
// read flags
|
|
uint8_t flags;
|
|
err = lwmqtt_read_byte(&buf_ptr, buf_end, &flags);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// read return code
|
|
uint8_t raw_return_code;
|
|
err = lwmqtt_read_byte(&buf_ptr, buf_end, &raw_return_code);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// get session present
|
|
*session_present = lwmqtt_read_bits(flags, 7, 1) == 1;
|
|
|
|
// get return code
|
|
switch (raw_return_code) {
|
|
case 0:
|
|
*return_code = LWMQTT_CONNECTION_ACCEPTED;
|
|
break;
|
|
case 1:
|
|
*return_code = LWMQTT_UNACCEPTABLE_PROTOCOL;
|
|
break;
|
|
case 2:
|
|
*return_code = LWMQTT_IDENTIFIER_REJECTED;
|
|
break;
|
|
case 3:
|
|
*return_code = LWMQTT_SERVER_UNAVAILABLE;
|
|
break;
|
|
case 4:
|
|
*return_code = LWMQTT_BAD_USERNAME_OR_PASSWORD;
|
|
break;
|
|
case 5:
|
|
*return_code = LWMQTT_NOT_AUTHORIZED;
|
|
break;
|
|
default:
|
|
*return_code = LWMQTT_UNKNOWN_RETURN_CODE;
|
|
}
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_encode_zero(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// write header
|
|
uint8_t header = 0;
|
|
lwmqtt_write_bits(&header, packet_type, 4, 4);
|
|
lwmqtt_err_t err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write remaining length
|
|
err = lwmqtt_write_varnum(&buf_ptr, buf_end, 0);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// set length
|
|
*len = buf_ptr - buf;
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_decode_ack(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t packet_type, bool *dup,
|
|
uint16_t *packet_id) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// read header
|
|
uint8_t header = 0;
|
|
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check packet type
|
|
if (lwmqtt_read_bits(header, 4, 4) != packet_type) {
|
|
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
|
}
|
|
|
|
// get dup
|
|
*dup = lwmqtt_read_bits(header, 3, 1) == 1;
|
|
|
|
// read remaining length
|
|
uint32_t rem_len;
|
|
err = lwmqtt_read_varnum(&buf_ptr, buf + buf_len, &rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check remaining length
|
|
if (rem_len != 2) {
|
|
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
|
}
|
|
|
|
// read packet id
|
|
err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_encode_ack(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type, bool dup,
|
|
uint16_t packet_id) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// prepare header
|
|
uint8_t header = 0;
|
|
|
|
// set packet type
|
|
lwmqtt_write_bits(&header, packet_type, 4, 4);
|
|
|
|
// set dup
|
|
lwmqtt_write_bits(&header, (uint8_t)(dup), 3, 1);
|
|
|
|
// set qos
|
|
lwmqtt_write_bits(&header, (uint8_t)(packet_type == LWMQTT_PUBREL_PACKET ? LWMQTT_QOS1 : LWMQTT_QOS0), 1, 2);
|
|
|
|
// write header
|
|
lwmqtt_err_t err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write remaining length
|
|
err = lwmqtt_write_varnum(&buf_ptr, buf_end, 2);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write packet id
|
|
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// set written length
|
|
*len = buf_ptr - buf;
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_decode_publish(uint8_t *buf, size_t buf_len, bool *dup, uint16_t *packet_id, lwmqtt_string_t *topic,
|
|
lwmqtt_message_t *msg) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// read header
|
|
uint8_t header;
|
|
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check packet type
|
|
if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_PUBLISH_PACKET) {
|
|
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
|
}
|
|
|
|
// get dup
|
|
*dup = lwmqtt_read_bits(header, 3, 1) == 1;
|
|
|
|
// get retained
|
|
msg->retained = lwmqtt_read_bits(header, 0, 1) == 1;
|
|
|
|
// get qos
|
|
switch (lwmqtt_read_bits(header, 1, 2)) {
|
|
case 0:
|
|
msg->qos = LWMQTT_QOS0;
|
|
break;
|
|
case 1:
|
|
msg->qos = LWMQTT_QOS1;
|
|
break;
|
|
case 2:
|
|
msg->qos = LWMQTT_QOS2;
|
|
break;
|
|
default:
|
|
msg->qos = LWMQTT_QOS0;
|
|
break;
|
|
}
|
|
|
|
// read remaining length
|
|
uint32_t rem_len;
|
|
err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check remaining length (topic length)
|
|
if (rem_len < 2) {
|
|
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
|
}
|
|
|
|
// check buffer capacity
|
|
if ((uint32_t)(buf_end - buf_ptr) < rem_len) {
|
|
return LWMQTT_BUFFER_TOO_SHORT;
|
|
}
|
|
|
|
// reset buf end
|
|
buf_end = buf_ptr + rem_len;
|
|
|
|
// read topic
|
|
err = lwmqtt_read_string(&buf_ptr, buf_end, topic);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// read packet id if qos is at least 1
|
|
if (msg->qos > 0) {
|
|
err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
} else {
|
|
*packet_id = 0;
|
|
}
|
|
|
|
// set payload length
|
|
msg->payload_len = buf_end - buf_ptr;
|
|
|
|
// read payload
|
|
err = lwmqtt_read_data(&buf_ptr, buf_end, &msg->payload, buf_end - buf_ptr);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_encode_publish(uint8_t *buf, size_t buf_len, size_t *len, bool dup, uint16_t packet_id,
|
|
lwmqtt_string_t topic, lwmqtt_message_t msg) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// calculate remaining length
|
|
uint32_t rem_len = 2 + topic.len + (uint32_t)msg.payload_len;
|
|
if (msg.qos > 0) {
|
|
rem_len += 2;
|
|
}
|
|
|
|
// check remaining length length
|
|
int rem_len_len;
|
|
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
|
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
|
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
|
}
|
|
|
|
// prepare header
|
|
uint8_t header = 0;
|
|
|
|
// set packet type
|
|
lwmqtt_write_bits(&header, LWMQTT_PUBLISH_PACKET, 4, 4);
|
|
|
|
// set dup
|
|
lwmqtt_write_bits(&header, (uint8_t)(dup), 3, 1);
|
|
|
|
// set qos
|
|
lwmqtt_write_bits(&header, msg.qos, 1, 2);
|
|
|
|
// set retained
|
|
lwmqtt_write_bits(&header, (uint8_t)(msg.retained), 0, 1);
|
|
|
|
// write header
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write remaining length
|
|
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write topic
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, topic);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write packet id if qos is at least 1
|
|
if (msg.qos > 0) {
|
|
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// write payload
|
|
err = lwmqtt_write_data(&buf_ptr, buf_end, msg.payload, msg.payload_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// set length
|
|
*len = buf_ptr - buf;
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_encode_subscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count,
|
|
lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// calculate remaining length
|
|
uint32_t rem_len = 2;
|
|
for (int i = 0; i < count; i++) {
|
|
rem_len += 2 + topic_filters[i].len + 1;
|
|
}
|
|
|
|
// check remaining length length
|
|
int rem_len_len;
|
|
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
|
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
|
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
|
}
|
|
|
|
// prepare header
|
|
uint8_t header = 0;
|
|
|
|
// set packet type
|
|
lwmqtt_write_bits(&header, LWMQTT_SUBSCRIBE_PACKET, 4, 4);
|
|
|
|
// set qos
|
|
lwmqtt_write_bits(&header, LWMQTT_QOS1, 1, 2);
|
|
|
|
// write header
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write remaining length
|
|
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write packet id
|
|
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write all subscriptions
|
|
for (int i = 0; i < count; i++) {
|
|
// write topic
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, topic_filters[i]);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write qos level
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, (uint8_t)qos_levels[i]);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// set length
|
|
*len = buf_ptr - buf;
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_decode_suback(uint8_t *buf, size_t buf_len, uint16_t *packet_id, int max_count, int *count,
|
|
lwmqtt_qos_t *granted_qos_levels) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// read header
|
|
uint8_t header;
|
|
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check packet type
|
|
if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_SUBACK_PACKET) {
|
|
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
|
}
|
|
|
|
// read remaining length
|
|
uint32_t rem_len;
|
|
err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// check remaining length (packet id + min. one suback code)
|
|
if (rem_len < 3) {
|
|
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
|
}
|
|
|
|
// read packet id
|
|
err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// read all suback codes
|
|
for (*count = 0; *count < (int)rem_len - 2; (*count)++) {
|
|
// check max count
|
|
if (*count > max_count) {
|
|
return LWMQTT_SUBACK_ARRAY_OVERFLOW;
|
|
}
|
|
|
|
// read qos level
|
|
uint8_t raw_qos_level;
|
|
err = lwmqtt_read_byte(&buf_ptr, buf_end, &raw_qos_level);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// set qos level
|
|
switch (raw_qos_level) {
|
|
case 0:
|
|
granted_qos_levels[*count] = LWMQTT_QOS0;
|
|
break;
|
|
case 1:
|
|
granted_qos_levels[*count] = LWMQTT_QOS1;
|
|
break;
|
|
case 2:
|
|
granted_qos_levels[*count] = LWMQTT_QOS2;
|
|
break;
|
|
default:
|
|
granted_qos_levels[*count] = LWMQTT_QOS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|
|
|
|
lwmqtt_err_t lwmqtt_encode_unsubscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count,
|
|
lwmqtt_string_t *topic_filters) {
|
|
// prepare pointer
|
|
uint8_t *buf_ptr = buf;
|
|
uint8_t *buf_end = buf + buf_len;
|
|
|
|
// calculate remaining length
|
|
uint32_t rem_len = 2;
|
|
for (int i = 0; i < count; i++) {
|
|
rem_len += 2 + topic_filters[i].len;
|
|
}
|
|
|
|
// check remaining length length
|
|
int rem_len_len;
|
|
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
|
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
|
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
|
}
|
|
|
|
// prepare header
|
|
uint8_t header = 0;
|
|
|
|
// set packet type
|
|
lwmqtt_write_bits(&header, LWMQTT_UNSUBSCRIBE_PACKET, 4, 4);
|
|
|
|
// set qos
|
|
lwmqtt_write_bits(&header, LWMQTT_QOS1, 1, 2);
|
|
|
|
// write header
|
|
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write remaining length
|
|
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write packet id
|
|
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
|
|
// write topics
|
|
for (int i = 0; i < count; i++) {
|
|
err = lwmqtt_write_string(&buf_ptr, buf_end, topic_filters[i]);
|
|
if (err != LWMQTT_SUCCESS) {
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// set length
|
|
*len = buf_ptr - buf;
|
|
|
|
return LWMQTT_SUCCESS;
|
|
}
|