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