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 
490  if(!conn->in_packet.has_props) {
491  DBG("MQTT - Message has no input properties");
492  return 0;
493  }
494 
495  DBG("MQTT - Curr prop pos %i; len %i; byte %i\n", (conn->in_packet.curr_props_pos - conn->in_packet.props_start),
496  conn->in_packet.properties_len,
497  *conn->in_packet.curr_props_pos);
498 
499  if((conn->in_packet.curr_props_pos - conn->in_packet.props_start)
500  >= conn->in_packet.properties_len) {
501  DBG("MQTT - Message has no more input properties\n");
502  return 0;
503  }
504 
505  prop_id_len_bytes =
506  mqtt_decode_var_byte_int(conn->in_packet.curr_props_pos,
507  conn->in_packet.properties_len - (conn->in_packet.curr_props_pos - conn->in_packet.props_start),
508  NULL, NULL, (uint16_t *)prop_id);
509 
510  DBG("MQTT - Decoded property ID %i (encoded using %i bytes)\n", *prop_id, prop_id_len_bytes);
511 
512  prop_len = parse_prop(conn, *prop_id, conn->in_packet.curr_props_pos + 1, data);
513 
514  DBG("MQTT - Decoded property len %i bytes\n", prop_len);
515 
516  conn->in_packet.curr_props_pos += prop_id_len_bytes + prop_len;
517 
518  return prop_len;
519 }
520 /*---------------------------------------------------------------------------*/
521 void
522 mqtt_prop_parse_connack_props(struct mqtt_connection *conn)
523 {
524  uint32_t prop_len;
525  mqtt_vhdr_prop_t prop_id;
526  uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
527  uint32_t val_int;
528 
529  DBG("MQTT - Parsing CONNACK properties for server capabilities\n");
530 
531  prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
532  while(prop_len) {
533  switch(prop_id) {
534  case MQTT_VHDR_PROP_RETAIN_AVAIL: {
535  val_int = (uint32_t)*data;
536  if(val_int == 0) {
537  conn->srv_feature_en &= ~MQTT_CAP_RETAIN_AVAIL;
538  }
539  break;
540  }
541  case MQTT_VHDR_PROP_WILD_SUB_AVAIL: {
542  val_int = (uint32_t)*data;
543  if(val_int == 0) {
544  conn->srv_feature_en &= ~MQTT_CAP_WILD_SUB_AVAIL;
545  }
546  break;
547  }
548  case MQTT_VHDR_PROP_SUB_ID_AVAIL: {
549  val_int = (uint32_t)*data;
550  if(val_int == 0) {
551  conn->srv_feature_en &= ~MQTT_CAP_SUB_ID_AVAIL;
552  }
553  break;
554  }
555  case MQTT_VHDR_PROP_SHARED_SUB_AVAIL: {
556  val_int = (uint32_t)*data;
557  if(val_int == 0) {
558  conn->srv_feature_en &= ~MQTT_CAP_SHARED_SUB_AVAIL;
559  }
560  break;
561  }
562  default:
563  DBG("MQTT - Error, unexpected CONNACK property '%i'", prop_id);
564  return;
565  }
566 
567  prop_id = 0;
568  prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
569  }
570 }
571 /*---------------------------------------------------------------------------*/
572 void
573 mqtt_prop_parse_auth_props(struct mqtt_connection *conn, struct mqtt_prop_auth_event *event)
574 {
575  uint32_t prop_len;
576  mqtt_vhdr_prop_t prop_id;
577  uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
578 
579  DBG("MQTT - Parsing CONNACK properties for server capabilities\n");
580 
581  event->auth_data.len = 0;
582  event->auth_method.length = 0;
583 
584  prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
585  while(prop_len) {
586  switch(prop_id) {
587  case MQTT_VHDR_PROP_AUTH_DATA: {
588  event->auth_data.len = prop_len - 2; /* 2 bytes are used to encode len */
589  memcpy(event->auth_data.data, data, prop_len - 2);
590  break;
591  }
592  case MQTT_VHDR_PROP_AUTH_METHOD: {
593  event->auth_method.length = prop_len - 2; /* 2 bytes are used to encode len */
594  memcpy(event->auth_method.string, data, prop_len - 2);
595  break;
596  }
597  default:
598  DBG("MQTT - Unhandled AUTH property '%i'", prop_id);
599  return;
600  }
601 
602  prop_id = 0;
603  prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
604  }
605 }
606 /*---------------------------------------------------------------------------*/
607 void
608 mqtt_prop_print_input_props(struct mqtt_connection *conn)
609 {
610  uint32_t prop_len;
611  mqtt_vhdr_prop_t prop_id;
612  uint8_t data[MQTT_PROP_MAX_PROP_LENGTH];
613  uint32_t i;
614 
615  DBG("MQTT - Printing all input properties\n");
616 
617  prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
618  while(prop_len) {
619  DBG("MQTT - Property ID %i, length %i\n", prop_id, prop_len);
620 
621  switch(prop_id) {
622  case MQTT_VHDR_PROP_PAYLOAD_FMT_IND:
623  case MQTT_VHDR_PROP_REQ_PROBLEM_INFO:
624  case MQTT_VHDR_PROP_REQ_RESP_INFO:
625  case MQTT_VHDR_PROP_MSG_EXP_INT:
626  case MQTT_VHDR_PROP_SESS_EXP_INT:
627  case MQTT_VHDR_PROP_WILL_DELAY_INT:
628  case MQTT_VHDR_PROP_MAX_PKT_SZ:
629  case MQTT_VHDR_PROP_RECEIVE_MAX:
630  case MQTT_VHDR_PROP_TOPIC_ALIAS_MAX:
631  case MQTT_VHDR_PROP_SUB_ID: {
632  DBG("MQTT - Decoded property value '%i'\n", (uint32_t)*data);
633  break;
634  }
635  case MQTT_VHDR_PROP_CONTENT_TYPE:
636  case MQTT_VHDR_PROP_RESP_TOPIC:
637  case MQTT_VHDR_PROP_AUTH_METHOD: {
638  DBG("MQTT - Decoded property value ");
639  DBG("(%i %i) %s", data[0], data[1], data + MQTT_STRING_LEN_SIZE);
640  DBG("\n");
641  break;
642  }
643  case MQTT_VHDR_PROP_CORRELATION_DATA:
644  case MQTT_VHDR_PROP_AUTH_DATA: {
645  DBG("MQTT - Decoded property value (%i %i) ", data[0], data[1]);
646  for(i = 2; i < prop_len; i++) {
647  DBG("%x ", data[i]);
648  }
649  DBG("\n");
650  break;
651  }
652  case MQTT_VHDR_PROP_USER_PROP: {
653 #if DEBUG_MQTT
654  uint32_t len1;
655  uint32_t len2;
656 
657  len1 = (data[0] << 8) + data[1];
658  len2 = (data[len1 + MQTT_STRING_LEN_SIZE] << 8) + data[len1 + MQTT_STRING_LEN_SIZE + 1];
659 #endif
660  DBG("MQTT - Decoded property value [(%i %i) %.*s, (%i %i) %.*s]",
661  data[0], data[1], len1, data + MQTT_STRING_LEN_SIZE,
662  data[len1 + MQTT_STRING_LEN_SIZE], data[len1 + MQTT_STRING_LEN_SIZE + 1], len2, data + len1 + 2 * MQTT_STRING_LEN_SIZE);
663  DBG("\n");
664  break;
665  }
666  default:
667  DBG("MQTT - Error, no such property '%i'\n", prop_id);
668  return;
669  }
670 
671  prop_id = 0;
672  prop_len = mqtt_get_next_in_prop(conn, &prop_id, data);
673  }
674 }
675 /*
676  * Functions to manipulate property lists
677  */
678 /*----------------------------------------------------------------------------*/
679 /* Creates a property list for the requested message type */
680 void
681 mqtt_prop_create_list(struct mqtt_prop_list **prop_list_out)
682 {
683  DBG("MQTT - Creating Property List\n");
684 
685 #if MQTT_PROP_USE_MEMB
686  *prop_list_out = memb_alloc(&prop_lists_mem);
687 #endif
688 
689  if(!(*prop_list_out)) {
690  DBG("MQTT - Error, allocated too many property lists (max %i)\n", MQTT_PROP_MAX_OUT_PROP_LISTS);
691  return;
692  }
693 
694  DBG("MQTT - Allocated Property list\n");
695 
696  LIST_STRUCT_INIT(*prop_list_out, props);
697 
698  DBG("MQTT - mem %p prop_list\n", *prop_list_out);
699 
700  (*prop_list_out)->properties_len = 0;
701  (*prop_list_out)->properties_len_enc_bytes = 1; /* 1 byte needed for len = 0 */
702 }
703 /*----------------------------------------------------------------------------*/
704 /* Prints all properties in the given property list (debug)
705  * If ID == MQTT_VHDR_PROP_ANY, prints all properties, otherwise it filters them
706  * by property ID
707  */
708 void
709 mqtt_prop_print_list(struct mqtt_prop_list *prop_list, mqtt_vhdr_prop_t prop_id)
710 {
711  struct mqtt_prop_out_property *prop;
712 
713  if(prop_list == NULL || prop_list->props == NULL) {
714  DBG("MQTT - Prop list empty\n");
715  } else {
716  prop = (struct mqtt_prop_out_property *)list_head(prop_list->props);
717 
718  do {
719  if(prop != NULL && (prop->id == prop_id || prop_id == MQTT_VHDR_PROP_ANY)) {
720  DBG("Property %p ID %i len %i\n", prop, prop->id, prop->property_len);
721  }
722  prop = (struct mqtt_prop_out_property *)list_item_next(prop);
723  } while(prop != NULL);
724  }
725 }
726 /*---------------------------------------------------------------------------*/
727 uint8_t
728 mqtt_prop_register(struct mqtt_prop_list **prop_list,
729  struct mqtt_prop_out_property **prop_out,
730 #if !MQTT_PROP_USE_MEMB
731  struct mqtt_prop_out_property *prop,
732 #endif
733  mqtt_msg_type_t msg,
734  mqtt_vhdr_prop_t prop_id, ...)
735 {
736 #if MQTT_PROP_USE_MEMB
737  struct mqtt_prop_out_property *prop;
738 #endif
739  va_list args;
740  uint32_t prop_len;
741 
742  va_start(args, prop_id);
743 
744  /* check that the property is compatible with the message? */
745 
746  if(!prop_list) {
747  DBG("MQTT - Error encoding prop %i on msg %i; list NULL\n", prop_id, msg);
748  va_end(args);
749  return 1;
750  }
751 
752  DBG("MQTT - prop list %p\n", *prop_list);
753  DBG("MQTT - prop list->list %p\n", (*prop_list)->props);
754 
755 #if MQTT_PROP_USE_MEMB
756  prop = (struct mqtt_prop_out_property *)memb_alloc(&props_mem);
757 #endif
758 
759  if(!prop) {
760  DBG("MQTT - Error, allocated too many properties (max %i)\n", MQTT_PROP_MAX_OUT_PROPS);
761  prop_out = NULL;
762  return 1;
763  }
764 
765  DBG("MQTT - Allocated prop %p\n", prop);
766 
767  prop_len = mqtt_prop_encode(&prop, prop_id, args);
768 
769  if(prop) {
770  DBG("MQTT - Adding prop %p to prop_list %p\n", prop, *prop_list);
771  list_add((*prop_list)->props, prop);
772  (*prop_list)->properties_len += 1; /* Property ID */
773  (*prop_list)->properties_len += prop_len;
774  mqtt_encode_var_byte_int(
775  (*prop_list)->properties_len_enc,
776  &((*prop_list)->properties_len_enc_bytes),
777  (*prop_list)->properties_len);
778  DBG("MQTT - New prop_list length %i\n", (*prop_list)->properties_len);
779  } else {
780  DBG("MQTT - Error encoding prop %i on msg %i\n", prop_id, msg);
781 #if MQTT_PROP_USE_MEMB
782  memb_free(&props_mem, prop);
783 #endif
784  va_end(args);
785  prop_out = NULL;
786  return 1;
787  }
788 
789  if(prop_out) {
790  *prop_out = prop;
791  }
792  va_end(args);
793  return 0;
794 }
795 /*----------------------------------------------------------------------------*/
796 /* Remove one property from list and free its memory */
797 uint8_t
798 mqtt_remove_prop(struct mqtt_prop_list **prop_list,
799  struct mqtt_prop_out_property *prop)
800 {
801  if(prop != NULL && prop_list != NULL && list_contains((*prop_list)->props, prop)) {
802  DBG("MQTT - Removing property %p from list %p\n", prop, *prop_list);
803 
804  /* Remove from list */
805  list_remove((*prop_list)->props, prop);
806 
807  /* Fix the property list length */
808  (*prop_list)->properties_len -= prop->property_len;
809  (*prop_list)->properties_len -= 1; /* Property ID */
810 
811  mqtt_encode_var_byte_int(
812  (*prop_list)->properties_len_enc,
813  &((*prop_list)->properties_len_enc_bytes),
814  (*prop_list)->properties_len);
815 
816  /* Free memory */
817 #if MQTT_PROP_USE_MEMB
818  memb_free(&props_mem, prop);
819 #endif
820  return 0;
821  } else {
822  DBG("MQTT - Cannot remove property\n");
823  return 1;
824  }
825 }
826 /* Remove & frees all properties in the list */
827 void
828 mqtt_prop_clear_list(struct mqtt_prop_list **prop_list)
829 {
830  struct mqtt_prop_out_property *prop;
831 
832  DBG("MQTT - Clearing Property List\n");
833 
834  if(prop_list == NULL || list_length((*prop_list)->props) == 0) {
835  DBG("MQTT - Prop list empty\n");
836  return;
837  } else {
838  prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
839 
840  do {
841  if(prop != NULL) {
842  (void)mqtt_remove_prop(prop_list, prop);
843  }
844  prop = (struct mqtt_prop_out_property *)list_head((*prop_list)->props);
845  } while(prop != NULL);
846  }
847 
848  LIST_STRUCT_INIT(*prop_list, props);
849 
850  if((*prop_list)->properties_len != 0 || (*prop_list)->properties_len_enc_bytes != 1) {
851  DBG("MQTT - Something went wrong when clearing property list!\n");
852  }
853 }
854 #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