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