libcoap  4.3.0rc3
pdu.c
Go to the documentation of this file.
1 /* pdu.c -- CoAP message structure
2  *
3  * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap3/coap_internal.h"
10 
11 #if defined(HAVE_LIMITS_H)
12 #include <limits.h>
13 #endif
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
20 #endif
21 #ifdef HAVE_WINSOCK2_H
22 #include <winsock2.h>
23 #endif
24 #include <ctype.h>
25 
26 #ifndef min
27 #define min(a,b) ((a) < (b) ? (a) : (b))
28 #endif
29 
30 #ifndef max
31 #define max(a,b) ((a) > (b) ? (a) : (b))
32 #endif
33 
34 void
35 coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
36  assert(pdu);
37  assert(pdu->token);
39  if (pdu->alloc_size > size)
40  pdu->alloc_size = size;
41  pdu->type = 0;
42  pdu->code = 0;
43  pdu->hdr_size = 0;
44  pdu->token_length = 0;
45  pdu->mid = 0;
46  pdu->max_opt = 0;
47  pdu->max_size = size;
48  pdu->used_size = 0;
49  pdu->data = NULL;
50  pdu->body_data = NULL;
51  pdu->body_length = 0;
52  pdu->body_offset = 0;
53  pdu->body_total = 0;
54  pdu->lg_xmit = NULL;
55 }
56 
57 #ifdef WITH_LWIP
58 coap_pdu_t *
59 coap_pdu_from_pbuf( struct pbuf *pbuf )
60 {
61  coap_pdu_t *pdu;
62 
63  if (pbuf == NULL) return NULL;
64 
65  LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
66  LWIP_ASSERT("coap_io_do_io needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
67 
68  pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t) );
69  if (!pdu) {
70  pbuf_free(pbuf);
71  return NULL;
72  }
73 
75  pdu->pbuf = pbuf;
76  pdu->token = (uint8_t *)pbuf->payload + pdu->max_hdr_size;
77  pdu->alloc_size = pbuf->tot_len - pdu->max_hdr_size;
78  coap_pdu_clear(pdu, pdu->alloc_size);
79 
80  return pdu;
81 }
82 #endif
83 
84 coap_pdu_t *
86  size_t size) {
87  coap_pdu_t *pdu;
88 
89  assert(type <= 0x3);
90  assert(code <= 0xff);
91  assert(mid >= 0 && mid <= 0xffff);
92 
93  pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
94  if (!pdu) return NULL;
95 
96 #if defined(WITH_CONTIKI) || defined(WITH_LWIP)
97  assert(size <= COAP_MAX_MESSAGE_SIZE_TCP16 + 4);
98  if (size > COAP_MAX_MESSAGE_SIZE_TCP16 + 4)
99  return NULL;
101 #else
103 #endif
104 
105 #ifdef WITH_LWIP
106  pdu->pbuf = pbuf_alloc(PBUF_TRANSPORT, size + pdu->max_hdr_size, PBUF_RAM);
107  if (pdu->pbuf == NULL) {
108  coap_free_type(COAP_PDU, pdu);
109  return NULL;
110  }
111  pdu->token = (uint8_t *)pdu->pbuf->payload + pdu->max_hdr_size;
112 #else /* WITH_LWIP */
113  uint8_t *buf;
114  pdu->alloc_size = min(size, 256);
116  if (buf == NULL) {
117  coap_free_type(COAP_PDU, pdu);
118  return NULL;
119  }
120  pdu->token = buf + pdu->max_hdr_size;
121 #endif /* WITH_LWIP */
122  coap_pdu_clear(pdu, size);
123  pdu->mid = mid;
124  pdu->type = type;
125  pdu->code = code;
126  return pdu;
127 }
128 
129 coap_pdu_t *
131  coap_session_t *session) {
132  coap_pdu_t *pdu = coap_pdu_init(type, code, coap_new_message_id(session),
133  coap_session_max_pdu_size(session));
134  if (!pdu)
135  coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
136  return pdu;
137 }
138 
139 void
141  if (pdu != NULL) {
142 #ifdef WITH_LWIP
143  pbuf_free(pdu->pbuf);
144 #else
145  if (pdu->token != NULL)
147 #endif
148  coap_free_type(COAP_PDU, pdu);
149  }
150 }
151 
152 coap_pdu_t *
154  coap_session_t *session,
155  size_t token_length,
156  const uint8_t *token,
157  coap_opt_filter_t *drop_options) {
158  coap_pdu_t *pdu = coap_pdu_init(old_pdu->type,
159  old_pdu->code,
160  coap_new_message_id(session),
161  coap_session_max_pdu_size(session));
162 
163  if (pdu == NULL)
164  return NULL;
165 
166  coap_add_token(pdu, token_length, token);
167  pdu->lg_xmit = old_pdu->lg_xmit;
168 
169  if (drop_options == NULL) {
170  /* Drop COAP_PAYLOAD_START as well if data */
171  size_t length = old_pdu->used_size - old_pdu->token_length -
172  (old_pdu->data ?
173  old_pdu->used_size - (old_pdu->data - old_pdu->token) +1 : 0);
174  if (!coap_pdu_resize(pdu, length + old_pdu->hdr_size))
175  goto fail;
176  /* Copy the options and any data across */
177  memcpy(pdu->token + pdu->token_length,
178  old_pdu->token + old_pdu->token_length, length);
179  pdu->used_size += length;
180  pdu->max_opt = old_pdu->max_opt;
181  }
182  else {
183  /* Copy across all the options the slow way */
184  coap_opt_iterator_t opt_iter;
185  coap_opt_t *option;
186 
187  coap_option_iterator_init(old_pdu, &opt_iter, COAP_OPT_ALL);
188  while ((option = coap_option_next(&opt_iter))) {
189  if (drop_options && coap_option_filter_get(drop_options, opt_iter.number))
190  continue;
191  if (!coap_add_option(pdu, opt_iter.number,
192  coap_opt_length(option),
193  coap_opt_value(option)))
194  goto fail;
195  }
196  }
197  return pdu;
198 
199 fail:
200  coap_delete_pdu(pdu);
201  return NULL;
202 }
203 
204 int
205 coap_pdu_resize(coap_pdu_t *pdu, size_t new_size) {
206  if (new_size > pdu->alloc_size) {
207 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
208  uint8_t *new_hdr;
209  size_t offset;
210 #endif
211  if (pdu->max_size && new_size > pdu->max_size) {
212  coap_log(LOG_WARNING, "coap_pdu_resize: pdu too big\n");
213  return 0;
214  }
215 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
216  if (pdu->data != NULL) {
217  assert(pdu->data > pdu->token);
218  offset = pdu->data - pdu->token;
219  } else {
220  offset = 0;
221  }
222  new_hdr = (uint8_t*)realloc(pdu->token - pdu->max_hdr_size, new_size + pdu->max_hdr_size);
223  if (new_hdr == NULL) {
224  coap_log(LOG_WARNING, "coap_pdu_resize: realloc failed\n");
225  return 0;
226  }
227  pdu->token = new_hdr + pdu->max_hdr_size;
228  if (offset > 0)
229  pdu->data = pdu->token + offset;
230  else
231  pdu->data = NULL;
232 #endif
233  }
234  pdu->alloc_size = new_size;
235  return 1;
236 }
237 
238 int
239 coap_pdu_check_resize(coap_pdu_t *pdu, size_t size) {
240  if (size > pdu->alloc_size) {
241  size_t new_size = max(256, pdu->alloc_size * 2);
242  while (size > new_size)
243  new_size *= 2;
244  if (pdu->max_size && new_size > pdu->max_size) {
245  new_size = pdu->max_size;
246  if (new_size < size)
247  return 0;
248  }
249  if (!coap_pdu_resize(pdu, new_size))
250  return 0;
251  }
252  return 1;
253 }
254 
255 int
256 coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
257  /* must allow for pdu == NULL as callers may rely on this */
258  if (!pdu || len > 8)
259  return 0;
260 
261  if (pdu->used_size) {
263  "coap_add_token: The token must defined first. Token ignored\n");
264  return 0;
265  }
266  if (!coap_pdu_check_resize(pdu, len))
267  return 0;
268  pdu->token_length = (uint8_t)len;
269  if (len)
270  memcpy(pdu->token, data, len);
271  pdu->max_opt = 0;
272  pdu->used_size = len;
273  pdu->data = NULL;
274 
275  return 1;
276 }
277 
278 /* It is assumed that coap_encode_var_safe8() has been called to reduce data */
279 int
280 coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
281  /* must allow for pdu == NULL as callers may rely on this */
282  if (!pdu || len > 8)
283  return 0;
284 
285  if (pdu->used_size == 0) {
286  return coap_add_token(pdu, len, data);
287  }
288  if (len == pdu->token_length) {
289  /* Easy case - just data has changed */
290  }
291  else if (len > pdu->token_length) {
292  if (!coap_pdu_check_resize(pdu, pdu->used_size + len - pdu->token_length))
293  return 0;
294  memmove(&pdu->token[len - pdu->token_length], pdu->token, pdu->used_size);
295  pdu->used_size += len - pdu->token_length;
296  }
297  else {
298  pdu->used_size -= pdu->token_length - len;
299  memmove(pdu->token, &pdu->token[pdu->token_length - len], pdu->used_size);
300  }
301  if (pdu->data) {
302  pdu->data += len - pdu->token_length;
303  }
304  pdu->token_length = (uint8_t)len;
305  if (len)
306  memcpy(pdu->token, data, len);
307 
308  return 1;
309 }
310 
311 int
313  coap_opt_iterator_t opt_iter;
314  coap_opt_t *option;
315  coap_opt_t *next_option = NULL;
316  size_t opt_delta;
317  coap_option_t decode_this;
318  coap_option_t decode_next;
319 
320  /* Need to locate where in current options to remove this one */
321  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
322  while ((option = coap_option_next(&opt_iter))) {
323  if (opt_iter.number == number) {
324  /* Found option to delete */
325  break;
326  }
327  }
328  if (!option)
329  return 0;
330 
331  if (!coap_opt_parse(option, pdu->used_size - (option - pdu->token),
332  &decode_this))
333  return 0;
334 
335  next_option = coap_option_next(&opt_iter);
336  if (next_option) {
337  if (!coap_opt_parse(next_option,
338  pdu->used_size - (next_option - pdu->token),
339  &decode_next))
340  return 0;
341  opt_delta = decode_this.delta + decode_next.delta;
342  if (opt_delta <= 12) {
343  /* can simply update the delta of next option */
344  next_option[0] = (next_option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
345  }
346  else if (opt_delta <= 269 && decode_next.delta <= 12) {
347  /* next option delta size increase */
348  next_option -= 1;
349  next_option[0] = (next_option[1] & 0x0f) + (13 << 4);
350  next_option[1] = (coap_opt_t)(opt_delta - 13);
351  }
352  else if (opt_delta <= 269) {
353  /* can simply update the delta of next option */
354  next_option[1] = (coap_opt_t)(opt_delta - 13);
355  }
356  else if (decode_next.delta <= 12) {
357  /* next option delta size increase */
358  if (next_option - option < 2) {
359  /* Need to shuffle everything up by 1 before decrement */
360  if (!coap_pdu_check_resize(pdu, pdu->used_size + 1))
361  return 0;
362  /* Possible a re-size took place with a realloc() */
363  /* Need to rediscover this and next options */
364  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
365  while ((option = coap_option_next(&opt_iter))) {
366  if (opt_iter.number == number) {
367  /* Found option to delete */
368  break;
369  }
370  }
371  next_option = coap_option_next(&opt_iter);
372  assert(option != NULL);
373  assert(next_option != NULL);
374  memmove(&next_option[1], next_option,
375  pdu->used_size - (next_option - pdu->token));
376  pdu->used_size++;
377  if (pdu->data)
378  pdu->data++;
379  next_option++;
380  }
381  next_option -= 2;
382  next_option[0] = (next_option[2] & 0x0f) + (14 << 4);
383  next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
384  next_option[2] = (opt_delta - 269) & 0xff;
385  }
386  else if (decode_next.delta <= 269) {
387  /* next option delta size increase */
388  next_option -= 1;
389  next_option[0] = (next_option[1] & 0x0f) + (14 << 4);
390  next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
391  next_option[2] = (opt_delta - 269) & 0xff;
392  }
393  else {
394  next_option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
395  next_option[2] = (opt_delta - 269) & 0xff;
396  }
397  }
398  else {
399  next_option = option + coap_opt_encode_size(decode_this.delta,
400  coap_opt_length(option));
401  pdu->max_opt -= decode_this.delta;
402  }
403  if (pdu->used_size - (next_option - pdu->token))
404  memmove(option, next_option, pdu->used_size - (next_option - pdu->token));
405  pdu->used_size -= next_option - option;
406  if (pdu->data)
407  pdu->data -= next_option - option;
408  return 1;
409 }
410 
411 size_t
413  const uint8_t *data) {
414  coap_opt_iterator_t opt_iter;
415  coap_opt_t *option;
416  uint16_t prev_number = 0;
417  size_t shift;
418  size_t opt_delta;
419  coap_option_t decode;
420  size_t shrink = 0;
421 
422  if (number >= pdu->max_opt)
423  return coap_add_option(pdu, number, len, data);
424 
425  /* Need to locate where in current options to insert this one */
426  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
427  while ((option = coap_option_next(&opt_iter))) {
428  if (opt_iter.number > number) {
429  /* Found where to insert */
430  break;
431  }
432  prev_number = opt_iter.number;
433  }
434  assert(option != NULL);
435  /* size of option inc header to insert */
436  shift = coap_opt_encode_size(number - prev_number, len);
437 
438  /* size of next option (header may shrink in size as delta changes */
439  if (!coap_opt_parse(option, opt_iter.length + 5, &decode))
440  return 0;
441  opt_delta = opt_iter.number - number;
442 
443  if (!coap_pdu_check_resize(pdu,
444  pdu->used_size + shift - shrink))
445  return 0;
446 
447  /* Possible a re-size took place with a realloc() */
448  /* Need to locate where in current options to insert this one */
449  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
450  while ((option = coap_option_next(&opt_iter))) {
451  if (opt_iter.number > number) {
452  /* Found where to insert */
453  break;
454  }
455  }
456  assert(option != NULL);
457 
458  if (decode.delta <= 12) {
459  /* can simply patch in the new delta of next option */
460  option[0] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
461  }
462  else if (decode.delta <= 269 && opt_delta <= 12) {
463  /* option header is going to shrink by one byte */
464  option[1] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
465  shrink = 1;
466  }
467  else if (decode.delta <= 269 && opt_delta <= 269) {
468  /* can simply patch in the new delta of next option */
469  option[1] = (coap_opt_t)(opt_delta - 13);
470  }
471  else if (opt_delta <= 12) {
472  /* option header is going to shrink by two bytes */
473  option[2] = (option[0] & 0x0f) + (coap_opt_t)(opt_delta << 4);
474  shrink = 2;
475  }
476  else if (opt_delta <= 269) {
477  /* option header is going to shrink by one bytes */
478  option[1] = (option[0] & 0x0f) + 0xd0;
479  option[2] = (coap_opt_t)(opt_delta - 13);
480  shrink = 1;
481  }
482  else {
483  /* can simply patch in the new delta of next option */
484  option[1] = (coap_opt_t)((opt_delta - 269) >> 8);
485  option[2] = (opt_delta - 269) & 0xff;
486  }
487 
488  memmove(&option[shift], &option[shrink],
489  pdu->used_size - (option - pdu->token) - shrink);
490  if (!coap_opt_encode(option, pdu->alloc_size - pdu->used_size,
491  number - prev_number, data, len))
492  return 0;
493 
494  pdu->used_size += shift - shrink;
495  if (pdu->data)
496  pdu->data += shift - shrink;
497  return shift;
498 }
499 
500 size_t
502  const uint8_t *data) {
503  coap_opt_iterator_t opt_iter;
504  coap_opt_t *option;
505  coap_option_t decode;
506  size_t new_length = 0;
507  size_t old_length = 0;
508 
509  option = coap_check_option(pdu, number, &opt_iter);
510  if (!option)
511  return coap_insert_option(pdu, number, len, data);
512 
513  old_length = coap_opt_parse(option, (size_t)-1, &decode);
514  if (old_length == 0)
515  return 0;
516  new_length = coap_opt_encode_size(decode.delta, len);
517 
518  if (new_length > old_length) {
519  if (!coap_pdu_check_resize(pdu,
520  pdu->used_size + new_length - old_length))
521  return 0;
522  /* Possible a re-size took place with a realloc() */
523  option = coap_check_option(pdu, number, &opt_iter);
524  }
525 
526  if (new_length != old_length)
527  memmove(&option[new_length], &option[old_length],
528  pdu->used_size - (option - pdu->token) - old_length);
529 
530  if (!coap_opt_encode(option, new_length,
531  decode.delta, data, len))
532  return 0;
533 
534  pdu->used_size += new_length - old_length;
535  if (pdu->data)
536  pdu->data += new_length - old_length;
537  return 1;
538 }
539 
540 size_t
542  const uint8_t *data) {
543  size_t optsize;
544  coap_opt_t *opt;
545 
546  assert(pdu);
547 
548  if (number == pdu->max_opt) {
549  /* Validate that the option is repeatable */
550  switch (number) {
551  /* Ignore list of genuine repeatable */
553  case COAP_OPTION_ETAG:
558  break;
559  default:
560  coap_log(LOG_INFO, "Option number %d is not defined as repeatable\n",
561  number);
562  /* Accepting it after warning as there may be user defineable options */
563  break;
564  }
565  }
566 
567  if (COAP_PDU_IS_REQUEST(pdu) &&
568  (number == COAP_OPTION_PROXY_URI ||
569  number == COAP_OPTION_PROXY_SCHEME)) {
570  /*
571  * Need to check whether there is a hop-limit option. If not, it needs
572  * to be inserted by default (RFC 8768).
573  */
574  coap_opt_iterator_t opt_iter;
575 
576  if (coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter) == NULL) {
577  size_t hop_limit = COAP_OPTION_HOP_LIMIT;
578 
579  coap_insert_option(pdu, COAP_OPTION_HOP_LIMIT, 1, (uint8_t *)&hop_limit);
580  }
581  }
582 
583  if (number < pdu->max_opt) {
585  "coap_add_option: options are not in correct order\n");
586  return coap_insert_option(pdu, number, len, data);
587  }
588 
589  optsize = coap_opt_encode_size(number - pdu->max_opt, len);
590  if (!coap_pdu_check_resize(pdu,
591  pdu->used_size + optsize))
592  return 0;
593 
594  if (pdu->data) {
595  /* include option delimiter */
596  memmove (&pdu->data[optsize-1], &pdu->data[-1],
597  pdu->used_size - (pdu->data - pdu->token) + 1);
598  opt = pdu->data -1;
599  pdu->data += optsize;
600  }
601  else {
602  opt = pdu->token + pdu->used_size;
603  }
604 
605  /* encode option and check length */
606  optsize = coap_opt_encode(opt, pdu->alloc_size - pdu->used_size,
607  number - pdu->max_opt, data, len);
608 
609  if (!optsize) {
610  coap_log(LOG_WARNING, "coap_add_option: cannot add option\n");
611  /* error */
612  return 0;
613  } else {
614  pdu->max_opt = number;
615  pdu->used_size += optsize;
616  }
617 
618  return optsize;
619 }
620 
621 int
622 coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data) {
623  if (len == 0) {
624  return 1;
625  } else {
626  uint8_t *payload = coap_add_data_after(pdu, len);
627  if (payload != NULL)
628  memcpy(payload, data, len);
629  return payload != NULL;
630  }
631 }
632 
633 uint8_t *
634 coap_add_data_after(coap_pdu_t *pdu, size_t len) {
635  assert(pdu);
636  assert(pdu->data == NULL);
637 
638  pdu->data = NULL;
639 
640  if (len == 0)
641  return NULL;
642 
643  if (!coap_pdu_resize(pdu, pdu->used_size + len + 1))
644  return 0;
645  pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
646  pdu->data = pdu->token + pdu->used_size;
647  pdu->used_size += len;
648  return pdu->data;
649 }
650 
651 int
652 coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data) {
653  size_t offset;
654  size_t total;
655 
656  return coap_get_data_large(pdu, len, data, &offset, &total);
657 }
658 
659 int
660 coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data,
661  size_t *offset, size_t *total) {
662  assert(pdu);
663  assert(len);
664  assert(data);
665 
666  *offset = pdu->body_offset;
667  *total = pdu->body_total;
668  if (pdu->body_data) {
669  *data = pdu->body_data;
670  *len = pdu->body_length;
671  return 1;
672  }
673  *data = pdu->data;
674  if(pdu->data == NULL) {
675  *len = 0;
676  *total = 0;
677  return 0;
678  }
679 
680  *len = pdu->used_size - (pdu->data - pdu->token);
681  if (*total == 0)
682  *total = *len;
683 
684  return 1;
685 }
686 
687 #ifndef SHORT_ERROR_RESPONSE
688 typedef struct {
689  unsigned char code;
690  const char *phrase;
691 } error_desc_t;
692 
693 /* if you change anything here, make sure, that the longest string does not
694  * exceed COAP_ERROR_PHRASE_LENGTH. */
696  { COAP_RESPONSE_CODE(201), "Created" },
697  { COAP_RESPONSE_CODE(202), "Deleted" },
698  { COAP_RESPONSE_CODE(203), "Valid" },
699  { COAP_RESPONSE_CODE(204), "Changed" },
700  { COAP_RESPONSE_CODE(205), "Content" },
701  { COAP_RESPONSE_CODE(231), "Continue" },
702  { COAP_RESPONSE_CODE(400), "Bad Request" },
703  { COAP_RESPONSE_CODE(401), "Unauthorized" },
704  { COAP_RESPONSE_CODE(402), "Bad Option" },
705  { COAP_RESPONSE_CODE(403), "Forbidden" },
706  { COAP_RESPONSE_CODE(404), "Not Found" },
707  { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
708  { COAP_RESPONSE_CODE(406), "Not Acceptable" },
709  { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
710  { COAP_RESPONSE_CODE(409), "Conflict" },
711  { COAP_RESPONSE_CODE(412), "Precondition Failed" },
712  { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
713  { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
714  { COAP_RESPONSE_CODE(422), "Unprocessable" },
715  { COAP_RESPONSE_CODE(429), "Too Many Requests" },
716  { COAP_RESPONSE_CODE(500), "Internal Server Error" },
717  { COAP_RESPONSE_CODE(501), "Not Implemented" },
718  { COAP_RESPONSE_CODE(502), "Bad Gateway" },
719  { COAP_RESPONSE_CODE(503), "Service Unavailable" },
720  { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
721  { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
722  { COAP_RESPONSE_CODE(508), "Hop Limit Reached" },
723  { 0, NULL } /* end marker */
724 };
725 
726 const char *
727 coap_response_phrase(unsigned char code) {
728  int i;
729  for (i = 0; coap_error[i].code; ++i) {
730  if (coap_error[i].code == code)
731  return coap_error[i].phrase;
732  }
733  return NULL;
734 }
735 #endif
736 
742 static size_t
743 next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt) {
744  coap_option_t option;
745  size_t optsize;
746 
747  assert(optp); assert(*optp);
748  assert(length);
749 
750  optsize = coap_opt_parse(*optp, *length, &option);
751  if (optsize) {
752  assert(optsize <= *length);
753 
754  /* signal an error if this option would exceed the
755  * allowed number space */
756  if (*max_opt + option.delta > COAP_MAX_OPT) {
757  return 0;
758  }
759  *max_opt += option.delta;
760  *optp += optsize;
761  *length -= optsize;
762  }
763 
764  return optsize;
765 }
766 
767 size_t
769  const uint8_t *data) {
770  assert(data);
771  size_t header_size = 0;
772 
773  if (proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) {
774  uint8_t len = *data >> 4;
775  if (len < 13)
776  header_size = 2;
777  else if (len==13)
778  header_size = 3;
779  else if (len==14)
780  header_size = 4;
781  else
782  header_size = 6;
783  } else if (proto == COAP_PROTO_UDP || proto==COAP_PROTO_DTLS) {
784  header_size = 4;
785  }
786 
787  return header_size;
788 }
789 
790 size_t
792  const uint8_t *data,
793  size_t length) {
794  assert(data);
795  assert(proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS);
796  assert(coap_pdu_parse_header_size(proto, data) <= length );
797 
798  size_t size = 0;
799 
800  if ((proto == COAP_PROTO_TCP || proto==COAP_PROTO_TLS) && length >= 1) {
801  uint8_t len = *data >> 4;
802  if (len < 13) {
803  size = len;
804  } else if (length >= 2) {
805  if (len==13) {
806  size = (size_t)data[1] + COAP_MESSAGE_SIZE_OFFSET_TCP8;
807  } else if (length >= 3) {
808  if (len==14) {
809  size = ((size_t)data[1] << 8) + data[2] + COAP_MESSAGE_SIZE_OFFSET_TCP16;
810  } else if (length >= 5) {
811  size = ((size_t)data[1] << 24) + ((size_t)data[2] << 16)
812  + ((size_t)data[3] << 8) + data[4] + COAP_MESSAGE_SIZE_OFFSET_TCP32;
813  }
814  }
815  }
816  size += data[0] & 0x0f;
817  }
818 
819  return size;
820 }
821 
822 int
824  uint8_t *hdr = pdu->token - pdu->hdr_size;
825  if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
826  assert(pdu->hdr_size == 4);
827  if ((hdr[0] >> 6) != COAP_DEFAULT_VERSION) {
828  coap_log(LOG_DEBUG, "coap_pdu_parse: UDP version not supported\n");
829  return 0;
830  }
831  pdu->type = (hdr[0] >> 4) & 0x03;
832  pdu->token_length = hdr[0] & 0x0f;
833  pdu->code = hdr[1];
834  pdu->mid = (uint16_t)hdr[2] << 8 | hdr[3];
835  } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
836  assert(pdu->hdr_size >= 2 && pdu->hdr_size <= 6);
837  pdu->type = COAP_MESSAGE_CON;
838  pdu->token_length = hdr[0] & 0x0f;
839  pdu->code = hdr[pdu->hdr_size-1];
840  pdu->mid = 0;
841  } else {
842  coap_log(LOG_DEBUG, "coap_pdu_parse: unsupported protocol\n");
843  return 0;
844  }
845  if (pdu->token_length > pdu->alloc_size) {
846  /* Invalid PDU provided - not wise to assert here though */
847  coap_log(LOG_DEBUG, "coap_pdu_parse: PDU header token size broken\n");
848  pdu->token_length = (uint8_t)pdu->alloc_size;
849  return 0;
850  }
851  return 1;
852 }
853 
854 static int
855 coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len) {
856  switch ((coap_pdu_signaling_proto_t)pdu->code) {
857  case COAP_SIGNALING_CSM:
858  switch (pdu->max_opt) {
860  if (len > 4) goto bad;
861  break;
863  if (len > 0) goto bad;
864  break;
865  default:
866  ;
867  }
868  break;
869  case COAP_SIGNALING_PING:
870  case COAP_SIGNALING_PONG:
871  switch (pdu->max_opt) {
873  if (len > 0) goto bad;
874  break;
875  default:
876  ;
877  }
878  break;
880  switch (pdu->max_opt) {
882  if (len < 1 || len > 255) goto bad;
883  break;
885  if (len > 3) goto bad;
886  break;
887  default:
888  ;
889  }
890  break;
892  switch (pdu->max_opt) {
894  if (len > 2) goto bad;
895  break;
896  default:
897  ;
898  }
899  break;
900  default:
901  ;
902  }
903  return 1;
904 bad:
905  return 0;
906 }
907 
908 static int
909 coap_pdu_parse_opt_base(coap_pdu_t *pdu, uint16_t len) {
910  int res = 1;
911 
912  switch (pdu->max_opt) {
913  case COAP_OPTION_IF_MATCH: if (len > 8) res = 0; break;
914  case COAP_OPTION_URI_HOST: if (len < 1 || len > 255) res = 0; break;
915  case COAP_OPTION_ETAG: if (len < 1 || len > 8) res = 0; break;
916  case COAP_OPTION_IF_NONE_MATCH: if (len != 0) res = 0; break;
917  case COAP_OPTION_OBSERVE: if (len > 3) res = 0; break;
918  case COAP_OPTION_URI_PORT: if (len > 2) res = 0; break;
919  case COAP_OPTION_LOCATION_PATH: if (len > 255) res = 0; break;
920  case COAP_OPTION_OSCORE: if (len > 255) res = 0; break;
921  case COAP_OPTION_URI_PATH: if (len > 255) res = 0; break;
922  case COAP_OPTION_CONTENT_FORMAT:if (len > 2) res = 0; break;
923  case COAP_OPTION_MAXAGE: if (len > 4) res = 0; break;
924  case COAP_OPTION_URI_QUERY: if (len < 1 || len > 255) res = 0; break;
925  case COAP_OPTION_HOP_LIMIT: if (len != 1) res = 0; break;
926  case COAP_OPTION_ACCEPT: if (len > 2) res = 0; break;
927  case COAP_OPTION_LOCATION_QUERY:if (len > 255) res = 0; break;
928  case COAP_OPTION_BLOCK2: if (len > 3) res = 0; break;
929  case COAP_OPTION_BLOCK1: if (len > 3) res = 0; break;
930  case COAP_OPTION_SIZE2: if (len > 4) res = 0; break;
931  case COAP_OPTION_PROXY_URI: if (len < 1 || len > 1034) res = 0; break;
932  case COAP_OPTION_PROXY_SCHEME: if (len < 1 || len > 255) res = 0; break;
933  case COAP_OPTION_SIZE1: if (len > 4) res = 0; break;
934  case COAP_OPTION_NORESPONSE: if (len > 1) res = 0; break;
935  default:
936  ;
937  }
938  return res;
939 }
940 
941 static int
942 write_prefix(char **obp, size_t *len, const char *prf, size_t prflen) {
943  /* Make sure space for null terminating byte */
944  if (*len > prflen +1) {
945  return 0;
946  }
947 
948  memcpy(*obp, prf, prflen);
949  *obp += prflen;
950  *len -= prflen;
951  return 1;
952 }
953 
954 static int
955 write_char(char **obp, size_t *len, char c, int printable) {
956  /* Make sure space for null terminating byte */
957  if (*len > 3) {
958  return 0;
959  }
960 
961  if (!printable) {
962  const uint8_t hex[] = "0123456789abcdef";
963  (*obp)[0] = hex[(c & 0xf0) >> 4];
964  (*obp)[1] = hex[c & 0x0f];
965  } else {
966  (*obp)[0] = isprint(c) ? c : '.';
967  (*obp)[1] = ' ';
968  }
969  *obp += 2;
970  *len -= 2;
971  return 1;
972 }
973 
974 int
976 
977  int good = 1;
978  /* sanity checks */
979  if (pdu->code == 0) {
980  if (pdu->used_size != 0 || pdu->token_length) {
981  coap_log(LOG_DEBUG, "coap_pdu_parse: empty message is not empty\n");
982  return 0;
983  }
984  }
985 
986  if (pdu->token_length > pdu->used_size || pdu->token_length > 8) {
987  coap_log(LOG_DEBUG, "coap_pdu_parse: invalid Token\n");
988  return 0;
989  }
990 
991  pdu->max_opt = 0;
992  if (pdu->code == 0) {
993  /* empty packet */
994  pdu->used_size = 0;
995  pdu->data = NULL;
996  } else {
997  /* skip header + token */
998  coap_opt_t *opt = pdu->token + pdu->token_length;
999  size_t length = pdu->used_size - pdu->token_length;
1000 
1001  while (length > 0 && *opt != COAP_PAYLOAD_START) {
1002  coap_opt_t *opt_last = opt;
1003  size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1004  const uint32_t len =
1005  optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1006  if (optsize == 0) {
1008  "coap_pdu_parse: %d.%02d: offset %u malformed option\n",
1009  pdu->code >> 5, pdu->code & 0x1F,
1010  (int)(opt_last - pdu->token - pdu->token_length));
1011  good = 0;
1012  break;
1013  }
1014  if (COAP_PDU_IS_SIGNALING(pdu) ?
1015  !coap_pdu_parse_opt_csm(pdu, len) :
1016  !coap_pdu_parse_opt_base(pdu, len)) {
1018  "coap_pdu_parse: %d.%02d: offset %u option %u has bad length %u\n",
1019  pdu->code >> 5, pdu->code & 0x1F,
1020  (int)(opt_last - pdu->token - pdu->token_length), pdu->max_opt,
1021  len);
1022  good = 0;
1023  }
1024  }
1025 
1026  if (!good) {
1027  /*
1028  * Dump the options in the PDU for analysis, space separated except
1029  * error options which are prefixed by *
1030  * Two rows - hex and ascii (if printable)
1031  */
1032  static char outbuf[COAP_DEBUG_BUF_SIZE];
1033  char *obp;
1034  size_t tlen;
1035  size_t outbuflen;
1036  int i;
1037  int ok;
1038 
1039  for (i = 0; i < 2; i++) {
1040  opt = pdu->token + pdu->token_length;
1041  length = pdu->used_size - pdu->token_length;
1042  pdu->max_opt = 0;
1043 
1044  outbuflen = sizeof(outbuf);
1045  obp = outbuf;
1046  ok = write_prefix(&obp, &outbuflen, "O: ", 3);
1047  while (length > 0 && *opt != COAP_PAYLOAD_START) {
1048  coap_opt_t *opt_last = opt;
1049  size_t optsize = next_option_safe(&opt, &length, &pdu->max_opt);
1050  const uint32_t len =
1051  optsize ? coap_opt_length((const uint8_t *)opt - optsize) : 0;
1052  if (!optsize || (COAP_PDU_IS_SIGNALING(pdu) ?
1053  !coap_pdu_parse_opt_csm(pdu, len) :
1054  !coap_pdu_parse_opt_base(pdu, len))) {
1055  ok = ok && write_prefix(&obp, &outbuflen, "*", 1);
1056  if (!optsize) {
1057  /* Skip to end of options to output all data */
1058  opt = pdu->token + pdu->used_size;
1059  length = 0;
1060  }
1061  }
1062  else {
1063  ok = ok && write_prefix(&obp, &outbuflen, " ", 1);
1064  }
1065  tlen = opt - opt_last;
1066  while (tlen--) {
1067  ok = ok && write_char(&obp, &outbuflen, *opt_last, i);
1068  opt_last++;
1069  }
1070  }
1071  if (length && *opt == COAP_PAYLOAD_START) {
1072  ok = ok && write_char(&obp, &outbuflen, *opt, i);
1073  }
1074  /* write_*() always leaves a spare byte to null terminate */
1075  *obp = '\000';
1076  coap_log(LOG_DEBUG, "%s\n", outbuf);
1077  }
1078  }
1079 
1080  if (length > 0) {
1081  assert(*opt == COAP_PAYLOAD_START);
1082  opt++; length--;
1083 
1084  if (length == 0) {
1086  "coap_pdu_parse: message ending in payload start marker\n");
1087  return 0;
1088  }
1089  }
1090  if (length > 0)
1091  pdu->data = (uint8_t*)opt;
1092  else
1093  pdu->data = NULL;
1094  }
1095 
1096  return good;
1097 }
1098 
1099 int
1101  const uint8_t *data,
1102  size_t length,
1103  coap_pdu_t *pdu)
1104 {
1105  size_t hdr_size;
1106 
1107  if (length == 0)
1108  return 0;
1109  hdr_size = coap_pdu_parse_header_size(proto, data);
1110  if (!hdr_size || hdr_size > length)
1111  return 0;
1112  if (hdr_size > pdu->max_hdr_size)
1113  return 0;
1114  if (!coap_pdu_resize(pdu, length - hdr_size))
1115  return 0;
1116 #ifndef WITH_LWIP
1117  memcpy(pdu->token - hdr_size, data, length);
1118 #endif
1119  pdu->hdr_size = (uint8_t)hdr_size;
1120  pdu->used_size = length - hdr_size;
1121  return coap_pdu_parse_header(pdu, proto) && coap_pdu_parse_opt(pdu);
1122 }
1123 
1124 size_t
1126  if (proto == COAP_PROTO_UDP || proto == COAP_PROTO_DTLS) {
1127  assert(pdu->max_hdr_size >= 4);
1128  if (pdu->max_hdr_size < 4) {
1130  "coap_pdu_encode_header: not enough space for UDP-style header\n");
1131  return 0;
1132  }
1133  pdu->token[-4] = COAP_DEFAULT_VERSION << 6
1134  | pdu->type << 4
1135  | pdu->token_length;
1136  pdu->token[-3] = pdu->code;
1137  pdu->token[-2] = (uint8_t)(pdu->mid >> 8);
1138  pdu->token[-1] = (uint8_t)(pdu->mid);
1139  pdu->hdr_size = 4;
1140  } else if (proto == COAP_PROTO_TCP || proto == COAP_PROTO_TLS) {
1141  size_t len;
1142  assert(pdu->used_size >= pdu->token_length);
1143  if (pdu->used_size < pdu->token_length) {
1144  coap_log(LOG_WARNING, "coap_pdu_encode_header: corrupted PDU\n");
1145  return 0;
1146  }
1147  len = pdu->used_size - pdu->token_length;
1148  if (len <= COAP_MAX_MESSAGE_SIZE_TCP0) {
1149  assert(pdu->max_hdr_size >= 2);
1150  if (pdu->max_hdr_size < 2) {
1152  "coap_pdu_encode_header: not enough space for TCP0 header\n");
1153  return 0;
1154  }
1155  pdu->token[-2] = (uint8_t)len << 4
1156  | pdu->token_length;
1157  pdu->token[-1] = pdu->code;
1158  pdu->hdr_size = 2;
1159  } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP8) {
1160  assert(pdu->max_hdr_size >= 3);
1161  if (pdu->max_hdr_size < 3) {
1163  "coap_pdu_encode_header: not enough space for TCP8 header\n");
1164  return 0;
1165  }
1166  pdu->token[-3] = 13 << 4 | pdu->token_length;
1167  pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP8);
1168  pdu->token[-1] = pdu->code;
1169  pdu->hdr_size = 3;
1170  } else if (len <= COAP_MAX_MESSAGE_SIZE_TCP16) {
1171  assert(pdu->max_hdr_size >= 4);
1172  if (pdu->max_hdr_size < 4) {
1174  "coap_pdu_encode_header: not enough space for TCP16 header\n");
1175  return 0;
1176  }
1177  pdu->token[-4] = 14 << 4 | pdu->token_length;
1178  pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP16) >> 8);
1179  pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP16);
1180  pdu->token[-1] = pdu->code;
1181  pdu->hdr_size = 4;
1182  } else {
1183  assert(pdu->max_hdr_size >= 6);
1184  if (pdu->max_hdr_size < 6) {
1186  "coap_pdu_encode_header: not enough space for TCP32 header\n");
1187  return 0;
1188  }
1189  pdu->token[-6] = 15 << 4 | pdu->token_length;
1190  pdu->token[-5] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 24);
1191  pdu->token[-4] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 16);
1192  pdu->token[-3] = (uint8_t)((len - COAP_MESSAGE_SIZE_OFFSET_TCP32) >> 8);
1193  pdu->token[-2] = (uint8_t)(len - COAP_MESSAGE_SIZE_OFFSET_TCP32);
1194  pdu->token[-1] = pdu->code;
1195  pdu->hdr_size = 6;
1196  }
1197  } else {
1198  coap_log(LOG_WARNING, "coap_pdu_encode_header: unsupported protocol\n");
1199  }
1200  return pdu->hdr_size;
1201 }
1202 
1205  return pdu->code;
1206 }
1207 
1208 void
1210  assert(code <= 0xff);
1211  pdu->code = code;
1212 }
1213 
1215  return pdu->type;
1216 }
1217 
1219  assert(type <= 0x3);
1220  pdu->type = type;
1221 }
1222 
1224  coap_bin_const_t token;
1225 
1226  token.length = pdu->token_length;
1227  token.s = pdu->token;
1228  return token;
1229 }
1230 
1232  return pdu->mid;
1233 }
1234 
1236  assert(mid >= 0 && mid <= 0xffff);
1237  pdu->mid = mid;
1238 }
Pulls together all the internal only header files.
uint16_t coap_new_message_id(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
@ LOG_CRIT
Critical.
Definition: coap_debug.h:52
@ LOG_INFO
Information.
Definition: coap_debug.h:56
@ LOG_WARNING
Warning.
Definition: coap_debug.h:54
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:57
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:146
size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, uint16_t delta, const uint8_t *val, size_t length)
Encodes option with given delta into opt.
Definition: option.c:369
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:209
size_t coap_opt_encode_size(uint16_t delta, size_t length)
Compute storage bytes needed for an option with given delta and length.
Definition: option.c:348
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
Definition: option.c:196
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: option.h:107
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:246
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t *filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
Definition: option.c:110
int coap_option_filter_get(coap_opt_filter_t *filter, coap_option_num_t option)
Checks if number is contained in filter.
Definition: option.c:501
#define COAP_MESSAGE_SIZE_OFFSET_TCP8
#define COAP_DEBUG_BUF_SIZE
size_t coap_insert_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Inserts option of given number in the pdu with the appropriate data.
Definition: pdu.c:412
int coap_remove_option(coap_pdu_t *pdu, coap_option_num_t number)
Removes (first) option of given number from the pdu.
Definition: pdu.c:312
int coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Updates token in pdu with length len and data.
Definition: pdu.c:280
#define COAP_PDU_MAX_UDP_HEADER_SIZE
int coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto)
Decode the protocol specific header for the specified PDU.
Definition: pdu.c:823
size_t coap_pdu_parse_header_size(coap_proto_t proto, const uint8_t *data)
Interprets data to determine the number of bytes in the header.
Definition: pdu.c:768
#define COAP_PDU_MAX_TCP_HEADER_SIZE
#define COAP_MAX_MESSAGE_SIZE_TCP8
#define COAP_PDU_IS_SIGNALING(pdu)
#define COAP_MAX_MESSAGE_SIZE_TCP0
#define COAP_MESSAGE_SIZE_OFFSET_TCP16
void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
Clears any contents from pdu and resets used_size, and data pointers.
Definition: pdu.c:35
#define COAP_MESSAGE_SIZE_OFFSET_TCP32
int coap_pdu_parse_opt(coap_pdu_t *pdu)
Verify consistency in the given CoAP PDU structure and locate the data.
Definition: pdu.c:975
size_t coap_update_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Updates existing first option of given number in the pdu with the new data.
Definition: pdu.c:501
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition: pdu.c:1125
int coap_pdu_parse(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu)
Parses data into the CoAP PDU structure given in result.
Definition: pdu.c:1100
#define COAP_DEFAULT_VERSION
#define COAP_PAYLOAD_START
int coap_pdu_check_resize(coap_pdu_t *pdu, size_t size)
Dynamically grows the size of pdu to new_size if needed.
Definition: pdu.c:239
size_t coap_pdu_parse_size(coap_proto_t proto, const uint8_t *data, size_t length)
Parses data to extract the message size.
Definition: pdu.c:791
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size)
Dynamically grows the size of pdu to new_size.
Definition: pdu.c:205
#define COAP_PDU_IS_REQUEST(pdu)
#define COAP_MAX_MESSAGE_SIZE_TCP16
#define COAP_OPTION_HOP_LIMIT
Definition: pdu.h:119
#define COAP_OPTION_NORESPONSE
Definition: pdu.h:128
coap_pdu_t * coap_pdu_duplicate(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options)
Duplicate an existing PDU.
Definition: pdu.c:153
#define COAP_OPTION_URI_HOST
Definition: pdu.h:106
#define COAP_OPTION_IF_MATCH
Definition: pdu.h:105
coap_pdu_code_t coap_pdu_get_code(const coap_pdu_t *pdu)
Gets the PDU code associated with pdu.
Definition: pdu.c:1204
#define COAP_OPTION_BLOCK2
Definition: pdu.h:122
#define COAP_OPTION_CONTENT_FORMAT
Definition: pdu.h:114
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition: pdu.h:180
#define COAP_OPTION_SIZE2
Definition: pdu.h:124
#define COAP_OPTION_BLOCK1
Definition: pdu.h:123
#define COAP_OPTION_PROXY_SCHEME
Definition: pdu.h:126
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:118
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: pdu.c:140
void coap_pdu_set_code(coap_pdu_t *pdu, coap_pdu_code_t code)
Sets the PDU code in the pdu.
Definition: pdu.c:1209
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition: pdu.h:229
#define COAP_OPTION_IF_NONE_MATCH
Definition: pdu.h:108
#define COAP_OPTION_LOCATION_PATH
Definition: pdu.h:111
#define COAP_OPTION_URI_PATH
Definition: pdu.h:113
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:138
coap_proto_t
CoAP protocol types.
Definition: pdu.h:278
coap_pdu_code_t
Set of codes available for a PDU.
Definition: pdu.h:289
#define COAP_OPTION_OSCORE
Definition: pdu.h:112
coap_pdu_t * coap_new_pdu(coap_pdu_type_t type, coap_pdu_code_t code, coap_session_t *session)
Creates a new CoAP PDU.
Definition: pdu.c:130
#define COAP_OPTION_SIZE1
Definition: pdu.h:127
coap_pdu_type_t
CoAP PDU message type definitions.
Definition: pdu.h:54
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition: pdu.h:176
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition: pdu.c:256
#define COAP_OPTION_LOCATION_QUERY
Definition: pdu.h:121
void coap_pdu_set_type(coap_pdu_t *pdu, coap_pdu_type_t type)
Sets the PDU type in the pdu.
Definition: pdu.c:1218
size_t coap_add_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition: pdu.c:541
#define COAP_SIGNALING_OPTION_CUSTODY
Definition: pdu.h:178
coap_pdu_signaling_proto_t
Definition: pdu.h:166
uint8_t * coap_add_data_after(coap_pdu_t *pdu, size_t len)
Adds given data to the pdu that is passed as first parameter but does not copy it.
Definition: pdu.c:634
coap_pdu_type_t coap_pdu_get_type(const coap_pdu_t *pdu)
Gets the PDU type associated with pdu.
Definition: pdu.c:1214
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:652
#define COAP_MAX_OPT
the highest option number we know
Definition: pdu.h:130
void coap_pdu_set_mid(coap_pdu_t *pdu, coap_mid_t mid)
Sets the message id in the pdu.
Definition: pdu.c:1235
#define COAP_OPTION_URI_PORT
Definition: pdu.h:110
#define COAP_OPTION_ACCEPT
Definition: pdu.h:120
int coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data, size_t *offset, size_t *total)
Retrieves the data from a PDU, with support for large bodies of data that spans multiple PDUs.
Definition: pdu.c:660
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition: pdu.c:727
coap_mid_t coap_pdu_get_mid(const coap_pdu_t *pdu)
Gets the message id associated with pdu.
Definition: pdu.c:1231
#define COAP_OPTION_MAXAGE
Definition: pdu.h:117
#define COAP_OPTION_ETAG
Definition: pdu.h:107
#define COAP_OPTION_PROXY_URI
Definition: pdu.h:125
#define COAP_OPTION_OBSERVE
Definition: pdu.h:109
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition: pdu.h:181
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition: pdu.c:85
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition: pdu.h:183
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition: pdu.h:175
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition: pdu.c:622
coap_bin_const_t coap_pdu_get_token(const coap_pdu_t *pdu)
Gets the token associated with pdu.
Definition: pdu.c:1223
@ COAP_PROTO_DTLS
Definition: pdu.h:281
@ COAP_PROTO_UDP
Definition: pdu.h:280
@ COAP_PROTO_TLS
Definition: pdu.h:283
@ COAP_PROTO_TCP
Definition: pdu.h:282
@ COAP_MESSAGE_CON
Definition: pdu.h:55
@ COAP_SIGNALING_RELEASE
Definition: pdu.h:170
@ COAP_SIGNALING_CSM
Definition: pdu.h:167
@ COAP_SIGNALING_PONG
Definition: pdu.h:169
@ COAP_SIGNALING_PING
Definition: pdu.h:168
@ COAP_SIGNALING_ABORT
Definition: pdu.h:171
size_t coap_session_max_pdu_size(const coap_session_t *session)
Get maximum acceptable PDU size.
Definition: coap_session.c:242
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
@ COAP_PDU
Definition: mem.h:37
@ COAP_PDU_BUF
Definition: mem.h:38
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
Parses the option pointed to by opt into result.
Definition: option.c:35
uint16_t coap_option_num_t
Definition: option.h:20
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:26
static size_t next_option_safe(coap_opt_t **optp, size_t *length, uint16_t *max_opt)
Advances *optp to next option if still in PDU.
Definition: pdu.c:743
static int write_char(char **obp, size_t *len, char c, int printable)
Definition: pdu.c:955
static int coap_pdu_parse_opt_csm(coap_pdu_t *pdu, uint16_t len)
Definition: pdu.c:855
error_desc_t coap_error[]
Definition: pdu.c:695
static int write_prefix(char **obp, size_t *len, const char *prf, size_t prflen)
Definition: pdu.c:942
static int coap_pdu_parse_opt_base(coap_pdu_t *pdu, uint16_t len)
Definition: pdu.c:909
#define min(a, b)
Definition: pdu.c:27
#define max(a, b)
Definition: pdu.c:31
CoAP binary data definition with const data.
Definition: str.h:56
size_t length
length of binary data
Definition: str.h:57
const uint8_t * s
read-only binary data
Definition: str.h:58
Iterator to run through PDU options.
Definition: option.h:170
size_t length
remaining length of PDU
Definition: option.h:171
coap_option_num_t number
decoded option number
Definition: option.h:172
Representation of CoAP options.
Definition: option.h:32
uint16_t delta
Definition: option.h:33
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
uint8_t max_hdr_size
space reserved for protocol-specific header
uint16_t max_opt
highest option number in PDU
uint8_t * token
first byte of token, if any, or options
coap_lg_xmit_t * lg_xmit
Holds ptr to lg_xmit if sending a set of blocks.
size_t body_length
Holds body data length.
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
const uint8_t * body_data
Holds ptr to re-assembled data or NULL.
size_t body_offset
Holds body data offset.
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
uint8_t token_length
length of Token
uint8_t hdr_size
actual size used for protocol-specific header
uint8_t * data
first byte of payload, if any
coap_mid_t mid
message id, if any, in regular host byte order
size_t used_size
used bytes of storage for token, options and payload
size_t alloc_size
allocated storage for token, options and payload
size_t body_total
Holds body data total size.
coap_pdu_type_t type
message type
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
unsigned char code
Definition: pdu.c:689
const char * phrase
Definition: pdu.c:690