Contiki-NG
coap.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 */
31
32/**
33 * \file
34 * An implementation of the Constrained Application Protocol (RFC).
35 * \author
36 * Matthias Kovatsch <kovatsch@inf.ethz.ch>
37 *
38 * Joakim Eriksson, joakim.eriksson@ri.se
39 * Niclas Finne, niclas.finne@ri.se
40 */
41
42/**
43 * \addtogroup coap
44 * @{
45 */
46
47
48#include <string.h>
49#include <stdlib.h>
50#include <inttypes.h>
51#include "sys/cc.h"
52#include "lib/random.h"
53
54#include "coap.h"
55#include "coap-transactions.h"
56
57/* Log configuration */
58#include "coap-log.h"
59#define LOG_MODULE "coap"
60#define LOG_LEVEL LOG_LEVEL_COAP
61
62/*---------------------------------------------------------------------------*/
63/*- Variables ---------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
65static uint16_t current_mid = 0;
66
67coap_status_t coap_status_code = NO_ERROR;
68const char *coap_error_message = "";
69/*---------------------------------------------------------------------------*/
70/*- Local helper functions --------------------------------------------------*/
71/*---------------------------------------------------------------------------*/
72static uint16_t
73coap_log_2(uint16_t value)
74{
75 uint16_t result = 0;
76
77 do {
78 value = value >> 1;
79 result++;
80 } while(value);
81
82 return result ? result - 1 : result;
83}
84/*---------------------------------------------------------------------------*/
85static uint32_t
86coap_parse_int_option(const uint8_t *bytes, size_t length)
87{
88 uint32_t var = 0;
89 int i = 0;
90
91 while(i < length) {
92 var <<= 8;
93 var |= bytes[i++];
94 }
95 return var;
96}
97/*---------------------------------------------------------------------------*/
98static uint8_t
99coap_option_nibble(unsigned int value)
100{
101 if(value < 13) {
102 return value;
103 } else if(value <= 0xFF + 13) {
104 return 13;
105 } else {
106 return 14;
107 }
108}
109/*---------------------------------------------------------------------------*/
110static size_t
111coap_set_option_header(unsigned int delta, size_t length, uint8_t *buffer)
112{
113 size_t written = 0;
114
115 buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length);
116
117 if(delta > 268) {
118 buffer[++written] = ((delta - 269) >> 8) & 0xff;
119 buffer[++written] = (delta - 269) & 0xff;
120 } else if(delta > 12) {
121 buffer[++written] = (delta - 13);
122 }
123
124 if(length > 268) {
125 buffer[++written] = ((length - 269) >> 8) & 0xff;
126 buffer[++written] = (length - 269) & 0xff;
127 } else if(length > 12) {
128 buffer[++written] = (length - 13);
129 }
130
131 LOG_DBG("WRITTEN %zu B opt header\n", 1 + written);
132
133 return ++written;
134}
135/*---------------------------------------------------------------------------*/
136static size_t
137coap_serialize_int_option(unsigned int number, unsigned int current_number,
138 uint8_t *buffer, uint32_t value)
139{
140 size_t i = 0;
141
142 if(0xFF000000 & value) {
143 ++i;
144 }
145 if(0xFFFF0000 & value) {
146 ++i;
147 }
148 if(0xFFFFFF00 & value) {
149 ++i;
150 }
151 if(0xFFFFFFFF & value) {
152 ++i;
153 }
154 LOG_DBG("OPTION %u (delta %u, len %zu)\n", number, number - current_number,
155 i);
156
157 i = coap_set_option_header(number - current_number, i, buffer);
158
159 if(0xFF000000 & value) {
160 buffer[i++] = (uint8_t)(value >> 24);
161 }
162 if(0xFFFF0000 & value) {
163 buffer[i++] = (uint8_t)(value >> 16);
164 }
165 if(0xFFFFFF00 & value) {
166 buffer[i++] = (uint8_t)(value >> 8);
167 }
168 if(0xFFFFFFFF & value) {
169 buffer[i++] = (uint8_t)(value);
170 }
171 return i;
172}
173/*---------------------------------------------------------------------------*/
174static size_t
175coap_serialize_array_option(unsigned int number, unsigned int current_number,
176 uint8_t *buffer, uint8_t *array, size_t length,
177 char split_char)
178{
179 size_t i = 0;
180
181 LOG_DBG("ARRAY type %u, len %zu, full [", number, length);
182 LOG_DBG_COAP_STRING((const char *)array, length);
183 LOG_DBG_("]\n");
184
185 if(split_char != '\0') {
186 int j;
187 uint8_t *part_start = array;
188 uint8_t *part_end = NULL;
189 size_t temp_length;
190
191 for(j = 0; j <= length + 1; ++j) {
192 LOG_DBG("STEP %u/%zu (%c)\n", j, length, array[j]);
193 if(array[j] == split_char || j == length) {
194 part_end = array + j;
195 temp_length = part_end - part_start;
196
197 i += coap_set_option_header(number - current_number, temp_length,
198 &buffer[i]);
199 memcpy(&buffer[i], part_start, temp_length);
200 i += temp_length;
201
202 LOG_DBG("OPTION type %u, delta %u, len %zu, part [", number,
203 number - current_number, i);
204 LOG_DBG_COAP_STRING((const char *)part_start, temp_length);
205 LOG_DBG_("]\n");
206 ++j; /* skip the splitter */
207 current_number = number;
208 part_start = array + j;
209 }
210 } /* for */
211 } else {
212 i += coap_set_option_header(number - current_number, length, &buffer[i]);
213 memcpy(&buffer[i], array, length);
214 i += length;
215
216 LOG_DBG("OPTION type %u, delta %u, len %zu\n", number,
217 number - current_number, length);
218 }
219
220 return i;
221}
222/*---------------------------------------------------------------------------*/
223static void
224coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option,
225 size_t option_len, char separator)
226{
227 /* merge multiple options */
228 if(*dst_len > 0) {
229 /* dst already contains an option: concatenate */
230 (*dst)[*dst_len] = separator;
231 *dst_len += 1;
232
233 /* memmove handles 2-byte option headers */
234 memmove((*dst) + (*dst_len), option, option_len);
235
236 *dst_len += option_len;
237 } else {
238 /* dst is empty: set to option */
239 *dst = (char *)option;
240 *dst_len = option_len;
241 }
242}
243/*---------------------------------------------------------------------------*/
244static int
245coap_get_variable(const char *buffer, size_t length, const char *name,
246 const char **output)
247{
248 const char *start = NULL;
249 const char *end = NULL;
250 const char *value_end = NULL;
251 size_t name_len = 0;
252
253 /*initialize the output buffer first */
254 *output = 0;
255
256 name_len = strlen(name);
257 end = buffer + length;
258
259 for(start = buffer; start + name_len < end; ++start) {
260 if((start == buffer || start[-1] == '&') && start[name_len] == '='
261 && strncmp(name, start, name_len) == 0) {
262
263 /* Point start to variable value */
264 start += name_len + 1;
265
266 /* Point end to the end of the value */
267 value_end = (const char *)memchr(start, '&', end - start);
268 if(value_end == NULL) {
269 value_end = end;
270 }
271 *output = start;
272
273 return value_end - start;
274 }
275 }
276 return 0;
277}
278/*---------------------------------------------------------------------------*/
279/*- Internal API ------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
281void
282coap_init_connection(void)
283{
284 /* initialize transaction ID */
285 current_mid = random_rand();
286}
287/*---------------------------------------------------------------------------*/
288uint16_t
289coap_get_mid()
290{
291 return ++current_mid;
292}
293/*---------------------------------------------------------------------------*/
294void
295coap_init_message(coap_message_t *coap_pkt, coap_message_type_t type,
296 uint8_t code, uint16_t mid)
297{
298 /* Important thing */
299 memset(coap_pkt, 0, sizeof(coap_message_t));
300
301 coap_pkt->type = type;
302 coap_pkt->code = code;
303 coap_pkt->mid = mid;
304}
305/*---------------------------------------------------------------------------*/
306size_t
307coap_serialize_message(coap_message_t *coap_pkt, uint8_t *buffer)
308{
309 uint8_t *option;
310 unsigned int current_number = 0;
311
312 /* Initialize */
313 coap_pkt->buffer = buffer;
314 coap_pkt->version = 1;
315
316 LOG_DBG("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer);
317
318 /* set header fields */
319 coap_pkt->buffer[0] = 0x00;
320 coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK
321 & (coap_pkt->version) << COAP_HEADER_VERSION_POSITION;
322 coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK
323 & (coap_pkt->type) << COAP_HEADER_TYPE_POSITION;
324 coap_pkt->buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK
325 & (coap_pkt->token_len) << COAP_HEADER_TOKEN_LEN_POSITION;
326 coap_pkt->buffer[1] = coap_pkt->code;
327 coap_pkt->buffer[2] = (uint8_t)((coap_pkt->mid) >> 8);
328 coap_pkt->buffer[3] = (uint8_t)(coap_pkt->mid);
329
330 /* empty message, dont need to do more stuff */
331 if(!coap_pkt->code) {
332 LOG_DBG_("-Done serializing empty message at %p-\n", coap_pkt->buffer);
333 return 4;
334 }
335
336 /* set Token */
337 LOG_DBG_("Token (len %u)", coap_pkt->token_len);
338 option = coap_pkt->buffer + COAP_HEADER_LEN;
339 for(current_number = 0; current_number < coap_pkt->token_len;
340 ++current_number) {
341 LOG_DBG_(" %02X", coap_pkt->token[current_number]);
342 *option = coap_pkt->token[current_number];
343 ++option;
344 }
345 LOG_DBG_("-\n");
346
347 /* Serialize options */
348 current_number = 0;
349
350 LOG_DBG("-Serializing options at %p-\n", option);
351
352 /* The options must be serialized in the order of their number */
353 COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match");
354 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0',
355 "Uri-Host");
356 COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag");
357 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH,
358 content_format -
359 coap_pkt->
360 content_format /* hack to get a zero field */,
361 "If-None-Match");
362 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe");
363 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port");
364 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/',
365 "Location-Path");
366 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/',
367 "Uri-Path");
368 LOG_DBG("Serialize content format: %d\n", coap_pkt->content_format);
369 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format,
370 "Content-Format");
371 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age");
372 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&',
373 "Uri-Query");
374 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept");
375 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query,
376 '&', "Location-Query");
377 COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2");
378 COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1");
379 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2");
380 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0',
381 "Proxy-Uri");
382 COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0',
383 "Proxy-Scheme");
384 COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1");
385
386 LOG_DBG("-Done serializing at %p----\n", option);
387
388 /* Pack payload */
389 if((option - coap_pkt->buffer) <= COAP_MAX_HEADER_SIZE) {
390 /* Payload marker */
391 if(coap_pkt->payload_len) {
392 *option = 0xFF;
393 ++option;
394 }
395 memmove(option, coap_pkt->payload, coap_pkt->payload_len);
396 } else {
397 /* an error occurred: caller must check for !=0 */
398 coap_pkt->buffer = NULL;
399 coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE";
400 return 0;
401 }
402
403 LOG_DBG("-Done %u B (header len %u, payload len %u)-\n",
404 (unsigned int)(coap_pkt->payload_len + option - buffer),
405 (unsigned int)(option - buffer),
406 (unsigned int)coap_pkt->payload_len);
407
408 LOG_DBG("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n",
409 coap_pkt->buffer[0], coap_pkt->buffer[1], coap_pkt->buffer[2],
410 coap_pkt->buffer[3], coap_pkt->buffer[4], coap_pkt->buffer[5],
411 coap_pkt->buffer[6], coap_pkt->buffer[7]);
412
413 return (option - buffer) + coap_pkt->payload_len; /* message length */
414}
415/*---------------------------------------------------------------------------*/
416coap_status_t
417coap_parse_message(coap_message_t *coap_pkt, uint8_t *data, uint16_t data_len)
418{
419 if(data_len < COAP_HEADER_LEN) {
420 /* Too short - malformed CoAP message */
421 LOG_WARN("BAD REQUEST: message too short\n");
422 return BAD_REQUEST_4_00;
423 }
424
425 /* initialize message */
426 memset(coap_pkt, 0, sizeof(coap_message_t));
427
428 /* pointer to message bytes */
429 coap_pkt->buffer = data;
430
431 /* parse header fields */
432 coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])
433 >> COAP_HEADER_VERSION_POSITION;
434 coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])
435 >> COAP_HEADER_TYPE_POSITION;
436 coap_pkt->token_len = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->buffer[0])
437 >> COAP_HEADER_TOKEN_LEN_POSITION;
438 coap_pkt->code = coap_pkt->buffer[1];
439 coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3];
440
441 if(coap_pkt->version != 1) {
442 coap_error_message = "CoAP version must be 1";
443 return BAD_REQUEST_4_00;
444 }
445
446 if(coap_pkt->token_len > COAP_TOKEN_LEN) {
447 coap_error_message = "Token Length must not be more than 8";
448 return BAD_REQUEST_4_00;
449 }
450
451 uint8_t *current_option = data + COAP_HEADER_LEN;
452 if(current_option + coap_pkt->token_len > data + data_len) {
453 /* Malformed CoAP message - token length out od message bounds */
454 LOG_WARN("BAD REQUEST: token outside message buffer");
455 return BAD_REQUEST_4_00;
456 }
457
458 memcpy(coap_pkt->token, current_option, coap_pkt->token_len);
459 LOG_DBG("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
460 coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1],
461 coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4],
462 coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7]
463 ); /* FIXME always prints 8 bytes */
464
465 /* parse options */
466 memset(coap_pkt->options, 0, sizeof(coap_pkt->options));
467 current_option += coap_pkt->token_len;
468
469 unsigned int option_number = 0;
470 unsigned int option_delta = 0;
471 size_t option_length = 0;
472
473 while(current_option < data + data_len) {
474 /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */
475 if((current_option[0] & 0xF0) == 0xF0) {
476 coap_pkt->payload = ++current_option;
477 coap_pkt->payload_len = data_len - (coap_pkt->payload - data);
478
479 /* also for receiving, the Erbium upper bound is COAP_MAX_CHUNK_SIZE */
480 if(coap_pkt->payload_len > COAP_MAX_CHUNK_SIZE) {
481 coap_pkt->payload_len = COAP_MAX_CHUNK_SIZE;
482 /* null-terminate payload */
483 }
484 coap_pkt->payload[coap_pkt->payload_len] = '\0';
485
486 break;
487 }
488
489 option_delta = current_option[0] >> 4;
490 option_length = current_option[0] & 0x0F;
491 ++current_option;
492 if(current_option >= data + data_len) {
493 /* Malformed CoAP - out of bounds */
494 LOG_WARN("BAD REQUEST: option delta outside message buffer\n");
495 return BAD_REQUEST_4_00;
496 }
497
498 if(option_delta == 13) {
499 option_delta += current_option[0];
500 ++current_option;
501 } else if(option_delta == 14) {
502 option_delta += 255;
503 option_delta += current_option[0] << 8;
504 ++current_option;
505 if(current_option >= data + data_len) {
506 /* Malformed CoAP - out of bounds */
507 LOG_WARN("BAD REQUEST: option delta outside message buffer\n");
508 return BAD_REQUEST_4_00;
509 }
510 option_delta += current_option[0];
511 ++current_option;
512 }
513
514 if(current_option >= data + data_len) {
515 /* Malformed CoAP - out of bounds */
516 LOG_WARN("BAD REQUEST: option delta outside message buffer\n");
517 return BAD_REQUEST_4_00;
518 }
519
520 if(option_length == 13) {
521 option_length += current_option[0];
522 ++current_option;
523 } else if(option_length == 14) {
524 option_length += 255;
525 option_length += current_option[0] << 8;
526 ++current_option;
527 if(current_option >= data + data_len) {
528 /* Malformed CoAP - out of bounds */
529 LOG_WARN("BAD REQUEST: option length outside message buffer\n");
530 return BAD_REQUEST_4_00;
531 }
532 option_length += current_option[0];
533 ++current_option;
534 }
535
536 if(current_option + option_length > data + data_len) {
537 /* Malformed CoAP - out of bounds */
538 LOG_WARN("BAD REQUEST: options outside data message: %u > %u\n",
539 (unsigned)(current_option + option_length - data), data_len);
540 return BAD_REQUEST_4_00;
541 }
542
543 option_number += option_delta;
544
545 if(option_number > COAP_OPTION_SIZE1) {
546 /* Malformed CoAP - out of bounds */
547 LOG_WARN("BAD REQUEST: option number too large: %u\n", option_number);
548 return BAD_REQUEST_4_00;
549 }
550
551 LOG_DBG("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
552 option_length);
553
554 coap_set_option(coap_pkt, option_number);
555
556 switch(option_number) {
557 case COAP_OPTION_CONTENT_FORMAT:
558 coap_pkt->content_format = coap_parse_int_option(current_option,
559 option_length);
560 LOG_DBG_("Content-Format [%u]\n", coap_pkt->content_format);
561 break;
562 case COAP_OPTION_MAX_AGE:
563 coap_pkt->max_age = coap_parse_int_option(current_option,
564 option_length);
565 LOG_DBG_("Max-Age [%"PRIu32"]\n", coap_pkt->max_age);
566 break;
567 case COAP_OPTION_ETAG:
568 coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length);
569 memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len);
570 LOG_DBG_("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
571 coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1],
572 coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4],
573 coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7]
574 ); /*FIXME always prints 8 bytes */
575 break;
576 case COAP_OPTION_ACCEPT:
577 coap_pkt->accept = coap_parse_int_option(current_option, option_length);
578 LOG_DBG_("Accept [%u]\n", coap_pkt->accept);
579 break;
580 case COAP_OPTION_IF_MATCH:
581 /* TODO support multiple ETags */
582 coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length);
583 memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len);
584 LOG_DBG_("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
585 coap_pkt->if_match_len, coap_pkt->if_match[0],
586 coap_pkt->if_match[1], coap_pkt->if_match[2],
587 coap_pkt->if_match[3], coap_pkt->if_match[4],
588 coap_pkt->if_match[5], coap_pkt->if_match[6],
589 coap_pkt->if_match[7]
590 ); /* FIXME always prints 8 bytes */
591 break;
592 case COAP_OPTION_IF_NONE_MATCH:
593 coap_pkt->if_none_match = 1;
594 LOG_DBG_("If-None-Match\n");
595 break;
596
597 case COAP_OPTION_PROXY_URI:
598#if COAP_PROXY_OPTION_PROCESSING
599 coap_pkt->proxy_uri = (char *)current_option;
600 coap_pkt->proxy_uri_len = option_length;
601#endif /* COAP_PROXY_OPTION_PROCESSING */
602 LOG_DBG_("Proxy-Uri NOT IMPLEMENTED [");
603 LOG_DBG_COAP_STRING(coap_pkt->proxy_uri, coap_pkt->proxy_uri_len);
604 LOG_DBG_("]\n");
605
606 coap_error_message = "This is a constrained server (Contiki)";
607 return PROXYING_NOT_SUPPORTED_5_05;
608 break;
609 case COAP_OPTION_PROXY_SCHEME:
610#if COAP_PROXY_OPTION_PROCESSING
611 coap_pkt->proxy_scheme = (char *)current_option;
612 coap_pkt->proxy_scheme_len = option_length;
613#endif
614 LOG_DBG_("Proxy-Scheme NOT IMPLEMENTED [");
615 LOG_DBG_COAP_STRING(coap_pkt->proxy_scheme, coap_pkt->proxy_scheme_len);
616 LOG_DBG_("]\n");
617 coap_error_message = "This is a constrained server (Contiki)";
618 return PROXYING_NOT_SUPPORTED_5_05;
619 break;
620
621 case COAP_OPTION_URI_HOST:
622 coap_pkt->uri_host = (char *)current_option;
623 coap_pkt->uri_host_len = option_length;
624 LOG_DBG_("Uri-Host [");
625 LOG_DBG_COAP_STRING(coap_pkt->uri_host, coap_pkt->uri_host_len);
626 LOG_DBG_("]\n");
627 break;
628 case COAP_OPTION_URI_PORT:
629 coap_pkt->uri_port = coap_parse_int_option(current_option,
630 option_length);
631 LOG_DBG_("Uri-Port [%u]\n", coap_pkt->uri_port);
632 break;
633 case COAP_OPTION_URI_PATH:
634 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
635 coap_merge_multi_option((char **)&(coap_pkt->uri_path),
636 &(coap_pkt->uri_path_len), current_option,
637 option_length, '/');
638 LOG_DBG_("Uri-Path [");
639 LOG_DBG_COAP_STRING(coap_pkt->uri_path, coap_pkt->uri_path_len);
640 LOG_DBG_("]\n");
641 break;
642 case COAP_OPTION_URI_QUERY:
643 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
644 coap_merge_multi_option((char **)&(coap_pkt->uri_query),
645 &(coap_pkt->uri_query_len), current_option,
646 option_length, '&');
647 LOG_DBG_("Uri-Query[");
648 LOG_DBG_COAP_STRING(coap_pkt->uri_query, coap_pkt->uri_query_len);
649 LOG_DBG_("]\n");
650 break;
651
652 case COAP_OPTION_LOCATION_PATH:
653 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
654 coap_merge_multi_option((char **)&(coap_pkt->location_path),
655 &(coap_pkt->location_path_len), current_option,
656 option_length, '/');
657
658 LOG_DBG_("Location-Path [");
659 LOG_DBG_COAP_STRING(coap_pkt->location_path, coap_pkt->location_path_len);
660 LOG_DBG_("]\n");
661 break;
662 case COAP_OPTION_LOCATION_QUERY:
663 /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
664 coap_merge_multi_option((char **)&(coap_pkt->location_query),
665 &(coap_pkt->location_query_len), current_option,
666 option_length, '&');
667 LOG_DBG_("Location-Query [");
668 LOG_DBG_COAP_STRING(coap_pkt->location_query, coap_pkt->location_query_len);
669 LOG_DBG_("]\n");
670 break;
671
672 case COAP_OPTION_OBSERVE:
673 coap_pkt->observe = coap_parse_int_option(current_option,
674 option_length);
675 LOG_DBG_("Observe [%"PRId32"]\n", coap_pkt->observe);
676 break;
677 case COAP_OPTION_BLOCK2:
678 coap_pkt->block2_num = coap_parse_int_option(current_option,
679 option_length);
680 coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3;
681 coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07);
682 coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F)
683 << (coap_pkt->block2_num & 0x07);
684 coap_pkt->block2_num >>= 4;
685 LOG_DBG_("Block2 [%lu%s (%u B/blk)]\n",
686 (unsigned long)coap_pkt->block2_num,
687 coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size);
688 break;
689 case COAP_OPTION_BLOCK1:
690 coap_pkt->block1_num = coap_parse_int_option(current_option,
691 option_length);
692 coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3;
693 coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07);
694 coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F)
695 << (coap_pkt->block1_num & 0x07);
696 coap_pkt->block1_num >>= 4;
697 LOG_DBG_("Block1 [%lu%s (%u B/blk)]\n",
698 (unsigned long)coap_pkt->block1_num,
699 coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size);
700 break;
701 case COAP_OPTION_SIZE2:
702 coap_pkt->size2 = coap_parse_int_option(current_option, option_length);
703 LOG_DBG_("Size2 [%"PRIu32"]\n", coap_pkt->size2);
704 break;
705 case COAP_OPTION_SIZE1:
706 coap_pkt->size1 = coap_parse_int_option(current_option, option_length);
707 LOG_DBG_("Size1 [%"PRIu32"]\n", coap_pkt->size1);
708 break;
709 default:
710 LOG_DBG_("unknown (%u)\n", option_number);
711 /* check if critical (odd) */
712 if(option_number & 1) {
713 coap_error_message = "Unsupported critical option";
714 return BAD_OPTION_4_02;
715 }
716 }
717
718 current_option += option_length;
719 } /* for */
720 LOG_DBG("-Done parsing-------\n");
721
722 return NO_ERROR;
723}
724/*---------------------------------------------------------------------------*/
725/*- CoAP Engine API ---------------------------------------------------------*/
726/*---------------------------------------------------------------------------*/
727int
728coap_get_query_variable(coap_message_t *coap_pkt,
729 const char *name, const char **output)
730{
731 if(coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
732 return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len,
733 name, output);
734 }
735 return 0;
736}
737int
738coap_get_post_variable(coap_message_t *coap_pkt,
739 const char *name, const char **output)
740{
741 if(coap_pkt->payload_len) {
742 return coap_get_variable((const char *)coap_pkt->payload,
743 coap_pkt->payload_len, name, output);
744 }
745 return 0;
746}
747/*---------------------------------------------------------------------------*/
748int
749coap_set_status_code(coap_message_t *message, unsigned int code)
750{
751 if(code <= 0xFF) {
752 message->code = (uint8_t)code;
753 return 1;
754 } else {
755 return 0;
756 }
757}
758/*---------------------------------------------------------------------------*/
759int
760coap_set_token(coap_message_t *coap_pkt, const uint8_t *token, size_t token_len)
761{
762 coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len);
763 memcpy(coap_pkt->token, token, coap_pkt->token_len);
764
765 return coap_pkt->token_len;
766}
767/*---------------------------------------------------------------------------*/
768/*- CoAP Implementation API -------------------------------------------------*/
769/*---------------------------------------------------------------------------*/
770int
771coap_get_header_content_format(coap_message_t *coap_pkt, unsigned int *format)
772{
773 if(!coap_is_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) {
774 return 0;
775 }
776 *format = coap_pkt->content_format;
777 return 1;
778}
779int
780coap_set_header_content_format(coap_message_t *coap_pkt, unsigned int format)
781{
782 coap_pkt->content_format = format;
783 coap_set_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT);
784 return 1;
785}
786/*---------------------------------------------------------------------------*/
787int
788coap_get_header_accept(coap_message_t *coap_pkt, unsigned int *accept)
789{
790 if(!coap_is_option(coap_pkt, COAP_OPTION_ACCEPT)) {
791 return 0;
792 }
793 *accept = coap_pkt->accept;
794 return 1;
795}
796int
797coap_set_header_accept(coap_message_t *coap_pkt, unsigned int accept)
798{
799 coap_pkt->accept = accept;
800 coap_set_option(coap_pkt, COAP_OPTION_ACCEPT);
801 return 1;
802}
803/*---------------------------------------------------------------------------*/
804int
805coap_get_header_max_age(coap_message_t *coap_pkt, uint32_t *age)
806{
807 if(!coap_is_option(coap_pkt, COAP_OPTION_MAX_AGE)) {
808 *age = COAP_DEFAULT_MAX_AGE;
809 } else {
810 *age = coap_pkt->max_age;
811 } return 1;
812}
813int
814coap_set_header_max_age(coap_message_t *coap_pkt, uint32_t age)
815{
816 coap_pkt->max_age = age;
817 coap_set_option(coap_pkt, COAP_OPTION_MAX_AGE);
818 return 1;
819}
820/*---------------------------------------------------------------------------*/
821int
822coap_get_header_etag(coap_message_t *coap_pkt, const uint8_t **etag)
823{
824 if(!coap_is_option(coap_pkt, COAP_OPTION_ETAG)) {
825 return 0;
826 }
827 *etag = coap_pkt->etag;
828 return coap_pkt->etag_len;
829}
830int
831coap_set_header_etag(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
832{
833 coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len);
834 memcpy(coap_pkt->etag, etag, coap_pkt->etag_len);
835
836 coap_set_option(coap_pkt, COAP_OPTION_ETAG);
837 return coap_pkt->etag_len;
838}
839/*---------------------------------------------------------------------------*/
840/*FIXME support multiple ETags */
841int
842coap_get_header_if_match(coap_message_t *coap_pkt, const uint8_t **etag)
843{
844 if(!coap_is_option(coap_pkt, COAP_OPTION_IF_MATCH)) {
845 return 0;
846 }
847 *etag = coap_pkt->if_match;
848 return coap_pkt->if_match_len;
849}
850int
851coap_set_header_if_match(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
852{
853 coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len);
854 memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len);
855
856 coap_set_option(coap_pkt, COAP_OPTION_IF_MATCH);
857 return coap_pkt->if_match_len;
858}
859/*---------------------------------------------------------------------------*/
860int
861coap_get_header_if_none_match(coap_message_t *message)
862{
863 return coap_is_option(message, COAP_OPTION_IF_NONE_MATCH) ? 1 : 0;
864}
865int
866coap_set_header_if_none_match(coap_message_t *message)
867{
868 coap_set_option(message, COAP_OPTION_IF_NONE_MATCH);
869 return 1;
870}
871/*---------------------------------------------------------------------------*/
872int
873coap_get_header_proxy_uri(coap_message_t *coap_pkt, const char **uri)
874{
875 if(!coap_is_option(coap_pkt, COAP_OPTION_PROXY_URI)) {
876 return 0;
877 }
878 *uri = coap_pkt->proxy_uri;
879 return coap_pkt->proxy_uri_len;
880}
881int
882coap_set_header_proxy_uri(coap_message_t *coap_pkt, const char *uri)
883{
884 /* TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide coap-conf define */
885
886 coap_pkt->proxy_uri = uri;
887 coap_pkt->proxy_uri_len = strlen(uri);
888
889 coap_set_option(coap_pkt, COAP_OPTION_PROXY_URI);
890 return coap_pkt->proxy_uri_len;
891}
892/*---------------------------------------------------------------------------*/
893int
894coap_get_header_uri_host(coap_message_t *coap_pkt, const char **host)
895{
896 if(!coap_is_option(coap_pkt, COAP_OPTION_URI_HOST)) {
897 return 0;
898 }
899 *host = coap_pkt->uri_host;
900 return coap_pkt->uri_host_len;
901}
902int
903coap_set_header_uri_host(coap_message_t *coap_pkt, const char *host)
904{
905 coap_pkt->uri_host = host;
906 coap_pkt->uri_host_len = strlen(host);
907
908 coap_set_option(coap_pkt, COAP_OPTION_URI_HOST);
909 return coap_pkt->uri_host_len;
910}
911/*---------------------------------------------------------------------------*/
912int
913coap_get_header_uri_path(coap_message_t *coap_pkt, const char **path)
914{
915 if(!coap_is_option(coap_pkt, COAP_OPTION_URI_PATH)) {
916 return 0;
917 }
918 *path = coap_pkt->uri_path;
919 return coap_pkt->uri_path_len;
920}
921int
922coap_set_header_uri_path(coap_message_t *coap_pkt, const char *path)
923{
924 while(path[0] == '/') {
925 ++path;
926 }
927
928 coap_pkt->uri_path = path;
929 coap_pkt->uri_path_len = strlen(path);
930
931 coap_set_option(coap_pkt, COAP_OPTION_URI_PATH);
932 return coap_pkt->uri_path_len;
933}
934/*---------------------------------------------------------------------------*/
935int
936coap_get_header_uri_query(coap_message_t *coap_pkt, const char **query)
937{
938 if(!coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
939 return 0;
940 }
941 *query = coap_pkt->uri_query;
942 return coap_pkt->uri_query_len;
943}
944int
945coap_set_header_uri_query(coap_message_t *coap_pkt, const char *query)
946{
947 while(query[0] == '?') {
948 ++query;
949 }
950
951 coap_pkt->uri_query = query;
952 coap_pkt->uri_query_len = strlen(query);
953
954 coap_set_option(coap_pkt, COAP_OPTION_URI_QUERY);
955 return coap_pkt->uri_query_len;
956}
957/*---------------------------------------------------------------------------*/
958int
959coap_get_header_location_path(coap_message_t *coap_pkt, const char **path)
960{
961 if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_PATH)) {
962 return 0;
963 }
964 *path = coap_pkt->location_path;
965 return coap_pkt->location_path_len;
966}
967int
968coap_set_header_location_path(coap_message_t *coap_pkt, const char *path)
969{
970 char *query;
971
972 while(path[0] == '/') {
973 ++path;
974 }
975
976 if((query = strchr(path, '?'))) {
977 coap_set_header_location_query(coap_pkt, query + 1);
978 coap_pkt->location_path_len = query - path;
979 } else {
980 coap_pkt->location_path_len = strlen(path);
981 } coap_pkt->location_path = path;
982
983 if(coap_pkt->location_path_len > 0) {
984 coap_set_option(coap_pkt, COAP_OPTION_LOCATION_PATH);
985 }
986 return coap_pkt->location_path_len;
987}
988/*---------------------------------------------------------------------------*/
989int
990coap_get_header_location_query(coap_message_t *coap_pkt, const char **query)
991{
992 if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_QUERY)) {
993 return 0;
994 }
995 *query = coap_pkt->location_query;
996 return coap_pkt->location_query_len;
997}
998int
999coap_set_header_location_query(coap_message_t *coap_pkt, const char *query)
1000{
1001 while(query[0] == '?') {
1002 ++query;
1003 }
1004
1005 coap_pkt->location_query = query;
1006 coap_pkt->location_query_len = strlen(query);
1007
1008 coap_set_option(coap_pkt, COAP_OPTION_LOCATION_QUERY);
1009 return coap_pkt->location_query_len;
1010}
1011/*---------------------------------------------------------------------------*/
1012int
1013coap_get_header_observe(coap_message_t *coap_pkt, uint32_t *observe)
1014{
1015 if(!coap_is_option(coap_pkt, COAP_OPTION_OBSERVE)) {
1016 return 0;
1017 }
1018 *observe = coap_pkt->observe;
1019 return 1;
1020}
1021int
1022coap_set_header_observe(coap_message_t *coap_pkt, uint32_t observe)
1023{
1024 coap_pkt->observe = observe;
1025 coap_set_option(coap_pkt, COAP_OPTION_OBSERVE);
1026 return 1;
1027}
1028/*---------------------------------------------------------------------------*/
1029int
1030coap_get_header_block2(coap_message_t *coap_pkt, uint32_t *num, uint8_t *more,
1031 uint16_t *size, uint32_t *offset)
1032{
1033 if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK2)) {
1034 return 0;
1035 }
1036 /* pointers may be NULL to get only specific block parameters */
1037 if(num != NULL) {
1038 *num = coap_pkt->block2_num;
1039 }
1040 if(more != NULL) {
1041 *more = coap_pkt->block2_more;
1042 }
1043 if(size != NULL) {
1044 *size = coap_pkt->block2_size;
1045 }
1046 if(offset != NULL) {
1047 *offset = coap_pkt->block2_offset;
1048 }
1049 return 1;
1050}
1051int
1052coap_set_header_block2(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1053 uint16_t size)
1054{
1055 if(size < 16) {
1056 return 0;
1057 }
1058 if(size > 2048) {
1059 return 0;
1060 }
1061 if(num > 0x0FFFFF) {
1062 return 0;
1063 }
1064 coap_pkt->block2_num = num;
1065 coap_pkt->block2_more = more ? 1 : 0;
1066 coap_pkt->block2_size = size;
1067
1068 coap_set_option(coap_pkt, COAP_OPTION_BLOCK2);
1069 return 1;
1070}
1071/*---------------------------------------------------------------------------*/
1072int
1073coap_get_header_block1(coap_message_t *coap_pkt, uint32_t *num, uint8_t *more,
1074 uint16_t *size, uint32_t *offset)
1075{
1076 if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK1)) {
1077 return 0;
1078 }
1079 /* pointers may be NULL to get only specific block parameters */
1080 if(num != NULL) {
1081 *num = coap_pkt->block1_num;
1082 }
1083 if(more != NULL) {
1084 *more = coap_pkt->block1_more;
1085 }
1086 if(size != NULL) {
1087 *size = coap_pkt->block1_size;
1088 }
1089 if(offset != NULL) {
1090 *offset = coap_pkt->block1_offset;
1091 }
1092 return 1;
1093}
1094int
1095coap_set_header_block1(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1096 uint16_t size)
1097{
1098 if(size < 16) {
1099 return 0;
1100 }
1101 if(size > 2048) {
1102 return 0;
1103 }
1104 if(num > 0x0FFFFF) {
1105 return 0;
1106 }
1107 coap_pkt->block1_num = num;
1108 coap_pkt->block1_more = more;
1109 coap_pkt->block1_size = size;
1110
1111 coap_set_option(coap_pkt, COAP_OPTION_BLOCK1);
1112 return 1;
1113}
1114/*---------------------------------------------------------------------------*/
1115int
1116coap_get_header_size2(coap_message_t *coap_pkt, uint32_t *size)
1117{
1118 if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE2)) {
1119 return 0;
1120 }
1121 *size = coap_pkt->size2;
1122 return 1;
1123}
1124int
1125coap_set_header_size2(coap_message_t *coap_pkt, uint32_t size)
1126{
1127 coap_pkt->size2 = size;
1128 coap_set_option(coap_pkt, COAP_OPTION_SIZE2);
1129 return 1;
1130}
1131/*---------------------------------------------------------------------------*/
1132int
1133coap_get_header_size1(coap_message_t *coap_pkt, uint32_t *size)
1134{
1135 if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE1)) {
1136 return 0;
1137 }
1138 *size = coap_pkt->size1;
1139 return 1;
1140}
1141int
1142coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size)
1143{
1144 coap_pkt->size1 = size;
1145 coap_set_option(coap_pkt, COAP_OPTION_SIZE1);
1146 return 1;
1147}
1148/*---------------------------------------------------------------------------*/
1149int
1150coap_get_payload(coap_message_t *coap_pkt, const uint8_t **payload)
1151{
1152 if(payload != NULL) {
1153 *payload = coap_pkt->payload;
1154 }
1155 return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0;
1156}
1157int
1158coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length)
1159{
1160 coap_pkt->payload = (uint8_t *)payload;
1161 coap_pkt->payload_len = MIN(COAP_MAX_CHUNK_SIZE, length);
1162
1163 return coap_pkt->payload_len;
1164}
1165/*---------------------------------------------------------------------------*/
1166/** @} */
Default definitions of C compiler quirk work-arounds.
Log support for CoAP.
CoAP module for reliable transport.
An implementation of the Constrained Application Protocol (RFC 7252).
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58
static uint8_t accept(uint8_t in)
Definition: mpl.c:1391
static void start(void)
Start measurement.
static uint8_t output(const linkaddr_t *localdest)
Take an IP packet and format it to be sent on an 802.15.4 network using 6lowpan.
Definition: sicslowpan.c:1606