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