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