Imported Upstream version 0.9.2
[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 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
20 #endif
21
22 #include "debug.h"
23 #include "pdu.h"
24 #include "option.h"
25 #include "encode.h"
26
27 #ifdef WITH_ARDUINO
28 #include "util.h"
29 #endif
30
31 #ifdef WITH_CONTIKI
32 #include "memb.h"
33
34 typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
35
36 MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
37
38 void
39 coap_pdu_resources_init()
40 {
41     memb_init(&pdu_storage);
42 }
43 #else /* WITH_CONTIKI */
44 #include "mem.h"
45 #endif /* WITH_CONTIKI */
46
47 void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
48 {
49     assert(pdu);
50
51     memset(pdu, 0, sizeof(coap_pdu_t) + size);
52     pdu->max_size = size;
53     pdu->hdr = (coap_hdr_t *) ((unsigned char *) pdu + sizeof(coap_pdu_t));
54     pdu->hdr->version = COAP_DEFAULT_VERSION;
55
56     /* data is NULL unless explicitly set by coap_add_data() */
57     pdu->length = sizeof(coap_hdr_t);
58 }
59
60 #ifdef WITH_LWIP
61 coap_pdu_t *
62 coap_pdu_from_pbuf(struct pbuf *pbuf)
63 {
64     LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
65     LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
66
67     void *data = pbuf->payload;
68     coap_pdu_t *result;
69
70     u8_t header_error = pbuf_header(pbuf, sizeof(coap_pdu_t));
71     LWIP_ASSERT("CoAP PDU header does not fit in existing header space", header_error == 0);
72
73     result = (coap_pdu_t *)pbuf->payload;
74
75     memset(result, 0, sizeof(coap_pdu_t));
76
77     result->max_size = pbuf->tot_len - sizeof(coap_pdu_t);
78     result->length = pbuf->tot_len - sizeof(coap_pdu_t);
79     result->hdr = data;
80     result->pbuf = pbuf;
81
82     return result;
83 }
84 #endif
85
86 coap_pdu_t *
87 coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
88 {
89     coap_pdu_t *pdu;
90 #ifdef WITH_LWIP
91     struct pbuf *p;
92 #endif
93
94     assert(size <= COAP_MAX_PDU_SIZE);
95     /* Size must be large enough to fit the header. */
96     if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
97         return NULL;
98
99     /* size must be large enough for hdr */
100 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
101     pdu = (coap_pdu_t *) coap_malloc(sizeof(coap_pdu_t) + size);
102 #endif
103 #ifdef WITH_CONTIKI
104     pdu = (coap_pdu_t *)memb_alloc(&pdu_storage);
105 #endif
106 #ifdef WITH_LWIP
107     p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
108     if (p != NULL)
109     {
110         u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t));
111         /* we could catch that case and allocate larger memory in advance, but then
112          * again, we'd run into greater trouble with incoming packages anyway */
113         LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0);
114         pdu = p->payload;
115     }
116     else
117     {
118         pdu = NULL;
119     }
120 #endif
121     if (pdu)
122     {
123         coap_pdu_clear(pdu, size);
124         pdu->hdr->id = id;
125         pdu->hdr->type = type;
126         pdu->hdr->code = code;
127 #ifdef WITH_LWIP
128         pdu->pbuf = p;
129 #endif
130     }
131     return pdu;
132 }
133
134 coap_pdu_t *
135 coap_new_pdu()
136 {
137     coap_pdu_t *pdu;
138
139 #ifndef WITH_CONTIKI
140     pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
141 #else /* WITH_CONTIKI */
142     pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
143 #endif /* WITH_CONTIKI */
144
145 #ifndef NDEBUG
146     if (!pdu)
147         coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
148 #endif
149     return pdu;
150 }
151
152 void coap_delete_pdu(coap_pdu_t *pdu)
153 {
154 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
155     coap_free( pdu );
156 #endif
157 #ifdef WITH_LWIP
158     if (pdu != NULL) /* accepting double free as the other implementation accept that too */
159         pbuf_free(pdu->pbuf);
160 #endif
161 #ifdef WITH_CONTIKI
162     memb_free(&pdu_storage, pdu);
163 #endif
164 }
165
166 int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
167 {
168     const size_t HEADERLENGTH = len + 4;
169     /* must allow for pdu == NULL as callers may rely on this */
170     if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
171         return 0;
172
173     pdu->hdr->token_length = len;
174     if (len)
175         memcpy(pdu->hdr->token, data, len);
176     pdu->max_delta = 0;
177     pdu->length = HEADERLENGTH;
178     pdu->data = NULL;
179
180     return 1;
181 }
182
183 /** @FIXME de-duplicate code with coap_add_option_later */
184 size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
185         const unsigned char *data)
186 {
187     size_t optsize;
188     coap_opt_t *opt;
189
190     assert(pdu);
191     pdu->data = NULL;
192
193     if (type < pdu->max_delta)
194     {
195         warn("coap_add_option: options are not in correct order\n");
196         return 0;
197     }
198
199     opt = (unsigned char *) pdu->hdr + pdu->length;
200
201     /* encode option and check length */
202     optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
203
204     if (!optsize)
205     {
206         warn("coap_add_option: cannot add option\n");
207         /* error */
208         return 0;
209     }
210     else
211     {
212         pdu->max_delta = type;
213         pdu->length += optsize;
214     }
215
216     return optsize;
217 }
218
219 /** @FIXME de-duplicate code with coap_add_option */
220 unsigned char*
221 coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
222 {
223     size_t optsize;
224     coap_opt_t *opt;
225
226     assert(pdu);
227     pdu->data = NULL;
228
229     if (type < pdu->max_delta)
230     {
231         warn("coap_add_option: options are not in correct order\n");
232         return NULL;
233     }
234
235     opt = (unsigned char *) pdu->hdr + pdu->length;
236
237     /* encode option and check length */
238     optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, NULL, len);
239
240     if (!optsize)
241     {
242         warn("coap_add_option: cannot add option\n");
243         /* error */
244         return NULL;
245     }
246     else
247     {
248         pdu->max_delta = type;
249         pdu->length += optsize;
250     }
251
252     return ((unsigned char*) opt) + optsize - len;
253 }
254
255 int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
256 {
257     assert(pdu);
258     assert(pdu->data == NULL);
259
260     if (len == 0)
261         return 1;
262
263     if (pdu->length + len + 1 > pdu->max_size)
264     {
265         warn("coap_add_data: cannot add: data too large for PDU\n");
266         assert(pdu->data == NULL);
267         return 0;
268     }
269
270     pdu->data = (unsigned char *) pdu->hdr + pdu->length;
271     *pdu->data = COAP_PAYLOAD_START;
272     pdu->data++;
273
274     memcpy(pdu->data, data, len);
275     pdu->length += len + 1;
276     return 1;
277 }
278
279 int coap_get_data(const coap_pdu_t *pdu, size_t *len, unsigned char **data)
280 {
281     assert(pdu);
282     assert(len);
283     assert(data);
284
285     if (pdu->data)
286     {
287         *len = (unsigned char *) pdu->hdr + pdu->length - pdu->data;
288         *data = pdu->data;
289     }
290     else
291     { /* no data, clear everything */
292         *len = 0;
293         *data = NULL;
294     }
295
296     return *data != NULL;
297 }
298
299 #ifndef SHORT_ERROR_RESPONSE
300 typedef struct
301 {
302     unsigned char code;
303     char *phrase;
304 } error_desc_t;
305
306 /* if you change anything here, make sure, that the longest string does not
307  * exceed COAP_ERROR_PHRASE_LENGTH. */
308 error_desc_t coap_error[] =
309 {
310 { COAP_RESPONSE_CODE(65), "2.01 Created" },
311 { COAP_RESPONSE_CODE(66), "2.02 Deleted" },
312 { COAP_RESPONSE_CODE(67), "2.03 Valid" },
313 { COAP_RESPONSE_CODE(68), "2.04 Changed" },
314 { COAP_RESPONSE_CODE(69), "2.05 Content" },
315 { COAP_RESPONSE_CODE(400), "Bad Request" },
316 { COAP_RESPONSE_CODE(401), "Unauthorized" },
317 { COAP_RESPONSE_CODE(402), "Bad Option" },
318 { COAP_RESPONSE_CODE(403), "Forbidden" },
319 { COAP_RESPONSE_CODE(404), "Not Found" },
320 { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
321 { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
322 { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
323 { COAP_RESPONSE_CODE(415), "Unsupported Media Type" },
324 { COAP_RESPONSE_CODE(500), "Internal Server Error" },
325 { COAP_RESPONSE_CODE(501), "Not Implemented" },
326 { COAP_RESPONSE_CODE(502), "Bad Gateway" },
327 { COAP_RESPONSE_CODE(503), "Service Unavailable" },
328 { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
329 { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
330 { 0, NULL } /* end marker */
331 };
332
333 char *
334 coap_response_phrase(unsigned char code)
335 {
336     int i;
337     for (i = 0; coap_error[i].code; ++i)
338     {
339         if (coap_error[i].code == code)
340             return coap_error[i].phrase;
341     }
342     return NULL;
343 }
344 #endif
345
346 /**
347  * Advances *optp to next option if still in PDU. This function
348  * returns the number of bytes opt has been advanced or @c 0
349  * on error.
350  */
351 static size_t next_option_safe(coap_opt_t **optp, size_t *length, coap_option_t* option)
352 {
353     //coap_option_t option;
354     size_t optsize;
355
356     assert(optp);
357     assert(*optp);
358     assert(length);
359     optsize = coap_opt_parse(*optp, *length, option);
360     if (optsize)
361     {
362         assert(optsize <= *length);
363
364         *optp += optsize;
365         *length -= optsize;
366     }
367
368     return optsize;
369 }
370
371 int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
372 {
373     coap_opt_t *opt;
374
375     assert(data);
376     assert(pdu);
377
378     if (pdu->max_size < length)
379     {
380         debug("insufficient space to store parsed PDU\n");
381         printf("[COAP] insufficient space to store parsed PDU\n");
382         return 0;
383     }
384
385     if (length < sizeof(coap_hdr_t))
386     {
387         debug("discarded invalid PDU\n");
388     }
389
390     pdu->hdr->version = data[0] >> 6;
391     pdu->hdr->type = (data[0] >> 4) & 0x03;
392     pdu->hdr->token_length = data[0] & 0x0f;
393     pdu->hdr->code = data[1];
394     /*
395      printf("[COAP] pdu - version : %d\n", pdu->hdr->version);
396      printf("[COAP] pdu - type : %d\n", pdu->hdr->type);
397      printf("[COAP] pdu - token_length : %d\n", pdu->hdr->token_length);
398      printf("[COAP] pdu - code : %d\n", pdu->hdr->code);
399      */
400     pdu->data = NULL;
401
402     /* sanity checks */
403     if (pdu->hdr->code == 0)
404     {
405         if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length)
406         {
407             debug("coap_pdu_parse: empty message is not empty\n");
408             goto discard;
409         }
410     }
411
412     if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8)
413     {
414         debug("coap_pdu_parse: invalid Token\n");
415         goto discard;
416     }
417
418     /* Copy message id in network byte order, so we can easily write the
419      * response back to the network. */
420     memcpy(&pdu->hdr->id, data + 2, 2);
421
422     //printf("[COAP] pdu - id : %d\n", pdu->hdr->id);
423
424     /* append data (including the Token) to pdu structure */
425     memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
426     pdu->length = length;
427
428     /* Finally calculate beginning of data block and thereby check integrity
429      * of the PDU structure. */
430
431     /* skip header + token */
432     length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
433     opt = (unsigned char *) (pdu->hdr + 1) + pdu->hdr->token_length;
434
435     while (length && *opt != COAP_PAYLOAD_START)
436     {
437         coap_option_t option;
438         memset(&option, 0, sizeof(coap_option_t));
439         if (!next_option_safe(&opt, (size_t *) &length, &option))
440         {
441             debug("coap_pdu_parse: drop\n");
442             goto discard;
443         }
444     }
445
446     /* end of packet or start marker */
447     if (length)
448     {
449         assert(*opt == COAP_PAYLOAD_START);
450         opt++;
451         length--;
452
453         if (!length)
454         {
455             debug("coap_pdu_parse: message ending in payload start marker\n");
456             goto discard;
457         }
458
459         debug(
460                 "set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length);
461         pdu->data = (unsigned char *) opt;
462         //printf("[COAP] pdu - data : %s\n", pdu->data);
463     }
464
465     return 1;
466
467     discard: return 0;
468 }