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
36void
37coap_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
61coap_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
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) {
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) {
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
133 coap_session_t *session) {
134 coap_pdu_t *pdu = coap_pdu_init(type, code, coap_new_message_id(session),
136 if (!pdu)
137 coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
138 return pdu;
139}
140
141void
143 if (pdu != NULL) {
144#ifdef WITH_LWIP
145 pbuf_free(pdu->pbuf);
146#else
147 if (pdu->token != NULL)
149#endif
151 }
152}
153
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),
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
201fail:
202 coap_delete_pdu(pdu);
203 return NULL;
204}
205
206int
207coap_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
240int
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
257int
258coap_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 */
281int
282coap_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
313int
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 */
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 */
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
413size_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 */
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 */
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
502size_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
542size_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
623int
624coap_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
635uint8_t *
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
653int
654coap_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
661int
662coap_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
690typedef struct {
691 unsigned char code;
692 const char *phrase;
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
728const char *
729coap_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
744static size_t
745next_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
769size_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
792size_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
824int
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
856static int
858 switch ((coap_pdu_signaling_proto_t)pdu->code) {
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;
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;
906bad:
907 return 0;
908}
909
910static int
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
943static int
944write_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
956static int
957write_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
976int
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
1101int
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
1126size_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
1210void
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
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
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
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: option.h:107
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
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
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
#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
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition: pdu.c:729
#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
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
#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_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
coap_pdu_code_t
Set of codes available for a PDU.
Definition: pdu.h:291
#define COAP_OPTION_OSCORE
Definition: pdu.h:114
#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
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
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_PORT
Definition: pdu.h:112
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_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
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
#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
@ COAP_PDU
Definition: mem.h:39
@ COAP_PDU_BUF
Definition: mem.h:40
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.
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