Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / libcoap-4.1.1 / pdu.c
1 /* pdu.c -- CoAP message structure
2  *
3  * Copyright (C) 2010,2011 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 "config.h"
10
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <limits.h>
19 #ifdef HAVE_ARPA_INET_H
20 #include <arpa/inet.h>
21 #endif
22
23 #include "debug.h"
24 #include "pdu.h"
25 #include "option.h"
26 #include "encode.h"
27
28 #ifdef WITH_ARDUINO
29 #include "util.h"
30 #endif
31
32 #ifdef WITH_CONTIKI
33 #include "memb.h"
34
35 #ifndef WITH_TCP
36 typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
37
38 MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
39 #endif
40
41 void
42 coap_pdu_resources_init()
43 {
44     memb_init(&pdu_storage);
45 }
46 #else /* WITH_CONTIKI */
47 #include "mem.h"
48 #endif /* WITH_CONTIKI */
49
50 void coap_pdu_clear(coap_pdu_t *pdu, size_t size, coap_transport_type transport, unsigned int length)
51 {
52     assert(pdu);
53
54     memset(pdu, 0, sizeof(coap_pdu_t) + size);
55     pdu->max_size = size;
56     pdu->hdr = (coap_hdr_t *) ((unsigned char *) pdu + sizeof(coap_pdu_t));
57
58     if (coap_udp == transport)
59     {
60         pdu->hdr->coap_hdr_udp_t.version = COAP_DEFAULT_VERSION;
61         /* data is NULL unless explicitly set by coap_add_data() */
62         pdu->length = sizeof(pdu->hdr->coap_hdr_udp_t);
63     }
64 #ifdef WITH_TCP
65     else
66     {
67         /* data is NULL unless explicitly set by coap_add_data() */
68         pdu->length = length;
69     }
70 #endif
71 }
72
73 #ifdef WITH_LWIP
74 coap_pdu_t *
75 coap_pdu_from_pbuf(struct pbuf *pbuf)
76 {
77     LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
78     LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
79
80     void *data = pbuf->payload;
81     coap_pdu_t *result;
82
83     u8_t header_error = pbuf_header(pbuf, sizeof(coap_pdu_t));
84     LWIP_ASSERT("CoAP PDU header does not fit in existing header space", header_error == 0);
85
86     result = (coap_pdu_t *)pbuf->payload;
87
88     memset(result, 0, sizeof(coap_pdu_t));
89
90     result->max_size = pbuf->tot_len - sizeof(coap_pdu_t);
91     result->length = pbuf->tot_len - sizeof(coap_pdu_t);
92     result->hdr = data;
93     result->pbuf = pbuf;
94
95     return result;
96 }
97 #endif
98
99 coap_pdu_t *
100 coap_pdu_init(unsigned char type, unsigned char code, unsigned short id,
101               size_t size, coap_transport_type transport)
102 {
103     coap_pdu_t *pdu;
104 #ifdef WITH_LWIP
105     struct pbuf *p;
106 #endif
107
108     unsigned int length = 0;
109     switch(transport)
110     {
111         case coap_udp:
112             length = sizeof(pdu->hdr->coap_hdr_udp_t);
113             break;
114 #ifdef WITH_TCP
115         case coap_tcp:
116             length = COAP_TCP_HEADER_NO_FIELD;
117             break;
118         case coap_tcp_8bit:
119             length = COAP_TCP_HEADER_8_BIT;
120             break;
121         case coap_tcp_16bit:
122             length = COAP_TCP_HEADER_16_BIT;
123             break;
124         case coap_tcp_32bit:
125             length = COAP_TCP_HEADER_32_BIT;
126             break;
127 #endif
128         default:
129             debug("it has wrong type\n");
130     }
131
132 #ifndef WITH_TCP
133     assert(size <= COAP_MAX_PDU_SIZE);
134     /* Size must be large enough to fit the header. */
135     if (size < length || size > COAP_MAX_PDU_SIZE)
136         return NULL;
137 #endif
138
139     /* size must be large enough for hdr */
140 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
141     pdu = (coap_pdu_t *) coap_malloc(sizeof(coap_pdu_t) + size);
142 #endif
143 #ifdef WITH_CONTIKI
144     pdu = (coap_pdu_t *)memb_alloc(&pdu_storage);
145 #endif
146 #ifdef WITH_LWIP
147     p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
148     if (p != NULL)
149     {
150         u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t));
151         /* we could catch that case and allocate larger memory in advance, but then
152          * again, we'd run into greater trouble with incoming packages anyway */
153         LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0);
154         pdu = p->payload;
155     }
156     else
157     {
158         pdu = NULL;
159     }
160 #endif
161     if (pdu)
162     {
163         coap_pdu_clear(pdu, size, transport, length);
164
165         switch(transport)
166         {
167             case coap_udp:
168                 pdu->hdr->coap_hdr_udp_t.id = id;
169                 pdu->hdr->coap_hdr_udp_t.type = type;
170                 pdu->hdr->coap_hdr_udp_t.code = code;
171                 break;
172 #ifdef WITH_TCP
173             case coap_tcp:
174                 pdu->hdr->coap_hdr_tcp_t.header_data[0] = 0;
175                 pdu->hdr->coap_hdr_tcp_t.header_data[1] = code;
176                 break;
177             case coap_tcp_8bit:
178                 pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_8_BIT << 4;
179                 pdu->hdr->coap_hdr_tcp_8bit_t.header_data[2] = code;
180                 break;
181             case coap_tcp_16bit:
182                 pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_16_BIT << 4;
183                 pdu->hdr->coap_hdr_tcp_16bit_t.header_data[3] = code;
184                 break;
185             case coap_tcp_32bit:
186                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_32_BIT << 4;
187                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5] = code;
188                 break;
189 #endif
190             default:
191                 debug("it has wrong type\n");
192         }
193
194 #ifdef WITH_LWIP
195         pdu->pbuf = p;
196 #endif
197     }
198     return pdu;
199 }
200
201 coap_pdu_t *
202 coap_new_pdu(coap_transport_type transport, unsigned int size)
203 {
204     coap_pdu_t *pdu;
205
206 #ifndef WITH_CONTIKI
207     pdu = coap_pdu_init(0, 0,
208                         ntohs(COAP_INVALID_TID),
209 #ifndef WITH_TCP
210                         COAP_MAX_PDU_SIZE,
211 #else
212                         size,
213 #endif
214                         transport);
215 #else /* WITH_CONTIKI */
216     pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID),
217 #ifndef WITH_TCP
218                         COAP_MAX_PDU_SIZE,
219 #else
220                         size,
221 #endif
222                         transport);
223 #endif /* WITH_CONTIKI */
224
225 #ifndef NDEBUG
226     if (!pdu)
227         coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
228 #endif
229     return pdu;
230 }
231
232 void coap_delete_pdu(coap_pdu_t *pdu)
233 {
234 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
235     coap_free( pdu );
236 #endif
237 #ifdef WITH_LWIP
238     if (pdu != NULL) /* accepting double free as the other implementation accept that too */
239         pbuf_free(pdu->pbuf);
240 #endif
241 #ifdef WITH_CONTIKI
242     memb_free(&pdu_storage, pdu);
243 #endif
244 }
245
246 #ifdef WITH_TCP
247 size_t coap_get_total_message_length(const unsigned char *data, size_t size)
248 {
249     if (!data || !size)
250     {
251         debug("received data length is null\n");
252         return 0;
253     }
254
255     coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
256             ((unsigned char *)data)[0] >> 4);
257     size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)data,
258                                                         transport);
259     size_t headerLen = coap_get_tcp_header_length((unsigned char *)data);
260
261     return headerLen + optPaylaodLen;
262 }
263
264 coap_transport_type coap_get_tcp_header_type_from_size(unsigned int size)
265 {
266     if (size < COAP_TCP_LENGTH_FIELD_8_BIT)
267     {
268         return coap_tcp;
269     }
270     else if (size < COAP_TCP_LENGTH_FIELD_16_BIT)
271     {
272         return coap_tcp_8bit;
273     }
274     else if (size < COAP_TCP_LENGTH_FIELD_32_BIT)
275     {
276         return coap_tcp_16bit;
277     }
278     else if (size < ULONG_MAX + COAP_TCP_LENGTH_FIELD_32_BIT)
279     {
280         return coap_tcp_32bit;
281     }
282
283     return -1;
284 }
285
286 coap_transport_type coap_get_tcp_header_type_from_initbyte(unsigned int length)
287 {
288     coap_transport_type type;
289     switch(length)
290     {
291         case COAP_TCP_LENGTH_FIELD_NUM_8_BIT:
292             type = coap_tcp_8bit;
293             break;
294         case COAP_TCP_LENGTH_FIELD_NUM_16_BIT:
295             type = coap_tcp_16bit;
296             break;
297         case COAP_TCP_LENGTH_FIELD_NUM_32_BIT:
298             type = coap_tcp_32bit;
299             break;
300         default:
301             type = coap_tcp;
302     }
303     return type;
304 }
305
306 void coap_add_length(const coap_pdu_t *pdu, coap_transport_type transport, unsigned int length)
307 {
308     assert(pdu);
309
310     switch(transport)
311     {
312         case coap_tcp:
313             pdu->hdr->coap_hdr_tcp_t.header_data[0] = length << 4;
314             break;
315         case coap_tcp_8bit:
316             if (length > COAP_TCP_LENGTH_FIELD_8_BIT)
317             {
318                 pdu->hdr->coap_hdr_tcp_8bit_t.header_data[1] =
319                         length - COAP_TCP_LENGTH_FIELD_8_BIT;
320             }
321             break;
322         case coap_tcp_16bit:
323             if (length > COAP_TCP_LENGTH_FIELD_16_BIT)
324             {
325                 unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_16_BIT;
326                 pdu->hdr->coap_hdr_tcp_16bit_t.header_data[1] = (total_length >> 8) & 0x0000ff;
327                 pdu->hdr->coap_hdr_tcp_16bit_t.header_data[2] = total_length & 0x000000ff;
328             }
329             break;
330         case coap_tcp_32bit:
331             if (length > COAP_TCP_LENGTH_FIELD_32_BIT)
332             {
333                 unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_32_BIT;
334                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[1] = total_length >> 24;
335                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[2] = (total_length >> 16) & 0x00ff;
336                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[3] = (total_length >> 8) & 0x0000ff;
337                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[4] = total_length & 0x000000ff;
338             }
339             break;
340         default:
341             debug("it has wrong type\n");
342     }
343 }
344
345 unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_type transport)
346 {
347     assert(header);
348
349     unsigned int length = 0;
350     unsigned int length_field_data = 0;
351     switch(transport)
352     {
353         case coap_tcp:
354             length = header[0] >> 4;
355             break;
356         case coap_tcp_8bit:
357             length = header[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
358             break;
359         case coap_tcp_16bit:
360             length_field_data = (header[1] << 8 | header[2]);
361             length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
362             break;
363         case coap_tcp_32bit:
364             length_field_data = header[1] << 24 | header[2] << 16 | header[3] << 8 | header[4];
365             length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
366             break;
367         default:
368             debug("it has wrong type\n");
369     }
370
371     return length;
372 }
373
374 unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_type transport)
375 {
376     assert(pdu);
377
378     unsigned int length = 0;
379     unsigned int length_field_data = 0;
380     switch(transport)
381     {
382         case coap_tcp:
383             length = pdu->hdr->coap_hdr_tcp_t.header_data[0] >> 4;
384             break;
385         case coap_tcp_8bit:
386             length = pdu->hdr->coap_hdr_tcp_8bit_t.header_data[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
387             break;
388         case coap_tcp_16bit:
389             length_field_data =
390                     pdu->hdr->coap_hdr_tcp_16bit_t.header_data[1] << 8 |
391                     pdu->hdr->coap_hdr_tcp_16bit_t.header_data[2];
392             length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
393             break;
394         case coap_tcp_32bit:
395             length_field_data =
396                     pdu->hdr->coap_hdr_tcp_32bit_t.header_data[1] << 24 |
397                     pdu->hdr->coap_hdr_tcp_32bit_t.header_data[2] << 16 |
398                     pdu->hdr->coap_hdr_tcp_32bit_t.header_data[3] << 8 |
399                     pdu->hdr->coap_hdr_tcp_32bit_t.header_data[4];
400             length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
401             break;
402         default:
403             debug("it has wrong type\n");
404     }
405
406     return length;
407 }
408
409 unsigned int coap_get_tcp_header_length(unsigned char *data)
410 {
411     assert(data);
412
413     unsigned int tokenLength =  data[0] & 0x0f;
414     coap_transport_type transport =
415             coap_get_tcp_header_type_from_initbyte(data[0] >> 4);
416     unsigned int length = 0;
417
418     length = coap_get_tcp_header_length_for_transport(transport) + tokenLength;
419     return length;
420 }
421
422 unsigned int coap_get_tcp_header_length_for_transport(coap_transport_type transport)
423 {
424     unsigned int length = 0;
425     switch(transport)
426     {
427         case coap_tcp:
428             length = COAP_TCP_HEADER_NO_FIELD;
429             break;
430         case coap_tcp_8bit:
431             length = COAP_TCP_HEADER_8_BIT;
432             break;
433         case coap_tcp_16bit:
434             length = COAP_TCP_HEADER_16_BIT;
435             break;
436         case coap_tcp_32bit:
437             length = COAP_TCP_HEADER_32_BIT;
438             break;
439         default:
440             debug("it has wrong type\n");
441     }
442
443     return length;
444 }
445
446 size_t coap_get_opt_header_length(unsigned short key, size_t length)
447 {
448     size_t headerLength = 0;
449
450     unsigned short optDeltaLength = 0;
451     if (COAP_OPTION_FIELD_8_BIT >= key)
452     {
453         optDeltaLength = 0;
454     }
455     else if (COAP_OPTION_FIELD_8_BIT < key && COAP_OPTION_FIELD_16_BIT >= key)
456     {
457         optDeltaLength = 1;
458     }
459     else
460     {
461         optDeltaLength = 2;
462     }
463
464     size_t optLength = 0;
465     if (COAP_OPTION_FIELD_8_BIT >= length)
466     {
467         optLength = 0;
468     }
469     else if (COAP_OPTION_FIELD_8_BIT < length && COAP_OPTION_FIELD_16_BIT >= length)
470     {
471         optLength = 1;
472     }
473     else if (COAP_OPTION_FIELD_16_BIT < length && COAP_OPTION_FIELD_32_BIT >= length)
474     {
475         optLength = 2;
476     }
477     else
478     {
479         printf("Error : Reserved for the Payload marker for length");
480         return 0;
481     }
482
483     headerLength = length + optDeltaLength + optLength + 1;
484
485     return headerLength;
486 }
487
488 #endif
489
490 void coap_add_code(const coap_pdu_t *pdu, coap_transport_type transport, unsigned int code)
491 {
492     assert(pdu);
493
494     switch(transport)
495     {
496         case coap_udp:
497             pdu->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(code);
498             break;
499 #ifdef WITH_TCP
500         case coap_tcp:
501             pdu->hdr->coap_hdr_tcp_t.header_data[1] = COAP_RESPONSE_CODE(code);
502             break;
503         case coap_tcp_8bit:
504             pdu->hdr->coap_hdr_tcp_8bit_t.header_data[2] = COAP_RESPONSE_CODE(code);
505             break;
506         case coap_tcp_16bit:
507             pdu->hdr->coap_hdr_tcp_16bit_t.header_data[3] = COAP_RESPONSE_CODE(code);
508             break;
509         case coap_tcp_32bit:
510             pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5] = COAP_RESPONSE_CODE(code);
511             break;
512 #endif
513         default:
514             debug("it has wrong type\n");
515     }
516 }
517
518 unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_type transport)
519 {
520     assert(pdu);
521
522     unsigned int code = 0;
523     switch(transport)
524     {
525         case coap_udp:
526             code = pdu->hdr->coap_hdr_udp_t.code;
527             break;
528 #ifdef WITH_TCP
529         case coap_tcp:
530             code = pdu->hdr->coap_hdr_tcp_t.header_data[1];
531             break;
532         case coap_tcp_8bit:
533             code = pdu->hdr->coap_hdr_tcp_8bit_t.header_data[2];
534             break;
535         case coap_tcp_16bit:
536             code = pdu->hdr->coap_hdr_tcp_16bit_t.header_data[3];
537             break;
538         case coap_tcp_32bit:
539             code = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5];
540             break;
541 #endif
542         default:
543             debug("it has wrong type\n");
544     }
545     return code;
546 }
547
548 int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data,
549                    coap_transport_type transport)
550 {
551     const size_t HEADERLENGTH = len + 4;
552     /* must allow for pdu == NULL as callers may rely on this */
553     if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
554         return 0;
555
556     unsigned char* token = NULL;
557     switch(transport)
558     {
559         case coap_udp:
560             pdu->hdr->coap_hdr_udp_t.token_length = len;
561             token = pdu->hdr->coap_hdr_udp_t.token;
562             pdu->length = HEADERLENGTH;
563             break;
564 #ifdef WITH_TCP
565         case coap_tcp:
566             pdu->hdr->coap_hdr_tcp_t.header_data[0] =
567                     pdu->hdr->coap_hdr_tcp_t.header_data[0] | len;
568             token = pdu->hdr->coap_hdr_tcp_t.token;
569             pdu->length = len + COAP_TCP_HEADER_NO_FIELD;
570             break;
571         case coap_tcp_8bit:
572             pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0] =
573                     pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0] | len;
574             token = pdu->hdr->coap_hdr_tcp_8bit_t.token;
575             pdu->length = len + COAP_TCP_HEADER_8_BIT;
576             break;
577         case coap_tcp_16bit:
578             pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0] =
579                     pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0] | len;
580             token = pdu->hdr->coap_hdr_tcp_16bit_t.token;
581             pdu->length = len + COAP_TCP_HEADER_16_BIT;
582             break;
583         case coap_tcp_32bit:
584             pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] =
585                     pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] | len;
586             token = pdu->hdr->coap_hdr_tcp_32bit_t.token;
587             pdu->length = len + COAP_TCP_HEADER_32_BIT;
588             break;
589 #endif
590         default:
591             debug("it has wrong type\n");
592     }
593
594     if (len)
595     {
596         memcpy(token, data, len);
597     }
598
599     pdu->max_delta = 0;
600     pdu->data = NULL;
601
602     return 1;
603 }
604
605 void coap_get_token(const coap_hdr_t *pdu_hdr, coap_transport_type transport,
606                     unsigned char **token, unsigned int *token_length)
607 {
608     assert(pdu_hdr);
609     assert(token);
610     assert(token_length);
611
612     switch(transport)
613     {
614         case coap_udp:
615             *token_length = pdu_hdr->coap_hdr_udp_t.token_length;
616             *token = (unsigned char *)pdu_hdr->coap_hdr_udp_t.token;
617             break;
618 #ifdef WITH_TCP
619         case coap_tcp:
620             *token_length = (pdu_hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f;
621             *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_t.token;
622             break;
623         case coap_tcp_8bit:
624             *token_length = (pdu_hdr->coap_hdr_tcp_8bit_t.header_data[0]) & 0x0f;
625             *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_8bit_t.token;
626             break;
627         case coap_tcp_16bit:
628             *token_length = (pdu_hdr->coap_hdr_tcp_16bit_t.header_data[0]) & 0x0f;
629             *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_16bit_t.token;
630             break;
631         case coap_tcp_32bit:
632             *token_length = (pdu_hdr->coap_hdr_tcp_32bit_t.header_data[0]) & 0x0f;
633             *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_32bit_t.token;
634             break;
635 #endif
636         default:
637             debug("it has wrong type\n");
638     }
639 }
640
641 /** @FIXME de-duplicate code with coap_add_option_later */
642 size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
643         const unsigned char *data, coap_transport_type transport)
644 {
645     size_t optsize;
646     coap_opt_t *opt;
647
648     assert(pdu);
649     pdu->data = NULL;
650
651     if (type < pdu->max_delta)
652     {
653         warn("coap_add_option: options are not in correct order\n");
654         return 0;
655     }
656
657     switch(transport)
658     {
659 #ifdef WITH_TCP
660         case coap_tcp:
661             opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length;
662             break;
663         case coap_tcp_8bit:
664             opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_8bit_t) + pdu->length;
665             break;
666         case coap_tcp_16bit:
667             opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_16bit_t) + pdu->length;
668             break;
669         case coap_tcp_32bit:
670             opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_32bit_t) + pdu->length;
671             break;
672 #endif
673         default:
674             opt = (unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length;
675             break;
676     }
677
678     /* encode option and check length */
679     optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
680
681     if (!optsize)
682     {
683         warn("coap_add_option: cannot add option\n");
684         /* error */
685         return 0;
686     }
687     else
688     {
689         pdu->max_delta = type;
690         pdu->length += optsize;
691     }
692
693     return optsize;
694 }
695
696 /** @FIXME de-duplicate code with coap_add_option */
697 unsigned char*
698 coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
699 {
700     size_t optsize;
701     coap_opt_t *opt;
702
703     assert(pdu);
704     pdu->data = NULL;
705
706     if (type < pdu->max_delta)
707     {
708         warn("coap_add_option: options are not in correct order\n");
709         return NULL;
710     }
711
712     opt = (unsigned char *) pdu->hdr + pdu->length;
713
714     /* encode option and check length */
715     optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, NULL, len);
716
717     if (!optsize)
718     {
719         warn("coap_add_option: cannot add option\n");
720         /* error */
721         return NULL;
722     }
723     else
724     {
725         pdu->max_delta = type;
726         pdu->length += optsize;
727     }
728
729     return ((unsigned char*) opt) + optsize - len;
730 }
731
732 int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
733 {
734     assert(pdu);
735     assert(pdu->data == NULL);
736
737     if (len == 0)
738         return 1;
739
740     if (pdu->length + len + 1 > pdu->max_size)
741     {
742         warn("coap_add_data: cannot add: data too large for PDU\n");
743         assert(pdu->data == NULL);
744         return 0;
745     }
746
747     pdu->data = (unsigned char *) pdu->hdr + pdu->length;
748     *pdu->data = COAP_PAYLOAD_START;
749     pdu->data++;
750
751     memcpy(pdu->data, data, len);
752     pdu->length += len + 1;
753     return 1;
754 }
755
756 int coap_get_data(const coap_pdu_t *pdu, size_t *len, unsigned char **data)
757 {
758     assert(pdu);
759     assert(len);
760     assert(data);
761
762     if (pdu->data)
763     {
764         *len = (unsigned char *) pdu->hdr + pdu->length - pdu->data;
765         *data = pdu->data;
766     }
767     else
768     { /* no data, clear everything */
769         *len = 0;
770         *data = NULL;
771     }
772
773     return *data != NULL;
774 }
775
776 #ifndef SHORT_ERROR_RESPONSE
777 typedef struct
778 {
779     unsigned char code;
780     char *phrase;
781 } error_desc_t;
782
783 /* if you change anything here, make sure, that the longest string does not
784  * exceed COAP_ERROR_PHRASE_LENGTH. */
785 error_desc_t coap_error[] =
786 {
787 { COAP_RESPONSE_CODE(65), "2.01 Created" },
788 { COAP_RESPONSE_CODE(66), "2.02 Deleted" },
789 { COAP_RESPONSE_CODE(67), "2.03 Valid" },
790 { COAP_RESPONSE_CODE(68), "2.04 Changed" },
791 { COAP_RESPONSE_CODE(69), "2.05 Content" },
792 { COAP_RESPONSE_CODE(400), "Bad Request" },
793 { COAP_RESPONSE_CODE(401), "Unauthorized" },
794 { COAP_RESPONSE_CODE(402), "Bad Option" },
795 { COAP_RESPONSE_CODE(403), "Forbidden" },
796 { COAP_RESPONSE_CODE(404), "Not Found" },
797 { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
798 { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
799 { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
800 { COAP_RESPONSE_CODE(415), "Unsupported Media Type" },
801 { COAP_RESPONSE_CODE(500), "Internal Server Error" },
802 { COAP_RESPONSE_CODE(501), "Not Implemented" },
803 { COAP_RESPONSE_CODE(502), "Bad Gateway" },
804 { COAP_RESPONSE_CODE(503), "Service Unavailable" },
805 { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
806 { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
807 { 0, NULL } /* end marker */
808 };
809
810 char *
811 coap_response_phrase(unsigned char code)
812 {
813     int i;
814     for (i = 0; coap_error[i].code; ++i)
815     {
816         if (coap_error[i].code == code)
817             return coap_error[i].phrase;
818     }
819     return NULL;
820 }
821 #endif
822
823 /**
824  * Advances *optp to next option if still in PDU. This function
825  * returns the number of bytes opt has been advanced or @c 0
826  * on error.
827  */
828 static size_t next_option_safe(coap_opt_t **optp, size_t *length, coap_option_t* option)
829 {
830     //coap_option_t option;
831     size_t optsize;
832
833     assert(optp);
834     assert(*optp);
835     assert(length);
836     optsize = coap_opt_parse(*optp, *length, option);
837     if (optsize)
838     {
839         assert(optsize <= *length);
840
841         *optp += optsize;
842         *length -= optsize;
843     }
844
845     return optsize;
846 }
847
848 int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu,
849                    coap_transport_type transport)
850 {
851     assert(data);
852     assert(pdu);
853
854     if (pdu->max_size < length)
855     {
856         debug("insufficient space to store parsed PDU\n");
857         printf("[COAP] insufficient space to store parsed PDU\n");
858         return -1;
859     }
860
861     unsigned int headerSize = 0;
862
863     if (coap_udp == transport)
864     {
865         headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
866     }
867 #ifdef WITH_TCP
868     else
869     {
870         headerSize = coap_get_tcp_header_length_for_transport(transport);
871     }
872 #endif
873
874     if (length < headerSize)
875     {
876         debug("discarded invalid PDU\n");
877     }
878
879     coap_opt_t *opt = NULL;
880     unsigned int tokenLength = 0;
881 #ifdef WITH_TCP
882     switch(transport)
883     {
884         case coap_udp:
885             break;
886         case coap_tcp:
887             for (size_t i = 0 ; i < headerSize ; i++)
888             {
889                 pdu->hdr->coap_hdr_tcp_t.header_data[i] = data[i];
890             }
891
892             tokenLength = data[0] & 0x0f;
893             opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_t) + 1) + tokenLength;
894             break;
895         case coap_tcp_8bit:
896             for (size_t i = 0 ; i < headerSize ; i++)
897             {
898                 pdu->hdr->coap_hdr_tcp_8bit_t.header_data[i] = data[i];
899             }
900
901             tokenLength = data[0] & 0x0f;
902             opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_8bit_t))
903                     + tokenLength + COAP_TCP_HEADER_8_BIT;
904             break;
905         case coap_tcp_16bit:
906             for (size_t i = 0 ; i < headerSize ; i++)
907             {
908                 pdu->hdr->coap_hdr_tcp_16bit_t.header_data[i] = data[i];
909             }
910
911             tokenLength = data[0] & 0x0f;
912             opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_16bit_t) + 1) + tokenLength;
913             break;
914         case coap_tcp_32bit:
915             for (size_t i = 0 ; i < headerSize ; i++)
916             {
917                 pdu->hdr->coap_hdr_tcp_32bit_t.header_data[i] = data[i];
918             }
919
920             tokenLength = data[0] & 0x0f;
921             opt = ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_32bit_t)) +
922                     headerSize + tokenLength;
923             break;
924         default:
925             printf("it has wrong type\n");
926     }
927 #endif
928     pdu->length = length;
929
930     if (coap_udp == transport)
931     {
932         pdu->hdr->coap_hdr_udp_t.version = data[0] >> 6;
933         pdu->hdr->coap_hdr_udp_t.type = (data[0] >> 4) & 0x03;
934         pdu->hdr->coap_hdr_udp_t.token_length = data[0] & 0x0f;
935         pdu->hdr->coap_hdr_udp_t.code = data[1];
936         pdu->data = NULL;
937
938         tokenLength = pdu->hdr->coap_hdr_udp_t.token_length;
939
940         /* sanity checks */
941         if (pdu->hdr->coap_hdr_udp_t.code == 0)
942         {
943             if (length != headerSize || tokenLength)
944             {
945                 debug("coap_pdu_parse: empty message is not empty\n");
946                 goto discard;
947             }
948         }
949
950         if (length < headerSize + tokenLength || tokenLength > 8)
951         {
952             debug("coap_pdu_parse: invalid Token\n");
953             goto discard;
954         }
955
956         memcpy(&pdu->hdr->coap_hdr_udp_t.id, data + 2, 2);
957
958         /* Finally calculate beginning of data block and thereby check integrity
959          * of the PDU structure. */
960
961         /* append data (including the Token) to pdu structure */
962         memcpy(&(pdu->hdr->coap_hdr_udp_t) + 1, data + headerSize, length - headerSize);
963
964         /* skip header + token */
965         length -= (tokenLength + headerSize);
966         opt = (unsigned char *) (&(pdu->hdr->coap_hdr_udp_t) + 1) + tokenLength;
967     }
968 #ifdef WITH_TCP
969     else // common for tcp header setting
970     {
971         pdu->data = NULL;
972
973         if (length < headerSize + tokenLength || tokenLength > 8)
974         {
975             debug("coap_pdu_parse: invalid Token\n");
976             goto discard;
977         }
978         /* Finally calculate beginning of data block and thereby check integrity
979          * of the PDU structure. */
980
981         /* append data (including the Token) to pdu structure */
982         memcpy(((unsigned char *) pdu->hdr) + headerSize,
983                data + headerSize, length - headerSize);
984
985         /* skip header + token */
986         length -= (tokenLength + headerSize);
987     }
988 #endif
989
990     while (length && *opt != COAP_PAYLOAD_START)
991     {
992         coap_option_t option;
993         memset(&option, 0, sizeof(coap_option_t));
994         if (!next_option_safe(&opt, (size_t *) &length, &option))
995         {
996             debug("coap_pdu_parse: drop\n");
997             goto discard;
998         }
999     }
1000
1001     /* end of packet or start marker */
1002     if (length)
1003     {
1004         assert(*opt == COAP_PAYLOAD_START);
1005         opt++;
1006         length--;
1007
1008         if (!length)
1009         {
1010             debug("coap_pdu_parse: message ending in payload start marker\n");
1011             goto discard;
1012         }
1013
1014         debug(
1015                 "set data to %p (pdu ends at %p)\n", (unsigned char *)opt,
1016                 (unsigned char *)pdu->hdr + pdu->length);
1017         pdu->data = (unsigned char *) opt;
1018         //printf("[COAP] pdu - data : %s\n", pdu->data);
1019     }
1020
1021     return 1;
1022
1023     discard: return 0;
1024 }