Contiki-NG
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
41 MEMB(prop_lists_mem, struct mqtt_prop_list, MQTT_PROP_MAX_OUT_PROP_LISTS);
42 MEMB(props_mem, struct mqtt_prop_out_property, MQTT_PROP_MAX_OUT_PROPS);
43 #endif
44 /*----------------------------------------------------------------------------*/
45 void
46 mqtt_props_init()
47 {
48 #if MQTT_PROP_USE_MEMB
49  memb_init(&props_mem);
50  memb_init(&prop_lists_mem);
51 #endif
52 }
53 /*----------------------------------------------------------------------------*/
54 static void
55 encode_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 /*---------------------------------------------------------------------------*/
75 static void
76 encode_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 /*---------------------------------------------------------------------------*/
97 static void
98 encode_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 /*---------------------------------------------------------------------------*/
115 static void
116 encode_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 /*---------------------------------------------------------------------------*/
131 uint32_t
132 mqtt_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
251 void
252 mqtt_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 /*---------------------------------------------------------------------------*/
294 static uint32_t
295 decode_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 /*---------------------------------------------------------------------------*/
318 static uint32_t
319 decode_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 /*---------------------------------------------------------------------------*/
349 static uint32_t
350 decode_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 /*---------------------------------------------------------------------------*/
377 static uint32_t
378 decode_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 /*---------------------------------------------------------------------------*/
403 static uint32_t
404 decode_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 /*---------------------------------------------------------------------------*/
429 uint32_t
430 parse_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
483 uint32_t
484 mqtt_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 /*---------------------------------------------------------------------------*/
524 void
525 mqtt_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 /*---------------------------------------------------------------------------*/
575 void
576 mqtt_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 /*---------------------------------------------------------------------------*/
610 void
611 mqtt_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 */
683 void
684 mqtt_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  */
711 void
712 mqtt_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 /*---------------------------------------------------------------------------*/
730 uint8_t
731 mqtt_prop_register(struct mqtt_prop_list **prop_list,
732  struct mqtt_prop_out_property **prop_out,
733 #if !MQTT_PROP_USE_MEMB
734  struct mqtt_prop_out_property *prop,
735 #endif
736  mqtt_msg_type_t msg,
737  mqtt_vhdr_prop_t prop_id, ...)
738 {
739 #if MQTT_PROP_USE_MEMB
740  struct mqtt_prop_out_property *prop;
741 #endif
742  va_list args;
743  uint32_t prop_len;
744 
745  va_start(args, prop_id);
746 
747  /* check that the property is compatible with the message? */
748 
749  if(!prop_list) {
750  DBG("MQTT - Error encoding prop %i on msg %i; list NULL\n", prop_id, msg);
751  va_end(args);
752  return 1;
753  }
754 
755  DBG("MQTT - prop list %p\n", *prop_list);
756  DBG("MQTT - prop list->list %p\n", (*prop_list)->props);
757 
758 #if MQTT_PROP_USE_MEMB
759  prop = (struct mqtt_prop_out_property *)memb_alloc(&props_mem);
760 #endif
761 
762  if(!prop) {
763  DBG("MQTT - Error, allocated too many properties (max %i)\n", MQTT_PROP_MAX_OUT_PROPS);
764  prop_out = NULL;
765  return 1;
766  }
767 
768  DBG("MQTT - Allocated prop %p\n", prop);
769 
770  prop_len = mqtt_prop_encode(&prop, prop_id, args);
771 
772  if(prop) {
773  DBG("MQTT - Adding prop %p to prop_list %p\n", prop, *prop_list);
774  list_add((*prop_list)->props, prop);
775  (*prop_list)->properties_len += 1; /* Property ID */
776  (*prop_list)->properties_len += prop_len;
777  mqtt_encode_var_byte_int(
778  (*prop_list)->properties_len_enc,
779  &((*prop_list)->properties_len_enc_bytes),
780  (*prop_list)->properties_len);
781  DBG("MQTT - New prop_list length %i\n", (*prop_list)->properties_len);
782  } else {
783  DBG("MQTT - Error encoding prop %i on msg %i\n", prop_id, msg);
784 #if MQTT_PROP_USE_MEMB
785  memb_free(&props_mem, prop);
786 #endif
787  va_end(args);
788  prop_out = NULL;
789  return 1;
790  }
791 
792  if(prop_out) {
793  *prop_out = prop;
794  }
795  va_end(args);
796  return 0;
797 }
798 /*----------------------------------------------------------------------------*/
799 /* Remove one property from list and free its memory */
800 uint8_t
801 mqtt_remove_prop(struct mqtt_prop_list **prop_list,
802  struct mqtt_prop_out_property *prop)
803 {
804  if(prop != NULL && prop_list != NULL && list_contains((*prop_list)->props, prop)) {
805  DBG("MQTT - Removing property %p from list %p\n", prop, *prop_list);
806 
807  /* Remove from list */
808  list_remove((*prop_list)->props, prop);
809 
810  /* Fix the property list length */
811  (*prop_list)->properties_len -= prop->property_len;
812  (*prop_list)->properties_len -= 1; /* Property ID */
813 
814  mqtt_encode_var_byte_int(
815  (*prop_list)->properties_len_enc,
816  &((*prop_list)->properties_len_enc_bytes),
817  (*prop_list)->properties_len);
818 
819  /* Free memory */
820 #if MQTT_PROP_USE_MEMB
821  memb_free(&props_mem, prop);
822 #endif
823  return 0;
824  } else {
825  DBG("MQTT - Cannot remove property\n");
826  return 1;
827  }
828 }
829 /* Remove & frees all properties in the list */
830 void
831 mqtt_prop_clear_list(struct mqtt_prop_list **prop_list)
832 {
833  struct mqtt_prop_out_property *prop;
834 
835  DBG("MQTT - Clearing Property List\n");
836 
837  if(prop_list == NULL || list_length((*prop_list)->props) == 0) {
838  DBG("MQTT - Prop list empty\n");
839  return;
840  } else {
841  prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
842 
843  do {
844  if(prop != NULL) {
845  (void)mqtt_remove_prop(prop_list, prop);
846  }
847  prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
848  } while(prop != NULL);
849  }
850 
851  LIST_STRUCT_INIT(*prop_list, props);
852 
853  if((*prop_list)->properties_len != 0 || (*prop_list)->properties_len_enc_bytes != 1) {
854  DBG("MQTT - Something went wrong when clearing property list!\n");
855  }
856 }
857 #endif
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
bool list_contains(list_t list, void *item)
Check if the list contains an item.
Definition: list.c:338
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
Header file for the Contiki MQTT engine.
Memory block allocation routines.
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
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
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90
int list_length(list_t list)
Get the length of a list.
Definition: list.c:272