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