Corrected empty body 'if' warning
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / libcoap-4.1.1 / option.c
1 /*
2  * option.c -- helpers for handling options in CoAP PDUs
3  *
4  * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * This file is part of the CoAP library libcoap. Please see
7  * README for terms of use.
8  */
9
10 #include "config.h"
11
12 #if defined(HAVE_ASSERT_H) && !defined(assert)
13 # include <assert.h>
14 #endif
15
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "option.h"
20 #include "debug.h"
21 #include "pdu.h"
22
23 coap_opt_t *
24 options_start(coap_pdu_t *pdu, coap_transport_type transport)
25 {
26     if (pdu && pdu->hdr)
27     {
28         if (coap_udp == transport && (pdu->hdr->coap_hdr_udp_t.token +
29                 pdu->hdr->coap_hdr_udp_t.token_length
30                 < (unsigned char *) pdu->hdr + pdu->length))
31         {
32             coap_opt_t *opt = pdu->hdr->coap_hdr_udp_t.token +
33                     pdu->hdr->coap_hdr_udp_t.token_length;
34             return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
35         }
36 #ifdef WITH_TCP
37         else if(coap_tcp == transport && (pdu->hdr->coap_hdr_tcp_t.token +
38                 ((pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f)
39                 < (unsigned char *) pdu->hdr + pdu->length))
40         {
41             coap_opt_t *opt = pdu->hdr->coap_hdr_tcp_t.token +
42                     ((pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f);
43             return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
44         }
45 #endif
46         return NULL;
47     }
48     else
49         return NULL;
50 }
51
52 size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
53 {
54
55     const coap_opt_t *opt_start = opt; /* store where parsing starts  */
56     assert(opt);
57     assert(result);
58
59 #define ADVANCE_OPT(o,e,step) if ((e) < step) {         \
60     debug("cannot advance opt past end\n");         \
61     return 0;                           \
62   } else {                          \
63     (e) -= step;                        \
64     (o) = ((unsigned char *)(o)) + step;            \
65   }
66
67     if (length < 1)
68         return 0;
69
70     result->delta = (*opt & 0xf0) >> 4;
71     result->length = *opt & 0x0f;
72
73     switch (result->delta)
74     {
75         case 15:
76             if (*opt != COAP_PAYLOAD_START)
77             {
78                 debug("ignored reserved option delta 15\n");
79             }
80             return 0;
81         case 14:
82             /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
83              * After that, the option pointer is advanced to the LSB which is handled
84              * just like case delta == 13. */
85             ADVANCE_OPT(opt, length, 1);
86             result->delta = ((*opt & 0xff) << 8) + 269;
87             if (result->delta < 269)
88             {
89                 debug("delta too large\n");
90                 return 0;
91             }
92             /* fall through */
93         case 13:
94             ADVANCE_OPT(opt, length, 1);
95             result->delta += *opt & 0xff;
96             break;
97
98         default:
99             ;
100     }
101
102     switch (result->length)
103     {
104         case 15:
105             debug("found reserved option length 15\n");
106             return 0;
107         case 14:
108             /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
109              * After that, the option pointer is advanced to the LSB which is handled
110              * just like case delta == 13. */
111             ADVANCE_OPT(opt, length, 1);
112             result->length = ((*opt & 0xff) << 8) + 269;
113             /* fall through */
114         case 13:
115             ADVANCE_OPT(opt, length, 1);
116             result->length += *opt & 0xff;
117             break;
118
119         default:
120             ;
121     }
122
123     ADVANCE_OPT(opt, length, 1);
124     /* opt now points to value, if present */
125
126     result->value = (unsigned char *) opt;
127     if (length < result->length)
128     {
129         debug("invalid option length\n");
130         return 0;
131     }
132     //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
133
134 #undef ADVANCE_OPT
135
136     return (opt + result->length) - opt_start;
137 }
138
139 coap_opt_iterator_t *
140 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
141                           const coap_opt_filter_t filter, coap_transport_type transport)
142 {
143     assert(pdu);
144     assert(pdu->hdr);
145     assert(oi);
146
147     memset(oi, 0, sizeof(coap_opt_iterator_t));
148
149     unsigned int token_length;
150     unsigned int headerSize;
151
152     switch(transport)
153     {
154 #ifdef WITH_TCP
155         case coap_tcp:
156             token_length = (pdu->hdr->coap_hdr_tcp_t.header_data[0]) & 0x0f;
157             headerSize = COAP_TCP_HEADER_NO_FIELD;
158             break;
159         case coap_tcp_8bit:
160             token_length = (pdu->hdr->coap_hdr_tcp_8bit_t.header_data[0]) & 0x0f;
161             headerSize = COAP_TCP_HEADER_8_BIT;
162             break;
163         case coap_tcp_16bit:
164             token_length = (pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0]) & 0x0f;
165             headerSize = COAP_TCP_HEADER_16_BIT;
166             break;
167         case coap_tcp_32bit:
168             token_length = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] & 0x0f;
169             headerSize = COAP_TCP_HEADER_32_BIT;
170             break;
171 #endif
172         default:
173             token_length = pdu->hdr->coap_hdr_udp_t.token_length;
174             headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
175             break;
176     }
177
178     oi->next_option = (unsigned char *) pdu->hdr + headerSize + token_length;
179
180     if (coap_udp == transport)
181     {
182         if ((unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length <= oi->next_option)
183         {
184             oi->bad = 1;
185             return NULL;
186         }
187     }
188 #ifdef WITH_TCP
189     else
190     {
191         if ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length <= oi->next_option)
192         {
193             oi->bad = 1;
194             return NULL;
195         }
196     }
197 #endif
198
199     assert((headerSize + token_length) <= pdu->length);
200
201     oi->length = pdu->length - (headerSize + token_length);
202
203     if (filter)
204     {
205         memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
206         oi->filtered = 1;
207     }
208     return oi;
209 }
210
211 static inline int opt_finished(coap_opt_iterator_t *oi)
212 {
213     assert(oi);
214
215     if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
216     {
217         oi->bad = 1;
218     }
219
220     return oi->bad;
221 }
222
223 coap_opt_t *
224 coap_option_next(coap_opt_iterator_t *oi)
225 {
226     coap_option_t option;
227     coap_opt_t *current_opt = NULL;
228     size_t optsize;
229     int b; /* to store result of coap_option_getb() */
230
231     assert(oi);
232
233     if (opt_finished(oi))
234         return NULL;
235
236     while (1)
237     {
238         /* oi->option always points to the next option to deliver; as
239          * opt_finished() filters out any bad conditions, we can assume that
240          * oi->option is valid. */
241         current_opt = oi->next_option;
242
243         /* Advance internal pointer to next option, skipping any option that
244          * is not included in oi->filter. */
245         optsize = coap_opt_parse(oi->next_option, oi->length, &option);
246         if (optsize)
247         {
248             assert(optsize <= oi->length);
249
250             oi->next_option += optsize;
251             oi->length -= optsize;
252
253             oi->type += option.delta;
254         }
255         else
256         { /* current option is malformed */
257             oi->bad = 1;
258             return NULL;
259         }
260
261         /* Exit the while loop when:
262          *   - no filtering is done at all
263          *   - the filter matches for the current option
264          *   - the filter is too small for the current option number
265          */
266         if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
267             break;
268         else if (b < 0)
269         { /* filter too small, cannot proceed */
270             oi->bad = 1;
271             return NULL;
272         }
273     }
274
275     return current_opt;
276 }
277
278 coap_opt_t *
279 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
280 {
281     coap_opt_filter_t f;
282
283     coap_option_filter_clear(f);
284     coap_option_setb(f, type);
285
286     coap_option_iterator_init(pdu, oi, f, coap_udp);
287
288     return coap_option_next(oi);
289 }
290
291 unsigned short coap_opt_delta(const coap_opt_t *opt)
292 {
293     unsigned short n;
294
295     n = (*opt++ & 0xf0) >> 4;
296
297     switch (n)
298     {
299         case 15: /* error */
300             warn("coap_opt_delta: illegal option delta\n");
301
302             /* This case usually should not happen, hence we do not have a
303              * proper way to indicate an error. */
304             return 0;
305         case 14:
306             /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
307              * After that, the option pointer is advanced to the LSB which is handled
308              * just like case delta == 13. */
309             n = ((*opt++ & 0xff) << 8) + 269;
310             /* fall through */
311         case 13:
312             n += *opt & 0xff;
313             break;
314         default: /* n already contains the actual delta value */
315             ;
316     }
317
318     return n;
319 }
320
321 unsigned short coap_opt_length(const coap_opt_t *opt)
322 {
323     unsigned short length;
324
325     length = *opt & 0x0f;
326     switch (*opt & 0xf0)
327     {
328         case 0xf0:
329             debug("illegal option delta\n");
330             return 0;
331         case 0xe0:
332             ++opt;
333             /* fall through to skip another byte */
334         case 0xd0:
335             ++opt;
336             /* fall through to skip another byte */
337         default:
338             ++opt;
339     }
340
341     switch (length)
342     {
343         case 0x0f:
344             debug("illegal option length\n");
345             return 0;
346         case 0x0e:
347             length = (*opt++ << 8) + 269;
348             /* fall through */
349         case 0x0d:
350             length += *opt++;
351             break;
352         default:
353             ;
354     }
355     return length;
356 }
357
358 unsigned char *
359 coap_opt_value(coap_opt_t *opt)
360 {
361     size_t ofs = 1;
362
363     switch (*opt & 0xf0)
364     {
365         case 0xf0:
366             debug("illegal option delta\n");
367             return 0;
368         case 0xe0:
369             ++ofs;
370             /* fall through */
371         case 0xd0:
372             ++ofs;
373             break;
374         default:
375             ;
376     }
377
378     switch (*opt & 0x0f)
379     {
380         case 0x0f:
381             debug("illegal option length\n");
382             return 0;
383         case 0x0e:
384             ++ofs;
385             /* fall through */
386         case 0x0d:
387             ++ofs;
388             break;
389         default:
390             ;
391     }
392
393     return (unsigned char *) opt + ofs;
394 }
395
396 size_t coap_opt_size(const coap_opt_t *opt)
397 {
398     coap_option_t option;
399
400     /* we must assume that opt is encoded correctly */
401     return coap_opt_parse(opt, (size_t) - 1, &option);
402 }
403
404 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
405 {
406     size_t skip = 0;
407
408     assert(opt);
409
410     if (maxlen == 0) /* need at least one byte */
411         return 0;
412
413     if (delta < 13)
414     {
415         opt[0] = delta << 4;
416     }
417     else if (delta < 270)
418     {
419         if (maxlen < 2)
420         {
421             debug("insufficient space to encode option delta %d", delta);
422             return 0;
423         }
424
425         opt[0] = 0xd0;
426         opt[++skip] = delta - 13;
427     }
428     else
429     {
430         if (maxlen < 3)
431         {
432             debug("insufficient space to encode option delta %d", delta);
433             return 0;
434         }
435
436         opt[0] = 0xe0;
437         opt[++skip] = ((delta - 269) >> 8) & 0xff;
438         opt[++skip] = (delta - 269) & 0xff;
439     }
440
441     if (length < 13)
442     {
443         opt[0] |= length & 0x0f;
444     }
445     else if (length < 270)
446     {
447         if (maxlen < skip + 1)
448         {
449             debug("insufficient space to encode option length %d", length);
450             return 0;
451         }
452
453         opt[0] |= 0x0d;
454         opt[++skip] = length - 13;
455     }
456     else
457     {
458         if (maxlen < skip + 2)
459         {
460             debug("insufficient space to encode option delta %d", delta);
461             return 0;
462         }
463
464         opt[0] |= 0x0e;
465         opt[++skip] = ((length - 269) >> 8) & 0xff;
466         opt[++skip] = (length - 269) & 0xff;
467     }
468
469     return skip + 1;
470 }
471
472 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
473         const unsigned char *val, size_t length)
474 {
475     size_t l = 1;
476
477     l = coap_opt_setheader(opt, maxlen, delta, length);
478     assert(l <= maxlen);
479
480     if (!l)
481     {
482         debug("coap_opt_encode: cannot set option header\n");
483         return 0;
484     }
485
486     maxlen -= l;
487     opt += l;
488
489     if (maxlen < length)
490     {
491         debug("coap_opt_encode: option too large for buffer\n");
492         return 0;
493     }
494
495     if (val) /* better be safe here */
496         memcpy(opt, val, length);
497
498     return l + length;
499 }
500
501 static coap_option_def_t coap_option_def[] = {
502     { COAP_OPTION_IF_MATCH,       'o',  0,   8 },
503     { COAP_OPTION_URI_HOST,       's',  1, 255 },
504     { COAP_OPTION_ETAG,           'o',  1,   8 },
505     { COAP_OPTION_IF_NONE_MATCH,  'e',  0,   0 },
506     { COAP_OPTION_URI_PORT,       'u',  0,   2 },
507     { COAP_OPTION_LOCATION_PATH,  's',  0, 255 },
508     { COAP_OPTION_URI_PATH,       's',  0, 255 },
509     { COAP_OPTION_CONTENT_TYPE,   'u',  0,   2 },
510     { COAP_OPTION_MAXAGE,         'u',  0,   4 },
511     { COAP_OPTION_URI_QUERY,      's',  1, 255 },
512     { COAP_OPTION_ACCEPT,         'u',  0,   2 },
513     { COAP_OPTION_LOCATION_QUERY, 's',  0, 255 },
514     { COAP_OPTION_PROXY_URI,      's',  1,1034 },
515     { COAP_OPTION_PROXY_SCHEME,   's',  1, 255 },
516     { COAP_OPTION_SIZE1,          'u',  0,   4 },
517     { COAP_OPTION_SIZE2,          'u',  0,   4 },
518     { COAP_OPTION_OBSERVE,        'u',  0,   3 },
519     { COAP_OPTION_BLOCK2,         'u',  0,   3 },
520     { COAP_OPTION_BLOCK1,         'u',  0,   3 },
521 };
522
523
524 coap_option_def_t* coap_opt_def(unsigned short key)
525 {
526     int i;
527
528     if (COAP_MAX_OPT < key)
529     {
530         return NULL;
531     }
532     for (i = 0; i < (int)(sizeof(coap_option_def)/sizeof(coap_option_def_t)); i++)
533     {
534         if (key == coap_option_def[i].key)
535             return &(coap_option_def[i]);
536     }
537     debug("coap_opt_def: add key:[%d] to coap_is_var_bytes", key);
538     return NULL;
539 }