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