iotivity 0.9.0
[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
22 coap_opt_t *
23 options_start(coap_pdu_t *pdu)
24 {
25
26     if (pdu && pdu->hdr
27             && (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *) pdu->hdr + pdu->length))
28     {
29
30         coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
31         return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
32
33     }
34     else
35         return NULL;
36 }
37
38 size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
39 {
40
41     const coap_opt_t *opt_start = opt; /* store where parsing starts  */
42     assert(opt);
43     assert(result);
44
45 #define ADVANCE_OPT(o,e,step) if ((e) < step) {                 \
46     debug("cannot advance opt past end\n");                     \
47     return 0;                                                   \
48   } else {                                                      \
49     (e) -= step;                                                \
50     (o) = ((unsigned char *)(o)) + step;                        \
51   }
52
53     if (length < 1)
54         return 0;
55
56     result->delta = (*opt & 0xf0) >> 4;
57     result->length = *opt & 0x0f;
58
59     switch (result->delta)
60     {
61         case 15:
62             if (*opt != COAP_PAYLOAD_START)
63                 debug("ignored reserved option delta 15\n");
64             return 0;
65         case 14:
66             /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
67              * After that, the option pointer is advanced to the LSB which is handled
68              * just like case delta == 13. */
69             ADVANCE_OPT(opt, length, 1);
70             result->delta = ((*opt & 0xff) << 8) + 269;
71             if (result->delta < 269)
72             {
73                 debug("delta too large\n");
74                 return 0;
75             }
76             /* fall through */
77         case 13:
78             ADVANCE_OPT(opt, length, 1);
79             result->delta += *opt & 0xff;
80             break;
81
82         default:
83             ;
84     }
85
86     switch (result->length)
87     {
88         case 15:
89             debug("found reserved option length 15\n");
90             return 0;
91         case 14:
92             /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
93              * After that, the option pointer is advanced to the LSB which is handled
94              * just like case delta == 13. */
95             ADVANCE_OPT(opt, length, 1);
96             result->length = ((*opt & 0xff) << 8) + 269;
97             /* fall through */
98         case 13:
99             ADVANCE_OPT(opt, length, 1);
100             result->length += *opt & 0xff;
101             break;
102
103         default:
104             ;
105     }
106
107     ADVANCE_OPT(opt, length, 1);
108     /* opt now points to value, if present */
109
110     result->value = (unsigned char *) opt;
111     if (length < result->length)
112     {
113         debug("invalid option length\n");
114         return 0;
115     }
116     //printf("[COAP] Option - coap_opt_parse result : %s, %d\n", result->value, result->length);
117
118 #undef ADVANCE_OPT
119
120     return (opt + result->length) - opt_start;
121 }
122
123 coap_opt_iterator_t *
124 coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
125 {
126     assert(pdu);
127     assert(pdu->hdr);
128     assert(oi);
129
130     memset(oi, 0, sizeof(coap_opt_iterator_t));
131
132     oi->next_option = (unsigned char *) pdu->hdr + sizeof(coap_hdr_t) + pdu->hdr->token_length;
133     if ((unsigned char *) pdu->hdr + pdu->length <= oi->next_option)
134     {
135         oi->bad = 1;
136         return NULL;
137     }
138
139     assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
140
141     oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
142
143     if (filter)
144     {
145         memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
146         oi->filtered = 1;
147     }
148     return oi;
149 }
150
151 static inline int opt_finished(coap_opt_iterator_t *oi)
152 {
153     assert(oi);
154
155     if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START)
156     {
157         oi->bad = 1;
158     }
159
160     return oi->bad;
161 }
162
163 coap_opt_t *
164 coap_option_next(coap_opt_iterator_t *oi)
165 {
166     coap_option_t option;
167     coap_opt_t *current_opt = NULL;
168     size_t optsize;
169     int b; /* to store result of coap_option_getb() */
170
171     assert(oi);
172
173     if (opt_finished(oi))
174         return NULL;
175
176     while (1)
177     {
178         /* oi->option always points to the next option to deliver; as
179          * opt_finished() filters out any bad conditions, we can assume that
180          * oi->option is valid. */
181         current_opt = oi->next_option;
182
183         /* Advance internal pointer to next option, skipping any option that
184          * is not included in oi->filter. */
185         optsize = coap_opt_parse(oi->next_option, oi->length, &option);
186         if (optsize)
187         {
188             assert(optsize <= oi->length);
189
190             oi->next_option += optsize;
191             oi->length -= optsize;
192
193             oi->type += option.delta;
194         }
195         else
196         { /* current option is malformed */
197             oi->bad = 1;
198             return NULL;
199         }
200
201         /* Exit the while loop when:
202          *   - no filtering is done at all
203          *   - the filter matches for the current option
204          *   - the filter is too small for the current option number 
205          */
206         if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0)
207             break;
208         else if (b < 0)
209         { /* filter too small, cannot proceed */
210             oi->bad = 1;
211             return NULL;
212         }
213     }
214
215     return current_opt;
216 }
217
218 coap_opt_t *
219 coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
220 {
221     coap_opt_filter_t f;
222
223     coap_option_filter_clear(f);
224     coap_option_setb(f, type);
225
226     coap_option_iterator_init(pdu, oi, f);
227
228     return coap_option_next(oi);
229 }
230
231 unsigned short coap_opt_delta(const coap_opt_t *opt)
232 {
233     unsigned short n;
234
235     n = (*opt++ & 0xf0) >> 4;
236
237     switch (n)
238     {
239         case 15: /* error */
240             warn("coap_opt_delta: illegal option delta\n");
241
242             /* This case usually should not happen, hence we do not have a
243              * proper way to indicate an error. */
244             return 0;
245         case 14:
246             /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
247              * After that, the option pointer is advanced to the LSB which is handled
248              * just like case delta == 13. */
249             n = ((*opt++ & 0xff) << 8) + 269;
250             /* fall through */
251         case 13:
252             n += *opt & 0xff;
253             break;
254         default: /* n already contains the actual delta value */
255             ;
256     }
257
258     return n;
259 }
260
261 unsigned short coap_opt_length(const coap_opt_t *opt)
262 {
263     unsigned short length;
264
265     length = *opt & 0x0f;
266     switch (*opt & 0xf0)
267     {
268         case 0xf0:
269             debug("illegal option delta\n");
270             return 0;
271         case 0xe0:
272             ++opt;
273             /* fall through to skip another byte */
274         case 0xd0:
275             ++opt;
276             /* fall through to skip another byte */
277         default:
278             ++opt;
279     }
280
281     switch (length)
282     {
283         case 0x0f:
284             debug("illegal option length\n");
285             return 0;
286         case 0x0e:
287             length = (*opt++ << 8) + 269;
288             /* fall through */
289         case 0x0d:
290             length += *opt++;
291             break;
292         default:
293             ;
294     }
295     return length;
296 }
297
298 unsigned char *
299 coap_opt_value(coap_opt_t *opt)
300 {
301     size_t ofs = 1;
302
303     switch (*opt & 0xf0)
304     {
305         case 0xf0:
306             debug("illegal option delta\n");
307             return 0;
308         case 0xe0:
309             ++ofs;
310             /* fall through */
311         case 0xd0:
312             ++ofs;
313             break;
314         default:
315             ;
316     }
317
318     switch (*opt & 0x0f)
319     {
320         case 0x0f:
321             debug("illegal option length\n");
322             return 0;
323         case 0x0e:
324             ++ofs;
325             /* fall through */
326         case 0x0d:
327             ++ofs;
328             break;
329         default:
330             ;
331     }
332
333     return (unsigned char *) opt + ofs;
334 }
335
336 size_t coap_opt_size(const coap_opt_t *opt)
337 {
338     coap_option_t option;
339
340     /* we must assume that opt is encoded correctly */
341     return coap_opt_parse(opt, (size_t) - 1, &option);
342 }
343
344 size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length)
345 {
346     size_t skip = 0;
347
348     assert(opt);
349
350     if (maxlen == 0) /* need at least one byte */
351         return 0;
352
353     if (delta < 13)
354     {
355         opt[0] = delta << 4;
356     }
357     else if (delta < 270)
358     {
359         if (maxlen < 2)
360         {
361             debug("insufficient space to encode option delta %d", delta);
362             return 0;
363         }
364
365         opt[0] = 0xd0;
366         opt[++skip] = delta - 13;
367     }
368     else
369     {
370         if (maxlen < 3)
371         {
372             debug("insufficient space to encode option delta %d", delta);
373             return 0;
374         }
375
376         opt[0] = 0xe0;
377         opt[++skip] = ((delta - 269) >> 8) & 0xff;
378         opt[++skip] = (delta - 269) & 0xff;
379     }
380
381     if (length < 13)
382     {
383         opt[0] |= length & 0x0f;
384     }
385     else if (length < 270)
386     {
387         if (maxlen < skip + 1)
388         {
389             debug("insufficient space to encode option length %d", length);
390             return 0;
391         }
392
393         opt[0] |= 0x0d;
394         opt[++skip] = length - 13;
395     }
396     else
397     {
398         if (maxlen < skip + 2)
399         {
400             debug("insufficient space to encode option delta %d", delta);
401             return 0;
402         }
403
404         opt[0] |= 0x0e;
405         opt[++skip] = ((length - 269) >> 8) & 0xff;
406         opt[++skip] = (length - 269) & 0xff;
407     }
408
409     return skip + 1;
410 }
411
412 size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
413         const unsigned char *val, size_t length)
414 {
415     size_t l = 1;
416
417     l = coap_opt_setheader(opt, maxlen, delta, length);
418     assert(l <= maxlen);
419
420     if (!l)
421     {
422         debug("coap_opt_encode: cannot set option header\n");
423         return 0;
424     }
425
426     maxlen -= l;
427     opt += l;
428
429     if (maxlen < length)
430     {
431         debug("coap_opt_encode: option too large for buffer\n");
432         return 0;
433     }
434
435     if (val) /* better be safe here */
436         memcpy(opt, val, length);
437
438     return l + length;
439 }
440