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, uint32_t buf_in_len,
297 uint8_t *data)
298{
299 uint32_t len;
300
301 /* The 2-byte length prefix must be present in the received input */
302 if(buf_in_len < MQTT_STRING_LEN_SIZE) {
303 DBG("MQTT - Error, truncated UTF8 string property\n");
304 return 0;
305 }
306
307 len = (buf_in[0] << 8) + buf_in[1];
308
309 DBG("MQTT - Decoding %d-char UTF8 string property\n", len);
310
311 /* The declared string must fit within the received input */
312 if(len + MQTT_STRING_LEN_SIZE > buf_in_len) {
313 DBG("MQTT - Error, UTF8 string property exceeds input\n");
314 return 0;
315 }
316
317 /* Include NULL terminator in destination */
318 if((len + MQTT_STRING_LEN_SIZE + 1) > MQTT_PROP_MAX_PROP_LENGTH) {
319 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
320 return 0;
321 }
322
323 memcpy(data, buf_in, len + MQTT_STRING_LEN_SIZE);
324 data[len + MQTT_STRING_LEN_SIZE] = '\0';
325
326 /* Length of string + 2 bytes for length */
327 return len + MQTT_STRING_LEN_SIZE;
328}
329/*---------------------------------------------------------------------------*/
330static uint32_t
331decode_prop_fixed_len_int(struct mqtt_connection *conn,
332 uint8_t *buf_in, uint32_t buf_in_len, int len,
333 uint8_t *data)
334{
335 int8_t i;
336 uint32_t *data_out;
337
338 DBG("MQTT - Decoding %d-byte int property\n", len);
339
340 if(len > MQTT_PROP_MAX_PROP_LENGTH) {
341 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
342 return 0;
343 }
344
345 /* All declared value bytes must be present in the received input */
346 if((uint32_t)len > buf_in_len) {
347 DBG("MQTT - Error, int property exceeds input\n");
348 return 0;
349 }
350
351 /* All integer input properties will be returned as uint32_t */
352 memset(data, 0, 4);
353
354 data_out = (uint32_t *)data;
355
356 for(i = 0; i < 4; i++) {
357 *data_out = *data_out << 8;
358
359 if(i < len) {
360 *data_out += buf_in[i];
361 }
362 }
363
364 return len;
365}
366/*---------------------------------------------------------------------------*/
367static uint32_t
368decode_prop_vbi(struct mqtt_connection *conn,
369 uint8_t *buf_in, uint32_t buf_in_len,
370 uint8_t *data)
371{
372 uint8_t prop_len_bytes;
373
374 DBG("MQTT - Decoding Variable Byte Integer property\n");
375
376 /* All integer input properties will be returned as uint32_t */
377 memset(data, 0, 4);
378
379 /* A Variable Byte Integer is at most 4 bytes, but never read past
380 * the bytes actually received in the input.
381 */
382 prop_len_bytes =
383 mqtt_decode_var_byte_int(buf_in, buf_in_len < 4 ? buf_in_len : 4,
384 NULL, NULL, (uint16_t *)data);
385
386 if(prop_len_bytes == 0) {
387 DBG("MQTT - Error decoding Variable Byte Integer\n");
388 return 0;
389 }
390
391 if(prop_len_bytes > MQTT_PROP_MAX_PROP_LENGTH) {
392 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
393 return 0;
394 }
395
396 return prop_len_bytes;
397}
398/*---------------------------------------------------------------------------*/
399static uint32_t
400decode_prop_binary_data(struct mqtt_connection *conn,
401 uint8_t *buf_in, uint32_t buf_in_len,
402 uint8_t *data)
403{
404 uint32_t data_len;
405
406 DBG("MQTT - Decoding Binary Data property\n");
407
408 /* The 2-byte length prefix must be present in the received input */
409 if(buf_in_len < MQTT_STRING_LEN_SIZE) {
410 DBG("MQTT - Error, truncated Binary Data property\n");
411 return 0;
412 }
413
414 data_len = (buf_in[0] << 8) + buf_in[1];
415
416 if(data_len == 0) {
417 DBG("MQTT - Error decoding Binary Data property length\n");
418 return 0;
419 }
420
421 /* The declared data must fit within the received input */
422 if(data_len + MQTT_STRING_LEN_SIZE > buf_in_len) {
423 DBG("MQTT - Error, Binary Data property exceeds input\n");
424 return 0;
425 }
426
427 if((data_len + MQTT_STRING_LEN_SIZE) > MQTT_PROP_MAX_PROP_LENGTH) {
428 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
429 return 0;
430 }
431
432 memcpy(data, buf_in, data_len + MQTT_STRING_LEN_SIZE);
433
434 return data_len + MQTT_STRING_LEN_SIZE;
435}
436/*---------------------------------------------------------------------------*/
437static uint32_t
438decode_prop_utf8_pair(struct mqtt_connection *conn,
439 uint8_t *buf_in, uint32_t buf_in_len,
440 uint8_t *data)
441{
442 uint32_t len1;
443 uint32_t len2;
444 uint32_t total_len;
445
446 /* The first 2-byte length prefix must be present in the received input */
447 if(buf_in_len < MQTT_STRING_LEN_SIZE) {
448 DBG("MQTT - Error, truncated UTF8 string pair property\n");
449 return 0;
450 }
451
452 len1 = (buf_in[0] << 8) + buf_in[1];
453
454 /* The first string and the second length prefix must be present before
455 * they are read below, otherwise len2 would be read out of bounds.
456 */
457 if(len1 + 2 * MQTT_STRING_LEN_SIZE > buf_in_len) {
458 DBG("MQTT - Error, UTF8 string pair property exceeds input\n");
459 return 0;
460 }
461
462 len2 = (buf_in[len1 + MQTT_STRING_LEN_SIZE] << 8) + buf_in[len1 + MQTT_STRING_LEN_SIZE + 1];
463 total_len = len1 + len2;
464
465 DBG("MQTT - Decoding %d-char UTF8 string pair property (%i + %i)\n", total_len, len1, len2);
466
467 /* The full pair must fit within the received input */
468 if(total_len + 2 * MQTT_STRING_LEN_SIZE > buf_in_len) {
469 DBG("MQTT - Error, UTF8 string pair property exceeds input\n");
470 return 0;
471 }
472
473 if((total_len + 2 * MQTT_STRING_LEN_SIZE) > MQTT_PROP_MAX_PROP_LENGTH) {
474 DBG("MQTT - Error, property too long (max %i bytes)", MQTT_PROP_MAX_PROP_LENGTH);
475 return 0;
476 }
477
478 memcpy(data, buf_in, total_len + 2 * MQTT_STRING_LEN_SIZE);
479
480 /* Length of string + 2 bytes for length */
481 return total_len + 2 * MQTT_STRING_LEN_SIZE;
482}
483/*---------------------------------------------------------------------------*/
484uint32_t
485parse_prop(struct mqtt_connection *conn,
486 mqtt_vhdr_prop_t prop_id, uint8_t *buf_in, uint32_t buf_in_len,
487 uint8_t *data)
488{
489 switch(prop_id) {
490 case MQTT_VHDR_PROP_PAYLOAD_FMT_IND:
491 case MQTT_VHDR_PROP_REQ_PROBLEM_INFO:
492 case MQTT_VHDR_PROP_REQ_RESP_INFO:
493 case MQTT_VHDR_PROP_MAX_QOS:
494 case MQTT_VHDR_PROP_RETAIN_AVAIL:
495 case MQTT_VHDR_PROP_WILD_SUB_AVAIL:
496 case MQTT_VHDR_PROP_SUB_ID_AVAIL:
497 case MQTT_VHDR_PROP_SHARED_SUB_AVAIL: {
498 return decode_prop_fixed_len_int(conn, buf_in, buf_in_len, 1, data);
499 }
500 case MQTT_VHDR_PROP_RECEIVE_MAX:
501 case MQTT_VHDR_PROP_TOPIC_ALIAS_MAX:
502 case MQTT_VHDR_PROP_SERVER_KEEP_ALIVE: {
503 return decode_prop_fixed_len_int(conn, buf_in, buf_in_len, 2, data);
504 }
505 case MQTT_VHDR_PROP_MSG_EXP_INT:
506 case MQTT_VHDR_PROP_SESS_EXP_INT:
507 case MQTT_VHDR_PROP_WILL_DELAY_INT:
508 case MQTT_VHDR_PROP_MAX_PKT_SZ: {
509 return decode_prop_fixed_len_int(conn, buf_in, buf_in_len, 4, data);
510 }
511 case MQTT_VHDR_PROP_CONTENT_TYPE:
512 case MQTT_VHDR_PROP_RESP_TOPIC:
513 case MQTT_VHDR_PROP_AUTH_METHOD:
514 case MQTT_VHDR_PROP_ASSIGNED_CLIENT_ID:
515 case MQTT_VHDR_PROP_RESP_INFO:
516 case MQTT_VHDR_PROP_SERVER_REFERENCE:
517 case MQTT_VHDR_PROP_REASON_STRING: {
518 return decode_prop_utf8(conn, buf_in, buf_in_len, data);
519 }
520 case MQTT_VHDR_PROP_CORRELATION_DATA:
521 case MQTT_VHDR_PROP_AUTH_DATA: {
522 return decode_prop_binary_data(conn, buf_in, buf_in_len, data);
523 }
524 case MQTT_VHDR_PROP_SUB_ID: {
525 return decode_prop_vbi(conn, buf_in, buf_in_len, data);
526 }
527 case MQTT_VHDR_PROP_USER_PROP: {
528 return decode_prop_utf8_pair(conn, buf_in, buf_in_len, data);
529 }
530 default:
531 DBG("MQTT - Error, no such property '%i'", prop_id);
532 return 0;
533 }
534
535 return 0;
536}
537/*---------------------------------------------------------------------------*/
538#if MQTT_5
539uint32_t
540mqtt_get_next_in_prop(struct mqtt_connection *conn,
541 mqtt_vhdr_prop_t *prop_id, uint8_t *data)
542{
543 uint32_t prop_len;
544 uint8_t prop_id_len_bytes;
545 uint16_t prop_id_decode;
546 uint32_t props_offset;
547 uint32_t props_avail;
548 uint32_t props_consumed;
549 uint32_t buf_remaining;
550
551 if(!conn->in_packet.has_props) {
552 DBG("MQTT - Message has no input properties");
553 return 0;
554 }
555
556 DBG("MQTT - Curr prop pos %i; len %i; byte %i\n", (conn->in_packet.curr_props_pos - conn->in_packet.props_start),
557 conn->in_packet.properties_len,
558 *conn->in_packet.curr_props_pos);
559
560 /*
561 * Determine how many bytes may safely be read from the current parsing
562 * position. Bound by both the declared properties length and the number
563 * of bytes actually received into the input buffer, so a malformed
564 * property length cannot drive reads past the received data. The
565 * computation is done on offsets rather than pointers, so that a
566 * malformed length never forms a pointer outside the input buffer.
567 */
568 props_offset =
569 (uint32_t)(conn->in_packet.props_start - conn->in_packet.payload);
570 if(conn->in_packet.payload_pos <= props_offset) {
571 DBG("MQTT - Message has no more input properties\n");
572 return 0;
573 }
574
575 props_avail = conn->in_packet.payload_pos - props_offset;
576 if(conn->in_packet.properties_len < props_avail) {
577 props_avail = conn->in_packet.properties_len;
578 }
579
580 props_consumed =
581 (uint32_t)(conn->in_packet.curr_props_pos - conn->in_packet.props_start);
582 if(props_consumed >= props_avail) {
583 DBG("MQTT - Message has no more input properties\n");
584 return 0;
585 }
586
587 buf_remaining = props_avail - props_consumed;
588
589 prop_id_len_bytes =
590 mqtt_decode_var_byte_int(conn->in_packet.curr_props_pos,
591 buf_remaining,
592 NULL, NULL, (uint16_t *)&prop_id_decode);
593
594 if(prop_id_len_bytes == 0 || prop_id_len_bytes >= buf_remaining) {
595 DBG("MQTT - Error decoding property ID (out of bounds)\n");
596 return 0;
597 }
598
599 *prop_id = prop_id_decode;
600
601 DBG("MQTT - Decoded property ID %i (encoded using %i bytes)\n", *prop_id, prop_id_len_bytes);
602
603 prop_len = parse_prop(conn, *prop_id,
604 conn->in_packet.curr_props_pos + prop_id_len_bytes,
605 buf_remaining - prop_id_len_bytes, data);
606
607 DBG("MQTT - Decoded property len %i bytes\n", prop_len);
608
609 conn->in_packet.curr_props_pos += prop_id_len_bytes + prop_len;
610
611 return prop_len;
612}
613/*---------------------------------------------------------------------------*/
614void
615mqtt_prop_parse_connack_props(struct mqtt_connection *conn)
616{
617 uint32_t prop_len;
618 mqtt_vhdr_prop_t prop_id;
619 uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
620 uint32_t val_int;
621
622 DBG("MQTT - Parsing CONNACK properties for server capabilities\n");
623
624 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
625 while(prop_len) {
626 switch(prop_id) {
627 case MQTT_VHDR_PROP_RETAIN_AVAIL: {
628 val_int = (uint32_t)*data;
629 if(val_int == 0) {
630 conn->srv_feature_en &= ~MQTT_CAP_RETAIN_AVAIL;
631 }
632 break;
633 }
634 case MQTT_VHDR_PROP_WILD_SUB_AVAIL: {
635 val_int = (uint32_t)*data;
636 if(val_int == 0) {
637 conn->srv_feature_en &= ~MQTT_CAP_WILD_SUB_AVAIL;
638 }
639 break;
640 }
641 case MQTT_VHDR_PROP_SUB_ID_AVAIL: {
642 val_int = (uint32_t)*data;
643 if(val_int == 0) {
644 conn->srv_feature_en &= ~MQTT_CAP_SUB_ID_AVAIL;
645 }
646 break;
647 }
648 case MQTT_VHDR_PROP_SHARED_SUB_AVAIL: {
649 val_int = (uint32_t)*data;
650 if(val_int == 0) {
651 conn->srv_feature_en &= ~MQTT_CAP_SHARED_SUB_AVAIL;
652 }
653 break;
654 }
655 default:
656 DBG("MQTT - Error, unexpected CONNACK property '%i'", prop_id);
657 return;
658 }
659
660 prop_id = 0;
661 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
662 }
663}
664/*---------------------------------------------------------------------------*/
665void
666mqtt_prop_parse_auth_props(struct mqtt_connection *conn, struct mqtt_prop_auth_event *event)
667{
668 uint32_t prop_len;
669 mqtt_vhdr_prop_t prop_id;
670 uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
671
672 DBG("MQTT - Parsing CONNACK properties for server capabilities\n");
673
674 event->auth_data.len = 0;
675 event->auth_method.length = 0;
676
677 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
678 while(prop_len) {
679 switch(prop_id) {
680 case MQTT_VHDR_PROP_AUTH_DATA: {
681 event->auth_data.len = prop_len - 2; /* 2 bytes are used to encode len */
682 memcpy(event->auth_data.data, data, prop_len - 2);
683 break;
684 }
685 case MQTT_VHDR_PROP_AUTH_METHOD: {
686 event->auth_method.length = prop_len - 2; /* 2 bytes are used to encode len */
687 memcpy(event->auth_method.string, data, prop_len - 2);
688 break;
689 }
690 default:
691 DBG("MQTT - Unhandled AUTH property '%i'", prop_id);
692 return;
693 }
694
695 prop_id = 0;
696 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
697 }
698}
699/*---------------------------------------------------------------------------*/
700void
701mqtt_prop_print_input_props(struct mqtt_connection *conn)
702{
703 uint32_t prop_len;
704 mqtt_vhdr_prop_t prop_id;
705 uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
706 uint32_t i;
707
708 DBG("MQTT - Printing all input properties\n");
709
710 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
711 while(prop_len) {
712 DBG("MQTT - Property ID %i, length %i\n", prop_id, prop_len);
713
714 switch(prop_id) {
715 case MQTT_VHDR_PROP_PAYLOAD_FMT_IND:
716 case MQTT_VHDR_PROP_REQ_PROBLEM_INFO:
717 case MQTT_VHDR_PROP_REQ_RESP_INFO:
718 case MQTT_VHDR_PROP_MSG_EXP_INT:
719 case MQTT_VHDR_PROP_SESS_EXP_INT:
720 case MQTT_VHDR_PROP_WILL_DELAY_INT:
721 case MQTT_VHDR_PROP_MAX_PKT_SZ:
722 case MQTT_VHDR_PROP_RECEIVE_MAX:
723 case MQTT_VHDR_PROP_TOPIC_ALIAS_MAX:
724 case MQTT_VHDR_PROP_SUB_ID: {
725 DBG("MQTT - Decoded property value '%i'\n", (uint32_t)*data);
726 break;
727 }
728 case MQTT_VHDR_PROP_CONTENT_TYPE:
729 case MQTT_VHDR_PROP_RESP_TOPIC:
730 case MQTT_VHDR_PROP_AUTH_METHOD: {
731 DBG("MQTT - Decoded property value ");
732 DBG("(%i %i) %s", data[0], data[1], data + MQTT_STRING_LEN_SIZE);
733 DBG("\n");
734 break;
735 }
736 case MQTT_VHDR_PROP_CORRELATION_DATA:
737 case MQTT_VHDR_PROP_AUTH_DATA: {
738 DBG("MQTT - Decoded property value (%i %i) ", data[0], data[1]);
739 for(i = 2; i < prop_len; i++) {
740 DBG("%x ", data[i]);
741 }
742 DBG("\n");
743 break;
744 }
745 case MQTT_VHDR_PROP_USER_PROP: {
746#if DEBUG_MQTT
747 uint32_t len1;
748 uint32_t len2;
749
750 len1 = (data[0] << 8) + data[1];
751 len2 = (data[len1 + MQTT_STRING_LEN_SIZE] << 8) + data[len1 + MQTT_STRING_LEN_SIZE + 1];
752#endif
753 DBG("MQTT - Decoded property value [(%i %i) %.*s, (%i %i) %.*s]",
754 data[0], data[1], len1, data + MQTT_STRING_LEN_SIZE,
755 data[len1 + MQTT_STRING_LEN_SIZE], data[len1 + MQTT_STRING_LEN_SIZE + 1], len2, data + len1 + 2 * MQTT_STRING_LEN_SIZE);
756 DBG("\n");
757 break;
758 }
759 default:
760 DBG("MQTT - Error, no such property '%i'\n", prop_id);
761 return;
762 }
763
764 prop_id = 0;
765 prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
766 }
767}
768/*
769 * Functions to manipulate property lists
770 */
771/*----------------------------------------------------------------------------*/
772/* Creates a property list for the requested message type */
773void
774mqtt_prop_create_list(struct mqtt_prop_list **prop_list_out)
775{
776 DBG("MQTT - Creating Property List\n");
777
778#if MQTT_PROP_USE_MEMB
779 *prop_list_out = memb_alloc(&prop_lists_mem);
780#endif
781
782 if(!(*prop_list_out)) {
783 DBG("MQTT - Error, allocated too many property lists (max %i)\n", MQTT_PROP_MAX_OUT_PROP_LISTS);
784 return;
785 }
786
787 DBG("MQTT - Allocated Property list\n");
788
789 LIST_STRUCT_INIT(*prop_list_out, props);
790
791 DBG("MQTT - mem %p prop_list\n", *prop_list_out);
792
793 (*prop_list_out)->properties_len = 0;
794 (*prop_list_out)->properties_len_enc_bytes = 1; /* 1 byte needed for len = 0 */
795}
796/*----------------------------------------------------------------------------*/
797/* Prints all properties in the given property list (debug)
798 * If ID == MQTT_VHDR_PROP_ANY, prints all properties, otherwise it filters them
799 * by property ID
800 */
801void
802mqtt_prop_print_list(struct mqtt_prop_list *prop_list, mqtt_vhdr_prop_t prop_id)
803{
804 struct mqtt_prop_out_property *prop;
805
806 if(prop_list == NULL || prop_list->props == NULL) {
807 DBG("MQTT - Prop list empty\n");
808 } else {
809 prop = (struct mqtt_prop_out_property *)list_head(prop_list->props);
810
811 do {
812 if(prop != NULL && (prop->id == prop_id || prop_id == MQTT_VHDR_PROP_ANY)) {
813 DBG("Property %p ID %i len %i\n", prop, prop->id, prop->property_len);
814 }
815 prop = (struct mqtt_prop_out_property *)list_item_next(prop);
816 } while(prop != NULL);
817 }
818}
819/*---------------------------------------------------------------------------*/
820uint8_t
821mqtt_prop_register_internal(struct mqtt_prop_list **prop_list,
822#if !MQTT_PROP_USE_MEMB
823 struct mqtt_prop_out_property *prop,
824#endif
825 mqtt_msg_type_t msg,
826 mqtt_vhdr_prop_t prop_id,
827 struct mqtt_prop_out_property **prop_out, ...)
828{
829 /* check that the property is compatible with the message? */
830 if(!prop_list) {
831 DBG("MQTT - Error encoding prop %i on msg %i; list NULL\n", prop_id, msg);
832 return 1;
833 }
834
835 DBG("MQTT - prop list %p\n", *prop_list);
836 DBG("MQTT - prop list->list %p\n", (*prop_list)->props);
837
838#if MQTT_PROP_USE_MEMB
839 struct mqtt_prop_out_property *prop = memb_alloc(&props_mem);
840#endif
841
842 if(!prop) {
843 DBG("MQTT - Error, allocated too many properties (max %i)\n", MQTT_PROP_MAX_OUT_PROPS);
844 prop_out = NULL;
845 return 1;
846 }
847
848 DBG("MQTT - Allocated prop %p\n", prop);
849
850 va_list args;
851 va_start(args, prop_out);
852 uint32_t prop_len = mqtt_prop_encode(&prop, prop_id, args);
853
854 if(prop) {
855 DBG("MQTT - Adding prop %p to prop_list %p\n", prop, *prop_list);
856 list_add((*prop_list)->props, prop);
857 (*prop_list)->properties_len += 1; /* Property ID */
858 (*prop_list)->properties_len += prop_len;
859 mqtt_encode_var_byte_int(
860 (*prop_list)->properties_len_enc,
861 &((*prop_list)->properties_len_enc_bytes),
862 (*prop_list)->properties_len);
863 DBG("MQTT - New prop_list length %i\n", (*prop_list)->properties_len);
864 } else {
865 DBG("MQTT - Error encoding prop %i on msg %i\n", prop_id, msg);
866#if MQTT_PROP_USE_MEMB
867 memb_free(&props_mem, prop);
868#endif
869 va_end(args);
870 prop_out = NULL;
871 return 1;
872 }
873
874 if(prop_out) {
875 *prop_out = prop;
876 }
877 va_end(args);
878 return 0;
879}
880/*----------------------------------------------------------------------------*/
881/* Remove one property from list and free its memory */
882uint8_t
883mqtt_remove_prop(struct mqtt_prop_list **prop_list,
884 struct mqtt_prop_out_property *prop)
885{
886 if(prop != NULL && prop_list != NULL && list_contains((*prop_list)->props, prop)) {
887 DBG("MQTT - Removing property %p from list %p\n", prop, *prop_list);
888
889 /* Remove from list */
890 list_remove((*prop_list)->props, prop);
891
892 /* Fix the property list length */
893 (*prop_list)->properties_len -= prop->property_len;
894 (*prop_list)->properties_len -= 1; /* Property ID */
895
896 mqtt_encode_var_byte_int(
897 (*prop_list)->properties_len_enc,
898 &((*prop_list)->properties_len_enc_bytes),
899 (*prop_list)->properties_len);
900
901 /* Free memory */
902#if MQTT_PROP_USE_MEMB
903 memb_free(&props_mem, prop);
904#endif
905 return 0;
906 } else {
907 DBG("MQTT - Cannot remove property\n");
908 return 1;
909 }
910}
911/* Remove & frees all properties in the list */
912void
913mqtt_prop_clear_list(struct mqtt_prop_list **prop_list)
914{
915 struct mqtt_prop_out_property *prop;
916
917 DBG("MQTT - Clearing Property List\n");
918
919 if(prop_list == NULL || list_length((*prop_list)->props) == 0) {
920 DBG("MQTT - Prop list empty\n");
921 return;
922 } else {
923 prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
924
925 do {
926 if(prop != NULL) {
927 (void)mqtt_remove_prop(prop_list, prop);
928 }
929 prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
930 } while(prop != NULL);
931 }
932
933 LIST_STRUCT_INIT(*prop_list, props);
934
935 if((*prop_list)->properties_len != 0 || (*prop_list)->properties_len_enc_bytes != 1) {
936 DBG("MQTT - Something went wrong when clearing property list!\n");
937 }
938}
939#endif
static int value(int type)
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.