Contiki-NG
Loading...
Searching...
No Matches
mqtt-prop.c
1/*
2 * Copyright (c) 2020, Alexandru-Ioan Pop - https://alexandruioan.me
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30/*---------------------------------------------------------------------------*/
31#include "contiki.h"
32#include "contiki-lib.h"
33#include "lib/memb.h"
34
35#include "mqtt.h"
36#include "mqtt-prop.h"
37
38#include <stdlib.h>
39/*---------------------------------------------------------------------------*/
40#if MQTT_PROP_USE_MEMB
41MEMB(prop_lists_mem, struct mqtt_prop_list, MQTT_PROP_MAX_OUT_PROP_LISTS);
42MEMB(props_mem, struct mqtt_prop_out_property, MQTT_PROP_MAX_OUT_PROPS);
43#endif
44/*----------------------------------------------------------------------------*/
45void
46mqtt_props_init()
47{
48#if MQTT_PROP_USE_MEMB
49 memb_init(&props_mem);
50 memb_init(&prop_lists_mem);
51#endif
52}
53/*----------------------------------------------------------------------------*/
54static void
55encode_prop_fixed_len_int(struct mqtt_prop_out_property **prop_out,
56 int val, uint8_t len)
57{
58 int8_t i;
59
60 DBG("MQTT - Creating %d-byte int property %i\n", len, val);
61
62 if(len > MQTT_PROP_MAX_PROP_LENGTH) {
63 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
64 return;
65 }
66
67 for(i = len - 1; i >= 0; i--) {
68 (*prop_out)->val[i] = val & 0x00FF;
69 val = val >> 8;
70 }
71
72 (*prop_out)->property_len = len;
73}
74/*---------------------------------------------------------------------------*/
75static void
76encode_prop_utf8(struct mqtt_prop_out_property **prop_out,
77 const char *str)
78{
79 int str_len;
80
81 DBG("MQTT - Encoding UTF-8 Property %s\n", str);
82 str_len = strlen(str);
83
84 /* 2 bytes are needed for each string to encode its length */
85 if((str_len + 2) > MQTT_PROP_MAX_PROP_LENGTH) {
86 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
87 return;
88 }
89
90 (*prop_out)->val[0] = str_len >> 8;
91 (*prop_out)->val[1] = str_len & 0x00FF;
92 memcpy((*prop_out)->val + 2, str, str_len);
93
94 (*prop_out)->property_len = str_len + 2;
95}
96/*---------------------------------------------------------------------------*/
97static void
98encode_prop_binary(struct mqtt_prop_out_property **prop_out,
99 const char *data, int data_len)
100{
101 DBG("MQTT - Encoding Binary Data (%d bytes)\n", data_len);
102
103 if((data_len + 2) > MQTT_PROP_MAX_PROP_LENGTH) {
104 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
105 return;
106 }
107
108 (*prop_out)->val[0] = data_len >> 8;
109 (*prop_out)->val[1] = data_len & 0x00FF;
110 memcpy((*prop_out)->val + 2, data, data_len);
111
112 (*prop_out)->property_len = data_len + 2;
113}
114/*---------------------------------------------------------------------------*/
115static void
116encode_prop_var_byte_int(struct mqtt_prop_out_property **prop_out,
117 int val)
118{
119 uint8_t id_len;
120
121 DBG("MQTT - Encoding Variable Byte Integer %d\n", val);
122
123 mqtt_encode_var_byte_int(
124 (*prop_out)->val,
125 &id_len,
126 val);
127
128 (*prop_out)->property_len = id_len;
129}
130/*---------------------------------------------------------------------------*/
131uint32_t
132mqtt_prop_encode(struct mqtt_prop_out_property **prop_out, mqtt_vhdr_prop_t prop_id,
133 va_list args)
134{
135 DBG("MQTT - Creating property with ID %i\n", prop_id);
136
137 if(!(*prop_out)) {
138 DBG("MQTT - Error, property target NULL!\n");
139 return 0;
140 }
141
142 (*prop_out)->property_len = 0;
143 (*prop_out)->id = prop_id;
144
145 /* Decode varargs and create encoded property value for selected type */
146 switch(prop_id) {
147 case MQTT_VHDR_PROP_PAYLOAD_FMT_IND:
148 case MQTT_VHDR_PROP_REQ_PROBLEM_INFO:
149 case MQTT_VHDR_PROP_REQ_RESP_INFO: {
150 int val;
151
152 val = va_arg(args, int);
153 encode_prop_fixed_len_int(prop_out, val, 1);
154
155 break;
156 }
157 case MQTT_VHDR_PROP_RECEIVE_MAX:
158 case MQTT_VHDR_PROP_TOPIC_ALIAS_MAX:
159 case MQTT_VHDR_PROP_TOPIC_ALIAS: {
160 int val;
161
162 val = va_arg(args, int);
163 encode_prop_fixed_len_int(prop_out, val, 2);
164
165 break;
166 }
167 case MQTT_VHDR_PROP_MSG_EXP_INT:
168 case MQTT_VHDR_PROP_SESS_EXP_INT:
169 case MQTT_VHDR_PROP_WILL_DELAY_INT:
170 case MQTT_VHDR_PROP_MAX_PKT_SZ: {
171 int val;
172
173 val = va_arg(args, int);
174 encode_prop_fixed_len_int(prop_out, val, 4);
175
176 break;
177 }
178 case MQTT_VHDR_PROP_CONTENT_TYPE:
179 case MQTT_VHDR_PROP_RESP_TOPIC:
180 case MQTT_VHDR_PROP_AUTH_METHOD: {
181 const char *str;
182
183 str = va_arg(args, const char *);
184 encode_prop_utf8(prop_out, str);
185
186 break;
187 }
188 case MQTT_VHDR_PROP_CORRELATION_DATA:
189 case MQTT_VHDR_PROP_AUTH_DATA: {
190 const char *data;
191 int data_len;
192
193 data = va_arg(args, const char *);
194 data_len = va_arg(args, int);
195
196 encode_prop_binary(prop_out, data, data_len);
197
198 break;
199 }
200 case MQTT_VHDR_PROP_SUB_ID: {
201 int val;
202
203 val = va_arg(args, int);
204
205 encode_prop_var_byte_int(prop_out, val);
206
207 break;
208 }
209 case MQTT_VHDR_PROP_USER_PROP: {
210 const char *name;
211 const char *value;
212 uint16_t name_len;
213 uint16_t val_len;
214
215 name = va_arg(args, const char *);
216 value = va_arg(args, const char *);
217
218 name_len = strlen(name);
219 val_len = strlen(value);
220
221 DBG("MQTT - Encoding User Property '%s: %s'\n", name, value);
222
223 /* 2 bytes are needed for each string to encode its length */
224 if((name_len + val_len + 4) > MQTT_PROP_MAX_PROP_LENGTH) {
225 DBG("MQTT - Error, property '%i' too long (max %i bytes)", prop_id, MQTT_PROP_MAX_PROP_LENGTH);
226 return 0;
227 }
228
229 (*prop_out)->val[0] = name_len >> 8;
230 (*prop_out)->val[1] = name_len & 0x00FF;
231 memcpy((*prop_out)->val + 2, name, strlen(name));
232 (*prop_out)->val[name_len + 2] = val_len >> 8;
233 (*prop_out)->val[name_len + 3] = val_len & 0x00FF;
234 memcpy((*prop_out)->val + name_len + 4, value, strlen(value));
235
236 (*prop_out)->property_len = strlen(name) + strlen(value) + 4;
237 break;
238 }
239 default:
240 DBG("MQTT - Error, no such property '%i'\n", prop_id);
241 *prop_out = NULL;
242 return 0;
243 }
244
245 DBG("MQTT - Property encoded length %i\n", (*prop_out)->property_len);
246
247 return (*prop_out)->property_len;
248}
249/*---------------------------------------------------------------------------*/
250#if MQTT_5
251void
252mqtt_prop_decode_input_props(struct mqtt_connection *conn)
253{
254 uint8_t prop_len_bytes;
255
256 DBG("MQTT - Parsing input properties\n");
257
258 /* All but PINGREQ and PINGRESP may contain a set of properties in the VHDR */
259 if(((conn->in_packet.fhdr & 0xF0) == MQTT_FHDR_MSG_TYPE_PINGREQ) ||
260 ((conn->in_packet.fhdr & 0xF0) == MQTT_FHDR_MSG_TYPE_PINGRESP)) {
261 return;
262 }
263
264 DBG("MQTT - Getting length\n");
265
266 prop_len_bytes =
267 mqtt_decode_var_byte_int(conn->in_packet.payload_start,
268 conn->in_packet.remaining_length - (conn->in_packet.payload_start - conn->in_packet.payload),
269 NULL, NULL, &conn->in_packet.properties_len);
270
271 if(prop_len_bytes == 0) {
272 DBG("MQTT - Error decoding input properties (out of bounds)\n");
273 return;
274 }
275
276 DBG("MQTT - Received %i VBI property bytes\n", prop_len_bytes);
277 DBG("MQTT - Input properties length %i\n", conn->in_packet.properties_len);
278
279 /* Total property length = number of bytes to encode length + length of
280 * properties themselves
281 */
282 conn->in_packet.properties_enc_len = prop_len_bytes;
283 /* Actual properties start after property length VBI */
284 conn->in_packet.props_start = conn->in_packet.payload_start + prop_len_bytes;
285 conn->in_packet.payload_start += prop_len_bytes;
286 conn->in_packet.curr_props_pos = conn->in_packet.props_start;
287
288 DBG("MQTT - First byte of first prop %i\n", *conn->in_packet.curr_props_pos);
289
290 conn->in_packet.has_props = 1;
291}
292#endif
293/*---------------------------------------------------------------------------*/
294static uint32_t
295decode_prop_utf8(struct mqtt_connection *conn,
296 uint8_t *buf_in,
297 uint8_t *data)
298{
299 uint32_t len;
300
301 len = (buf_in[0] << 8) + buf_in[1];
302
303 DBG("MQTT - Decoding %d-char UTF8 string property\n", len);
304
305 /* Include NULL terminator in destination */
306 if((len + MQTT_STRING_LEN_SIZE + 1) > MQTT_PROP_MAX_PROP_LENGTH) {
307 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
308 return 0;
309 }
310
311 memcpy(data, buf_in, len + MQTT_STRING_LEN_SIZE);
312 data[len + MQTT_STRING_LEN_SIZE] = '\0';
313
314 /* Length of string + 2 bytes for length */
315 return len + MQTT_STRING_LEN_SIZE;
316}
317/*---------------------------------------------------------------------------*/
318static uint32_t
319decode_prop_fixed_len_int(struct mqtt_connection *conn,
320 uint8_t *buf_in, int len,
321 uint8_t *data)
322{
323 int8_t i;
324 uint32_t *data_out;
325
326 DBG("MQTT - Decoding %d-byte int property\n", len);
327
328 if(len > MQTT_PROP_MAX_PROP_LENGTH) {
329 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
330 return 0;
331 }
332
333 /* All integer input properties will be returned as uint32_t */
334 memset(data, 0, 4);
335
336 data_out = (uint32_t *)data;
337
338 for(i = 0; i < 4; i++) {
339 *data_out = *data_out << 8;
340
341 if(i < len) {
342 *data_out += buf_in[i];
343 }
344 }
345
346 return len;
347}
348/*---------------------------------------------------------------------------*/
349static uint32_t
350decode_prop_vbi(struct mqtt_connection *conn,
351 uint8_t *buf_in,
352 uint8_t *data)
353{
354 uint8_t prop_len_bytes;
355
356 DBG("MQTT - Decoding Variable Byte Integer property\n");
357
358 /* All integer input properties will be returned as uint32_t */
359 memset(data, 0, 4);
360
361 prop_len_bytes =
362 mqtt_decode_var_byte_int(buf_in, 4, NULL, NULL, (uint16_t *)data);
363
364 if(prop_len_bytes == 0) {
365 DBG("MQTT - Error decoding Variable Byte Integer\n");
366 return 0;
367 }
368
369 if(prop_len_bytes > MQTT_PROP_MAX_PROP_LENGTH) {
370 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
371 return 0;
372 }
373
374 return prop_len_bytes;
375}
376/*---------------------------------------------------------------------------*/
377static uint32_t
378decode_prop_binary_data(struct mqtt_connection *conn,
379 uint8_t *buf_in,
380 uint8_t *data)
381{
382 uint8_t data_len;
383
384 DBG("MQTT - Decoding Binary Data property\n");
385
386 data_len = (buf_in[0] << 8) + buf_in[1];
387
388 if(data_len == 0) {
389 DBG("MQTT - Error decoding Binary Data property length\n");
390 return 0;
391 }
392
393 if((data_len + 2) > MQTT_PROP_MAX_PROP_LENGTH) {
394 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
395 return 0;
396 }
397
398 memcpy(data, buf_in, data_len + 2);
399
400 return data_len + 2;
401}
402/*---------------------------------------------------------------------------*/
403static uint32_t
404decode_prop_utf8_pair(struct mqtt_connection *conn,
405 uint8_t *buf_in,
406 uint8_t *data)
407{
408 uint32_t len1;
409 uint32_t len2;
410 uint32_t total_len;
411
412 len1 = (buf_in[0] << 8) + buf_in[1];
413 len2 = (buf_in[len1 + MQTT_STRING_LEN_SIZE] << 8) + buf_in[len1 + MQTT_STRING_LEN_SIZE + 1];
414 total_len = len1 + len2;
415
416 DBG("MQTT - Decoding %d-char UTF8 string pair property (%i + %i)\n", total_len, len1, len2);
417
418 if((total_len + 2 * MQTT_STRING_LEN_SIZE) > MQTT_PROP_MAX_PROP_LENGTH) {
419 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
420 return 0;
421 }
422
423 memcpy(data, buf_in, total_len + 2 * MQTT_STRING_LEN_SIZE);
424
425 /* Length of string + 2 bytes for length */
426 return total_len + 2 * MQTT_STRING_LEN_SIZE;
427}
428/*---------------------------------------------------------------------------*/
429uint32_t
430parse_prop(struct mqtt_connection *conn,
431 mqtt_vhdr_prop_t prop_id, uint8_t *buf_in, uint8_t *data)
432{
433 switch(prop_id) {
434 case MQTT_VHDR_PROP_PAYLOAD_FMT_IND:
435 case MQTT_VHDR_PROP_REQ_PROBLEM_INFO:
436 case MQTT_VHDR_PROP_REQ_RESP_INFO:
437 case MQTT_VHDR_PROP_MAX_QOS:
438 case MQTT_VHDR_PROP_RETAIN_AVAIL:
439 case MQTT_VHDR_PROP_WILD_SUB_AVAIL:
440 case MQTT_VHDR_PROP_SUB_ID_AVAIL:
441 case MQTT_VHDR_PROP_SHARED_SUB_AVAIL: {
442 return decode_prop_fixed_len_int(conn, buf_in, 1, data);
443 }
444 case MQTT_VHDR_PROP_RECEIVE_MAX:
445 case MQTT_VHDR_PROP_TOPIC_ALIAS_MAX:
446 case MQTT_VHDR_PROP_SERVER_KEEP_ALIVE: {
447 return decode_prop_fixed_len_int(conn, buf_in, 2, data);
448 }
449 case MQTT_VHDR_PROP_MSG_EXP_INT:
450 case MQTT_VHDR_PROP_SESS_EXP_INT:
451 case MQTT_VHDR_PROP_WILL_DELAY_INT:
452 case MQTT_VHDR_PROP_MAX_PKT_SZ: {
453 return decode_prop_fixed_len_int(conn, buf_in, 4, data);
454 }
455 case MQTT_VHDR_PROP_CONTENT_TYPE:
456 case MQTT_VHDR_PROP_RESP_TOPIC:
457 case MQTT_VHDR_PROP_AUTH_METHOD:
458 case MQTT_VHDR_PROP_ASSIGNED_CLIENT_ID:
459 case MQTT_VHDR_PROP_RESP_INFO:
460 case MQTT_VHDR_PROP_SERVER_REFERENCE:
461 case MQTT_VHDR_PROP_REASON_STRING: {
462 return decode_prop_utf8(conn, buf_in, data);
463 }
464 case MQTT_VHDR_PROP_CORRELATION_DATA:
465 case MQTT_VHDR_PROP_AUTH_DATA: {
466 return decode_prop_binary_data(conn, buf_in, data);
467 }
468 case MQTT_VHDR_PROP_SUB_ID: {
469 return decode_prop_vbi(conn, buf_in, data);
470 }
471 case MQTT_VHDR_PROP_USER_PROP: {
472 return decode_prop_utf8_pair(conn, buf_in, data);
473 }
474 default:
475 DBG("MQTT - Error, no such property '%i'", prop_id);
476 return 0;
477 }
478
479 return 0;
480}
481/*---------------------------------------------------------------------------*/
482#if MQTT_5
483uint32_t
484mqtt_get_next_in_prop(struct mqtt_connection *conn,
485 mqtt_vhdr_prop_t *prop_id, uint8_t *data)
486{
487 uint32_t prop_len;
488 uint8_t prop_id_len_bytes;
489 uint16_t prop_id_decode;
490
491 if(!conn->in_packet.has_props) {
492 DBG("MQTT - Message has no input properties");
493 return 0;
494 }
495
496 DBG("MQTT - Curr prop pos %i; len %i; byte %i\n", (conn->in_packet.curr_props_pos - conn->in_packet.props_start),
497 conn->in_packet.properties_len,
498 *conn->in_packet.curr_props_pos);
499
500 if((conn->in_packet.curr_props_pos - conn->in_packet.props_start)
501 >= conn->in_packet.properties_len) {
502 DBG("MQTT - Message has no more input properties\n");
503 return 0;
504 }
505
506 prop_id_len_bytes =
507 mqtt_decode_var_byte_int(conn->in_packet.curr_props_pos,
508 conn->in_packet.properties_len - (conn->in_packet.curr_props_pos - conn->in_packet.props_start),
509 NULL, NULL, (uint16_t *)&prop_id_decode);
510
511 *prop_id = prop_id_decode;
512
513 DBG("MQTT - Decoded property ID %i (encoded using %i bytes)\n", *prop_id, prop_id_len_bytes);
514
515 prop_len = parse_prop(conn, *prop_id, conn->in_packet.curr_props_pos + 1, data);
516
517 DBG("MQTT - Decoded property len %i bytes\n", prop_len);
518
519 conn->in_packet.curr_props_pos += prop_id_len_bytes + prop_len;
520
521 return prop_len;
522}
523/*---------------------------------------------------------------------------*/
524void
525mqtt_prop_parse_connack_props(struct mqtt_connection *conn)
526{
527 uint32_t prop_len;
528 mqtt_vhdr_prop_t prop_id;
529 uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
530 uint32_t val_int;
531
532 DBG("MQTT - Parsing CONNACK properties for server capabilities\n");
533
534 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
535 while(prop_len) {
536 switch(prop_id) {
537 case MQTT_VHDR_PROP_RETAIN_AVAIL: {
538 val_int = (uint32_t)*data;
539 if(val_int == 0) {
540 conn->srv_feature_en &= ~MQTT_CAP_RETAIN_AVAIL;
541 }
542 break;
543 }
544 case MQTT_VHDR_PROP_WILD_SUB_AVAIL: {
545 val_int = (uint32_t)*data;
546 if(val_int == 0) {
547 conn->srv_feature_en &= ~MQTT_CAP_WILD_SUB_AVAIL;
548 }
549 break;
550 }
551 case MQTT_VHDR_PROP_SUB_ID_AVAIL: {
552 val_int = (uint32_t)*data;
553 if(val_int == 0) {
554 conn->srv_feature_en &= ~MQTT_CAP_SUB_ID_AVAIL;
555 }
556 break;
557 }
558 case MQTT_VHDR_PROP_SHARED_SUB_AVAIL: {
559 val_int = (uint32_t)*data;
560 if(val_int == 0) {
561 conn->srv_feature_en &= ~MQTT_CAP_SHARED_SUB_AVAIL;
562 }
563 break;
564 }
565 default:
566 DBG("MQTT - Error, unexpected CONNACK property '%i'", prop_id);
567 return;
568 }
569
570 prop_id = 0;
571 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
572 }
573}
574/*---------------------------------------------------------------------------*/
575void
576mqtt_prop_parse_auth_props(struct mqtt_connection *conn, struct mqtt_prop_auth_event *event)
577{
578 uint32_t prop_len;
579 mqtt_vhdr_prop_t prop_id;
580 uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
581
582 DBG("MQTT - Parsing CONNACK properties for server capabilities\n");
583
584 event->auth_data.len = 0;
585 event->auth_method.length = 0;
586
587 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
588 while(prop_len) {
589 switch(prop_id) {
590 case MQTT_VHDR_PROP_AUTH_DATA: {
591 event->auth_data.len = prop_len - 2; /* 2 bytes are used to encode len */
592 memcpy(event->auth_data.data, data, prop_len - 2);
593 break;
594 }
595 case MQTT_VHDR_PROP_AUTH_METHOD: {
596 event->auth_method.length = prop_len - 2; /* 2 bytes are used to encode len */
597 memcpy(event->auth_method.string, data, prop_len - 2);
598 break;
599 }
600 default:
601 DBG("MQTT - Unhandled AUTH property '%i'", prop_id);
602 return;
603 }
604
605 prop_id = 0;
606 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
607 }
608}
609/*---------------------------------------------------------------------------*/
610void
611mqtt_prop_print_input_props(struct mqtt_connection *conn)
612{
613 uint32_t prop_len;
614 mqtt_vhdr_prop_t prop_id;
615 uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
616 uint32_t i;
617
618 DBG("MQTT - Printing all input properties\n");
619
620 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
621 while(prop_len) {
622 DBG("MQTT - Property ID %i, length %i\n", prop_id, prop_len);
623
624 switch(prop_id) {
625 case MQTT_VHDR_PROP_PAYLOAD_FMT_IND:
626 case MQTT_VHDR_PROP_REQ_PROBLEM_INFO:
627 case MQTT_VHDR_PROP_REQ_RESP_INFO:
628 case MQTT_VHDR_PROP_MSG_EXP_INT:
629 case MQTT_VHDR_PROP_SESS_EXP_INT:
630 case MQTT_VHDR_PROP_WILL_DELAY_INT:
631 case MQTT_VHDR_PROP_MAX_PKT_SZ:
632 case MQTT_VHDR_PROP_RECEIVE_MAX:
633 case MQTT_VHDR_PROP_TOPIC_ALIAS_MAX:
634 case MQTT_VHDR_PROP_SUB_ID: {
635 DBG("MQTT - Decoded property value '%i'\n", (uint32_t)*data);
636 break;
637 }
638 case MQTT_VHDR_PROP_CONTENT_TYPE:
639 case MQTT_VHDR_PROP_RESP_TOPIC:
640 case MQTT_VHDR_PROP_AUTH_METHOD: {
641 DBG("MQTT - Decoded property value ");
642 DBG("(%i %i) %s", data[0], data[1], data + MQTT_STRING_LEN_SIZE);
643 DBG("\n");
644 break;
645 }
646 case MQTT_VHDR_PROP_CORRELATION_DATA:
647 case MQTT_VHDR_PROP_AUTH_DATA: {
648 DBG("MQTT - Decoded property value (%i %i) ", data[0], data[1]);
649 for(i = 2; i < prop_len; i++) {
650 DBG("%x ", data[i]);
651 }
652 DBG("\n");
653 break;
654 }
655 case MQTT_VHDR_PROP_USER_PROP: {
656#if DEBUG_MQTT
657 uint32_t len1;
658 uint32_t len2;
659
660 len1 = (data[0] << 8) + data[1];
661 len2 = (data[len1 + MQTT_STRING_LEN_SIZE] << 8) + data[len1 + MQTT_STRING_LEN_SIZE + 1];
662#endif
663 DBG("MQTT - Decoded property value [(%i %i) %.*s, (%i %i) %.*s]",
664 data[0], data[1], len1, data + MQTT_STRING_LEN_SIZE,
665 data[len1 + MQTT_STRING_LEN_SIZE], data[len1 + MQTT_STRING_LEN_SIZE + 1], len2, data + len1 + 2 * MQTT_STRING_LEN_SIZE);
666 DBG("\n");
667 break;
668 }
669 default:
670 DBG("MQTT - Error, no such property '%i'\n", prop_id);
671 return;
672 }
673
674 prop_id = 0;
675 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
676 }
677}
678/*
679 * Functions to manipulate property lists
680 */
681/*----------------------------------------------------------------------------*/
682/* Creates a property list for the requested message type */
683void
684mqtt_prop_create_list(struct mqtt_prop_list **prop_list_out)
685{
686 DBG("MQTT - Creating Property List\n");
687
688#if MQTT_PROP_USE_MEMB
689 *prop_list_out = memb_alloc(&prop_lists_mem);
690#endif
691
692 if(!(*prop_list_out)) {
693 DBG("MQTT - Error, allocated too many property lists (max %i)\n", MQTT_PROP_MAX_OUT_PROP_LISTS);
694 return;
695 }
696
697 DBG("MQTT - Allocated Property list\n");
698
699 LIST_STRUCT_INIT(*prop_list_out, props);
700
701 DBG("MQTT - mem %p prop_list\n", *prop_list_out);
702
703 (*prop_list_out)->properties_len = 0;
704 (*prop_list_out)->properties_len_enc_bytes = 1; /* 1 byte needed for len = 0 */
705}
706/*----------------------------------------------------------------------------*/
707/* Prints all properties in the given property list (debug)
708 * If ID == MQTT_VHDR_PROP_ANY, prints all properties, otherwise it filters them
709 * by property ID
710 */
711void
712mqtt_prop_print_list(struct mqtt_prop_list *prop_list, mqtt_vhdr_prop_t prop_id)
713{
714 struct mqtt_prop_out_property *prop;
715
716 if(prop_list == NULL || prop_list->props == NULL) {
717 DBG("MQTT - Prop list empty\n");
718 } else {
719 prop = (struct mqtt_prop_out_property *)list_head(prop_list->props);
720
721 do {
722 if(prop != NULL && (prop->id == prop_id || prop_id == MQTT_VHDR_PROP_ANY)) {
723 DBG("Property %p ID %i len %i\n", prop, prop->id, prop->property_len);
724 }
725 prop = (struct mqtt_prop_out_property *)list_item_next(prop);
726 } while(prop != NULL);
727 }
728}
729/*---------------------------------------------------------------------------*/
730uint8_t
731mqtt_prop_register_internal(struct mqtt_prop_list **prop_list,
732#if !MQTT_PROP_USE_MEMB
733 struct mqtt_prop_out_property *prop,
734#endif
735 mqtt_msg_type_t msg,
736 mqtt_vhdr_prop_t prop_id,
737 struct mqtt_prop_out_property **prop_out, ...)
738{
739 /* check that the property is compatible with the message? */
740 if(!prop_list) {
741 DBG("MQTT - Error encoding prop %i on msg %i; list NULL\n", prop_id, msg);
742 return 1;
743 }
744
745 DBG("MQTT - prop list %p\n", *prop_list);
746 DBG("MQTT - prop list->list %p\n", (*prop_list)->props);
747
748#if MQTT_PROP_USE_MEMB
749 struct mqtt_prop_out_property *prop = memb_alloc(&props_mem);
750#endif
751
752 if(!prop) {
753 DBG("MQTT - Error, allocated too many properties (max %i)\n", MQTT_PROP_MAX_OUT_PROPS);
754 prop_out = NULL;
755 return 1;
756 }
757
758 DBG("MQTT - Allocated prop %p\n", prop);
759
760 va_list args;
761 va_start(args, prop_out);
762 uint32_t prop_len = mqtt_prop_encode(&prop, prop_id, args);
763
764 if(prop) {
765 DBG("MQTT - Adding prop %p to prop_list %p\n", prop, *prop_list);
766 list_add((*prop_list)->props, prop);
767 (*prop_list)->properties_len += 1; /* Property ID */
768 (*prop_list)->properties_len += prop_len;
769 mqtt_encode_var_byte_int(
770 (*prop_list)->properties_len_enc,
771 &((*prop_list)->properties_len_enc_bytes),
772 (*prop_list)->properties_len);
773 DBG("MQTT - New prop_list length %i\n", (*prop_list)->properties_len);
774 } else {
775 DBG("MQTT - Error encoding prop %i on msg %i\n", prop_id, msg);
776#if MQTT_PROP_USE_MEMB
777 memb_free(&props_mem, prop);
778#endif
779 va_end(args);
780 prop_out = NULL;
781 return 1;
782 }
783
784 if(prop_out) {
785 *prop_out = prop;
786 }
787 va_end(args);
788 return 0;
789}
790/*----------------------------------------------------------------------------*/
791/* Remove one property from list and free its memory */
792uint8_t
793mqtt_remove_prop(struct mqtt_prop_list **prop_list,
794 struct mqtt_prop_out_property *prop)
795{
796 if(prop != NULL && prop_list != NULL && list_contains((*prop_list)->props, prop)) {
797 DBG("MQTT - Removing property %p from list %p\n", prop, *prop_list);
798
799 /* Remove from list */
800 list_remove((*prop_list)->props, prop);
801
802 /* Fix the property list length */
803 (*prop_list)->properties_len -= prop->property_len;
804 (*prop_list)->properties_len -= 1; /* Property ID */
805
806 mqtt_encode_var_byte_int(
807 (*prop_list)->properties_len_enc,
808 &((*prop_list)->properties_len_enc_bytes),
809 (*prop_list)->properties_len);
810
811 /* Free memory */
812#if MQTT_PROP_USE_MEMB
813 memb_free(&props_mem, prop);
814#endif
815 return 0;
816 } else {
817 DBG("MQTT - Cannot remove property\n");
818 return 1;
819 }
820}
821/* Remove & frees all properties in the list */
822void
823mqtt_prop_clear_list(struct mqtt_prop_list **prop_list)
824{
825 struct mqtt_prop_out_property *prop;
826
827 DBG("MQTT - Clearing Property List\n");
828
829 if(prop_list == NULL || list_length((*prop_list)->props) == 0) {
830 DBG("MQTT - Prop list empty\n");
831 return;
832 } else {
833 prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
834
835 do {
836 if(prop != NULL) {
837 (void)mqtt_remove_prop(prop_list, prop);
838 }
839 prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
840 } while(prop != NULL);
841 }
842
843 LIST_STRUCT_INIT(*prop_list, props);
844
845 if((*prop_list)->properties_len != 0 || (*prop_list)->properties_len_enc_bytes != 1) {
846 DBG("MQTT - Something went wrong when clearing property list!\n");
847 }
848}
849#endif
static void * list_item_next(const void *item)
Get the next item following this item.
Definition list.h:294
int list_length(const_list_t list)
Get the length of a list.
Definition list.c:160
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition list.c:71
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition list.c:134
bool list_contains(const_list_t list, const void *item)
Check if the list contains an item.
Definition list.c:185
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition list.h:126
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition list.h:169
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition memb.c:78
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition memb.c:59
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition memb.c:52
#define MEMB(name, structure, num)
Declare a memory block.
Definition memb.h:91
Memory block allocation routines.
Header file for the Contiki MQTT engine.