};
/* MQTT connack packet */
-struct mqtt_connack_response_pkt {
+struct mqtt_connack_reply_pkt {
uint8_t control; /* Paquet type : must be (MQTT_CONTROL_CONNACK << 4) */
uint8_t rem_len; /* Remaining length : must be 0x02 */
uint8_t flags; /* Connect acknowledge flags */
* The function returns -EINVAL if pkt is NULL, -EPROTO in case of invalid connack packet or
* -EREMOTEIO in case of connection refused by the server (ret_code is then valid in the packet).
*/
-int mqtt_check_connack_response_pkt(const struct mqtt_connack_response_pkt* pkt);
+int mqtt_check_connack_reply_pkt(const struct mqtt_connack_reply_pkt* pkt);
/***************************************************************************** */
/* publish and puback packets */
int mqtt_pack_publish_packet(const struct mqtt_publish_pkt* pkt, uint8_t* buf, uint32_t buf_size);
+/* Unpack MQTT publish packet
+ * This function must be called in order to transform a received publish MQTT packet to a
+ * mqtt_publish_pkt structure.
+ * The function also checks the validity of the packet.
+ * All returned pointers within the struct will point to parts of the provided buffer, so the buffer
+ * must not be discarded after the call.
+ * if the return value is positive, it is the topic string length.
+ */
+int mqtt_unpack_publish_packet(struct mqtt_publish_pkt* pkt, uint8_t* buf, uint32_t size);
+
#define MQTT_PUBREL_FLAG (0x01 << 1)
-/* MQTT publish responses packet, used for puback, pubrec, pubrel and pubcomp */
-/* control paquet type must be either (MQTT_CONTROL_PUBACK << 4) if QoS = 1 (no further response required)
+/* MQTT publish replies packet, used for puback, pubrec, pubrel and pubcomp */
+/* control paquet type must be either (MQTT_CONTROL_PUBACK << 4) if QoS = 1 (no further reply required)
* or (MQTT_CONTROL_PUBREC << 4) if QoS = 2 and then a publish release must be received or sent
* (MQTT_CONTROL_PUBREL << 4), answered by a publish complete packet (MQTT_CONTROL_PUBCOMP << 4) */
-struct mqtt_publish_response_pkt {
+struct mqtt_publish_reply_pkt {
uint8_t control; /* Packet type */
uint8_t rem_len; /* Remaining length : must be 0x02 */
uint16_t acked_pkt_id; /* Id of packet that is being acknowledged, in network endianness */
/* Build MQTT puback, pubrec, pubrel or pubcomp packet, used in the publish acknowledge one-way or
* two-way hand-check mechanism.
* The provided buf must be big enough to hold 4 bytes.
- * Note that buf may safely be cast to or from a mqtt_publish_response_pkt struct pointer.
+ * Note that buf may safely be cast to or from a mqtt_publish_reply_pkt struct pointer.
* type is one of MQTT_CONTROL_PUBACK, MQTT_CONTROL_PUBREC, MQTT_CONTROL_PUBREL or MQTT_CONTROL_PUBCOMP.
* acked_pkt_id is the ID of the concerned publish packet, in host endianness.
* Returns the used buffer size (4 bytes) on success, or -EINVAL in case of a NULL buf pointer.
*/
-int mqtt_pack_publish_response_pkt(uint8_t* buf, uint16_t acked_pkt_id, uint8_t type);
+int mqtt_pack_publish_reply_pkt(uint8_t* buf, uint16_t acked_pkt_id, uint8_t type);
/* Check MQTT puback, pubrec, pubrel or pubcomp packet
* This function may get called to check a supposed publish acknowledge packet in either one-way or
* The function checks for conformance to the MQTT protocol and returns 0 if the packet is valid.
* The function returns -EPROTO in case of protocol error or -EINVAL in case of a NULL pkt pointer.
*/
-int mqtt_check_publish_response_pkt(struct mqtt_publish_response_pkt* pkt, uint8_t type);
+int mqtt_check_publish_reply_pkt(struct mqtt_publish_reply_pkt* pkt, uint8_t type);
/* subsribe, unsubsribe, suback and unsuback packets */
#define MQTT_SUBSCRIBE_FLAG (0x01 << 1)
+#define MQTT_UNSUBSCRIBE_FLAG MQTT_SUBSCRIBE_FLAG
-/* MQTT subscribe packet */
-struct mqtt_subscribe_pkt {
+/* MQTT subscribe or unsubsribe packet */
+struct mqtt_sub_pkt {
uint16_t packet_id; /* Packet identifier */
uint8_t nb_topics; /* Number of topics in the topics table. Limited to 125 */
struct mqtt_topic* topics; /* Table of topics */
};
-/* MQTT subscribe response packet */
-struct mqtt_subscribe_response_pkt {
+/* Build MQTT subscribe packet
+ * This function must be called in order to create a subscribe MQTT packet used to
+ * subscibe on a topic (or multiple topics) in order to receive data published on this
+ * or these topics.
+ * We limit the number of subscriptions sent at once to 125 in order to get a fixed size
+ * subscription acknoledgement packet.
+ */
+int mqtt_pack_subscribe_pkt(const struct mqtt_sub_pkt* pkt, uint8_t* buf, uint32_t buf_size);
+
+/* Build MQTT unsubscribe packet
+ * This function must be called in order to create an unsubscribe MQTT packet used to unsubscibe
+ * from a topic (or multiple topics) in order to stop receiving data published on this or these
+ * topics.
+ */
+int mqtt_pack_unsubscribe_pkt(const struct mqtt_sub_pkt* pkt, uint8_t* buf, uint32_t buf_size);
+
+
+
+/* MQTT subscribe or unsubscribe reply packet */
+struct mqtt_sub_reply_pkt {
uint8_t control; /* Packet type */
- uint8_t rem_len; /* Remaining length : must be 0x03 in our "single subscription" case */
+ uint8_t rem_len; /* Remaining length : this is valid for up to 125 subscriptions sent at once ... */
uint16_t acked_pkt_id; /* Id of packet that is being acknowledged, in network endianness */
- uint8_t ret_code; /* equals accepted QoS or 0x80 in case of error */
} __attribute__ ((__packed__));
#define MQTT_SUBSCRIBE_FAILURE (0x80)
-
-/***************************************************************************** */
-/* unsubsribe and unsuback packets */
-
-/* NOTE : Same as subscription, I choosed not to implement the possibility to send multiple unsubscriptions
- * at once here in order to avoid unnecessary complexity of code and dynamic allocation of memory.
+/* Check MQTT suback packet
+ * This function may get called to check a supposed subscribe acknowledge packet.
+ * The function checks for conformance to the MQTT protocol and returns 0 if the packet is valid,
+ * regardless of the return codes received.
+ * len must be the length of the full packet received, which includes the mqtt_subscribe_reply_pkt
+ * structure and all the return codes received.
*/
+int mqtt_check_suback_reply_pkt(const struct mqtt_sub_reply_pkt* pkt, uint8_t len);
-#define MQTT_UNSUBSCRIBE_FLAG (0x01 << 1)
-
-/* MQTT unsubscribe packet */
-struct mqtt_unsubscribe_pkt {
- uint16_t packet_id; /* Packet identifier */
- char* topic;
-};
+/* Check MQTT unsuback packet
+ * This function may get called to check a supposed unsubscribe acknowledge packet.
+ * The function checks for conformance to the MQTT protocol and returns 0 if the packet is valid.
+ */
+int mqtt_check_unsuback_reply_pkt(const struct mqtt_sub_reply_pkt* pkt);
-/* MQTT unsubscribe response packet */
-struct mqtt_unsubscribe_response_pkt {
- uint8_t control; /* Packet type */
- uint8_t rem_len; /* Remaining length : must be 0x02 in our "single subscription" case */
- uint16_t acked_pkt_id; /* Id of packet that is being acknowledged, in network endianness */
-} __attribute__ ((__packed__));
/***************************************************************************** */
-/* MQTT ping request and response packet */
+/* MQTT ping request and reply packet */
struct mqtt_ping_pkt {
uint8_t control; /* Packet type : either (MQTT_CONTROL_PINGREQ << 4) or (MQTT_CONTROL_PINGRESP << 4) */
uint8_t rem_len; /* Remaining length : must be 0x00 */
} __attribute__ ((__packed__));
+/* Build MQTT ping packet
+ * This one is a fixed packet, easy.
+ */
+int mqtt_pack_ping_pkt(uint8_t* buf);
+
+/* Check MQTT ping reply packet */
+int mqtt_check_ping_reply_pkt(const struct mqtt_ping_pkt* pkt);
+
+
/***************************************************************************** */
/* MQTT disconnect */
* The function checks for conformance to the MQTT protocol and returns 0 if the packet is valid,
* regardless of the retrun code value.
*/
-int mqtt_check_connack_response_pkt(const struct mqtt_connack_response_pkt* pkt)
+int mqtt_check_connack_reply_pkt(const struct mqtt_connack_reply_pkt* pkt)
{
if (pkt == NULL) {
return -EINVAL;
/* Build MQTT puback, pubrec, pubrel or pubcomp packet, used in the publish acknowledge one-way or
* two-way hand-check mechanism.
*/
-int mqtt_pack_publish_response_pkt(uint8_t* buf, uint16_t acked_pkt_id, uint8_t type)
+int mqtt_pack_publish_reply_pkt(uint8_t* buf, uint16_t acked_pkt_id, uint8_t type)
{
uint16_t tmp_acked_pkt_id = 0;
if (buf == NULL) {
* This function may get called to check a supposed publish acknowledge packet in either one-way or
* two-way hand-check mechanism.
*/
-int mqtt_check_publish_response_pkt(struct mqtt_publish_response_pkt* pkt, uint8_t type)
+int mqtt_check_publish_reply_pkt(struct mqtt_publish_reply_pkt* pkt, uint8_t type)
{
uint8_t awaited_control = 0;
}
+/* Subscribe and unsubscribe packets only differ by the addition of the QoS byte after each topic. */
+static int mqtt_pack_sub_unsub(const struct mqtt_sub_pkt* pkt,
+ uint8_t* buf, uint32_t buf_size, uint8_t type)
+{
+ uint32_t remaining_length = 0;
+ uint32_t len = 0, i = 0;
+ uint16_t topic_len = 0;
+ uint16_t tmp_packet_id = 0;
+
+ if ((pkt == NULL) || (buf == NULL)) {
+ return -EINVAL;
+ }
+ if ((type != MQTT_CONTROL_SUBSCRIBE) && (type != MQTT_CONTROL_UNSUBSCRIBE)) {
+ return -EINVAL;
+ }
+ /* Check packet consistency */
+ if ((pkt->nb_topics == 0) || (pkt->topics == NULL)) {
+ return -ENODATA;
+ }
+ /* Limit the number of topics to 125 in orer to keep the variable length field on one byte in
+ * the subscribe acknowledge packet. */
+ if (pkt->nb_topics > 125) {
+ return -EINVAL;
+ }
+ /* Compute message size
+ * Packet ID is 2 bytes long. */
+ remaining_length = 2;
+ for (i = 0; i < pkt->nb_topics; i++) {
+ if (pkt->topics[i].name == NULL) {
+ return -EINVAL;
+ }
+ topic_len = strlen(pkt->topics[i].name);
+ /* Update packet payload size. */
+ remaining_length += topic_len + 2;
+ if (type == MQTT_CONTROL_SUBSCRIBE) {
+ /* Add one for the associated QoS for each topic */
+ remaining_length += 1;
+ }
+ }
+
+ /* Build MQTT Publish packet */
+ /* Fixed header */
+ len = mqtt_pack_fixed_header(buf, type, MQTT_SUBSCRIBE_FLAG, remaining_length);
+ if (remaining_length + len > buf_size) {
+ return -E2BIG;
+ }
+ /* Packet ID */
+ tmp_packet_id = htons(pkt->packet_id);
+ memcpy((buf + len), &tmp_packet_id, 2);
+ len += 2;
+ /* Topic(s) */
+ for (i = 0; i < pkt->nb_topics; i++) {
+ topic_len = strlen(pkt->topics[i].name);
+ len += mqtt_pack_str((buf + len), pkt->topics[i].name, topic_len);
+ if (type == MQTT_CONTROL_SUBSCRIBE) {
+ /* Add the associated QoS */
+ buf[len++] = pkt->topics[i].QoS & 0x03;
+ }
+ }
+
+ return len;
+}
+
+/***************************************************************************** */
+/* Build MQTT subscribe packet
+ * This function must be called in order to create a subscribe MQTT packet used to
+ * subscibe on a topic (or multiple topics) in order to receive data published on this
+ * or these topics.
+ * We limit the number of subscriptions sent at once to 125 in order to get a fixed size
+ * subscription acknoledgement packet.
+ */
+int mqtt_pack_subscribe_pkt(const struct mqtt_sub_pkt* pkt, uint8_t* buf, uint32_t buf_size)
+{
+ return mqtt_pack_sub_unsub(pkt, buf, buf_size, MQTT_CONTROL_SUBSCRIBE);
+}
+
+/***************************************************************************** */
+/* Build MQTT unsubscribe packet
+ * This function must be called in order to create an unsubscribe MQTT packet used to unsubscibe
+ * from a topic (or multiple topics) in order to stop receiving data published on this or these
+ * topics.
+ */
+int mqtt_pack_unsubscribe_pkt(const struct mqtt_sub_pkt* pkt, uint8_t* buf, uint32_t buf_size)
+{
+ return mqtt_pack_sub_unsub(pkt, buf, buf_size, MQTT_CONTROL_UNSUBSCRIBE);
+}
+
+
+/***************************************************************************** */
+/* Check MQTT suback packet
+ * This function may get called to check a supposed subscribe acknowledge packet.
+ * The function checks for conformance to the MQTT protocol and returns 0 if the packet is valid,
+ * regardless of the return codes received.
+ * len must be the length of the full packet received, which includes the mqtt_subscribe_reply_pkt
+ * structure and all the return codes received.
+ */
+int mqtt_check_suback_reply_pkt(const struct mqtt_sub_reply_pkt* pkt, uint8_t len)
+{
+ int i = 0;
+ uint8_t* ret_codes = NULL;
+ if (pkt == NULL) {
+ return -EINVAL;
+ }
+ if (pkt->control != (MQTT_CONTROL_SUBACK << 4)) {
+ return -EPROTO;
+ }
+ if ((pkt->rem_len > 127) || (pkt->rem_len != (len - 2))) {
+ return -EPROTO;
+ }
+ ret_codes = (uint8_t*)pkt + 4;
+ for (i = 0; i < (pkt->rem_len - 2); i++) {
+ if ((ret_codes[i] != 0x80) && (ret_codes[i] > MQTT_QoS_2)) {
+ return -EREMOTEIO;
+ }
+ }
+ /* Valid packet */
+ return 0;
+}
+
+
+/***************************************************************************** */
+/* Check MQTT unsuback packet
+ * This function may get called to check a supposed unsubscribe acknowledge packet.
+ * The function checks for conformance to the MQTT protocol and returns 0 if the packet is valid.
+ */
+int mqtt_check_unsuback_reply_pkt(const struct mqtt_sub_reply_pkt* pkt)
+{
+ if (pkt == NULL) {
+ return -EINVAL;
+ }
+ if (pkt->control != (MQTT_CONTROL_UNSUBACK << 4)) {
+ return -EPROTO;
+ }
+ if (pkt->rem_len != 2) {
+ return -EPROTO;
+ }
+ /* Valid packet */
+ return 0;
+}
+
+
+/***************************************************************************** */
+/* Build MQTT ping packet
+ * This one is a fixed packet, easy.
+ */
+int mqtt_pack_ping_pkt(uint8_t* buf)
+{
+ struct mqtt_ping_pkt pkt = {
+ .control = (MQTT_CONTROL_PINGREQ << 4),
+ .rem_len = 0,
+ };
+ if (buf == NULL) {
+ return -EINVAL;
+ }
+ memcpy(buf, &pkt, sizeof(struct mqtt_ping_pkt));
+ return sizeof(struct mqtt_ping_pkt);
+}
+
+
+/***************************************************************************** */
+/* Check MQTT ping reply packet */
+int mqtt_check_ping_reply_pkt(const struct mqtt_ping_pkt* pkt)
+{
+ if (pkt == NULL) {
+ return -EINVAL;
+ }
+ if (pkt->control != (MQTT_CONTROL_PINGRESP << 4)) {
+ return -EPROTO;
+ }
+ if (pkt->rem_len != 0) {
+ return -EPROTO;
+ }
+ return 0;
+}
+
+
+/***************************************************************************** */
+/* Build MQTT disconnect packet
+ * This one is a fixed packet, easy.
+ */
+int mqtt_pack_disconnect_pkt(uint8_t* buf)
+{
+ struct mqtt_disconnect_pkt pkt = {
+ .control = (MQTT_CONTROL_DISCONNECT << 4),
+ .rem_len = 0,
+ };
+ if (buf == NULL) {
+ return -EINVAL;
+ }
+ memcpy(buf, &pkt, sizeof(struct mqtt_disconnect_pkt));
+ return sizeof(struct mqtt_disconnect_pkt);
+}