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 /*---------------------------------------------------------------------------*/
65 static uint16_t current_mid = 0;
66 
67 coap_status_t coap_status_code = NO_ERROR;
68 const char *coap_error_message = "";
69 /*---------------------------------------------------------------------------*/
70 /*- Local helper functions --------------------------------------------------*/
71 /*---------------------------------------------------------------------------*/
72 static uint16_t
73 coap_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 /*---------------------------------------------------------------------------*/
85 static uint32_t
86 coap_parse_int_option(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 /*---------------------------------------------------------------------------*/
98 static uint8_t
99 coap_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 /*---------------------------------------------------------------------------*/
110 static size_t
111 coap_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 /*---------------------------------------------------------------------------*/
136 static size_t
137 coap_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 /*---------------------------------------------------------------------------*/
174 static size_t
175 coap_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 /*---------------------------------------------------------------------------*/
223 static void
224 coap_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 /*---------------------------------------------------------------------------*/
244 static int
245 coap_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 /*---------------------------------------------------------------------------*/
281 void
282 coap_init_connection(void)
283 {
284  /* initialize transaction ID */
285  current_mid = random_rand();
286 }
287 /*---------------------------------------------------------------------------*/
288 uint16_t
289 coap_get_mid()
290 {
291  return ++current_mid;
292 }
293 /*---------------------------------------------------------------------------*/
294 void
295 coap_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 /*---------------------------------------------------------------------------*/
306 size_t
307 coap_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 /*---------------------------------------------------------------------------*/
416 coap_status_t
417 coap_parse_message(coap_message_t *coap_pkt, uint8_t *data, uint16_t data_len)
418 {
419  /* initialize message */
420  memset(coap_pkt, 0, sizeof(coap_message_t));
421 
422  /* pointer to message bytes */
423  coap_pkt->buffer = data;
424 
425  /* parse header fields */
426  coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])
427  >> COAP_HEADER_VERSION_POSITION;
428  coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])
429  >> COAP_HEADER_TYPE_POSITION;
430  coap_pkt->token_len = (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt->buffer[0])
431  >> COAP_HEADER_TOKEN_LEN_POSITION;
432  coap_pkt->code = coap_pkt->buffer[1];
433  coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3];
434 
435  if(coap_pkt->version != 1) {
436  coap_error_message = "CoAP version must be 1";
437  return BAD_REQUEST_4_00;
438  }
439 
440  if(coap_pkt->token_len > COAP_TOKEN_LEN) {
441  coap_error_message = "Token Length must not be more than 8";
442  return BAD_REQUEST_4_00;
443  }
444 
445  uint8_t *current_option = data + COAP_HEADER_LEN;
446 
447  memcpy(coap_pkt->token, current_option, coap_pkt->token_len);
448  LOG_DBG("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
449  coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1],
450  coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4],
451  coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7]
452  ); /* FIXME always prints 8 bytes */
453 
454  /* parse options */
455  memset(coap_pkt->options, 0, sizeof(coap_pkt->options));
456  current_option += coap_pkt->token_len;
457 
458  unsigned int option_number = 0;
459  unsigned int option_delta = 0;
460  size_t option_length = 0;
461 
462  while(current_option < data + data_len) {
463  /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */
464  if((current_option[0] & 0xF0) == 0xF0) {
465  coap_pkt->payload = ++current_option;
466  coap_pkt->payload_len = data_len - (coap_pkt->payload - data);
467 
468  /* also for receiving, the Erbium upper bound is COAP_MAX_CHUNK_SIZE */
469  if(coap_pkt->payload_len > COAP_MAX_CHUNK_SIZE) {
470  coap_pkt->payload_len = COAP_MAX_CHUNK_SIZE;
471  /* null-terminate payload */
472  }
473  coap_pkt->payload[coap_pkt->payload_len] = '\0';
474 
475  break;
476  }
477 
478  option_delta = current_option[0] >> 4;
479  option_length = current_option[0] & 0x0F;
480  ++current_option;
481 
482  if(option_delta == 13) {
483  option_delta += current_option[0];
484  ++current_option;
485  } else if(option_delta == 14) {
486  option_delta += 255;
487  option_delta += current_option[0] << 8;
488  ++current_option;
489  option_delta += current_option[0];
490  ++current_option;
491  }
492 
493  if(option_length == 13) {
494  option_length += current_option[0];
495  ++current_option;
496  } else if(option_length == 14) {
497  option_length += 255;
498  option_length += current_option[0] << 8;
499  ++current_option;
500  option_length += current_option[0];
501  ++current_option;
502  }
503 
504  if(current_option + option_length > data + data_len) {
505  /* Malformed CoAP - out of bounds */
506  LOG_WARN("BAD REQUEST: options outside data message: %u > %u\n",
507  (unsigned)(current_option + option_length - data), data_len);
508  return BAD_REQUEST_4_00;
509  }
510 
511  option_number += option_delta;
512 
513  if(option_number > COAP_OPTION_SIZE1) {
514  /* Malformed CoAP - out of bounds */
515  LOG_WARN("BAD REQUEST: option number too large: %u\n", option_number);
516  return BAD_REQUEST_4_00;
517  }
518 
519  LOG_DBG("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
520  option_length);
521 
522  coap_set_option(coap_pkt, option_number);
523 
524  switch(option_number) {
525  case COAP_OPTION_CONTENT_FORMAT:
526  coap_pkt->content_format = coap_parse_int_option(current_option,
527  option_length);
528  LOG_DBG_("Content-Format [%u]\n", coap_pkt->content_format);
529  break;
530  case COAP_OPTION_MAX_AGE:
531  coap_pkt->max_age = coap_parse_int_option(current_option,
532  option_length);
533  LOG_DBG_("Max-Age [%"PRIu32"]\n", coap_pkt->max_age);
534  break;
535  case COAP_OPTION_ETAG:
536  coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length);
537  memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len);
538  LOG_DBG_("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
539  coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1],
540  coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4],
541  coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7]
542  ); /*FIXME always prints 8 bytes */
543  break;
544  case COAP_OPTION_ACCEPT:
545  coap_pkt->accept = coap_parse_int_option(current_option, option_length);
546  LOG_DBG_("Accept [%u]\n", coap_pkt->accept);
547  break;
548  case COAP_OPTION_IF_MATCH:
549  /* TODO support multiple ETags */
550  coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length);
551  memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len);
552  LOG_DBG_("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n",
553  coap_pkt->if_match_len, coap_pkt->if_match[0],
554  coap_pkt->if_match[1], coap_pkt->if_match[2],
555  coap_pkt->if_match[3], coap_pkt->if_match[4],
556  coap_pkt->if_match[5], coap_pkt->if_match[6],
557  coap_pkt->if_match[7]
558  ); /* FIXME always prints 8 bytes */
559  break;
560  case COAP_OPTION_IF_NONE_MATCH:
561  coap_pkt->if_none_match = 1;
562  LOG_DBG_("If-None-Match\n");
563  break;
564 
565  case COAP_OPTION_PROXY_URI:
566 #if COAP_PROXY_OPTION_PROCESSING
567  coap_pkt->proxy_uri = (char *)current_option;
568  coap_pkt->proxy_uri_len = option_length;
569 #endif /* COAP_PROXY_OPTION_PROCESSING */
570  LOG_DBG_("Proxy-Uri NOT IMPLEMENTED [");
571  LOG_DBG_COAP_STRING(coap_pkt->proxy_uri, coap_pkt->proxy_uri_len);
572  LOG_DBG_("]\n");
573 
574  coap_error_message = "This is a constrained server (Contiki)";
575  return PROXYING_NOT_SUPPORTED_5_05;
576  break;
577  case COAP_OPTION_PROXY_SCHEME:
578 #if COAP_PROXY_OPTION_PROCESSING
579  coap_pkt->proxy_scheme = (char *)current_option;
580  coap_pkt->proxy_scheme_len = option_length;
581 #endif
582  LOG_DBG_("Proxy-Scheme NOT IMPLEMENTED [");
583  LOG_DBG_COAP_STRING(coap_pkt->proxy_scheme, coap_pkt->proxy_scheme_len);
584  LOG_DBG_("]\n");
585  coap_error_message = "This is a constrained server (Contiki)";
586  return PROXYING_NOT_SUPPORTED_5_05;
587  break;
588 
589  case COAP_OPTION_URI_HOST:
590  coap_pkt->uri_host = (char *)current_option;
591  coap_pkt->uri_host_len = option_length;
592  LOG_DBG_("Uri-Host [");
593  LOG_DBG_COAP_STRING(coap_pkt->uri_host, coap_pkt->uri_host_len);
594  LOG_DBG_("]\n");
595  break;
596  case COAP_OPTION_URI_PORT:
597  coap_pkt->uri_port = coap_parse_int_option(current_option,
598  option_length);
599  LOG_DBG_("Uri-Port [%u]\n", coap_pkt->uri_port);
600  break;
601  case COAP_OPTION_URI_PATH:
602  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
603  coap_merge_multi_option((char **)&(coap_pkt->uri_path),
604  &(coap_pkt->uri_path_len), current_option,
605  option_length, '/');
606  LOG_DBG_("Uri-Path [");
607  LOG_DBG_COAP_STRING(coap_pkt->uri_path, coap_pkt->uri_path_len);
608  LOG_DBG_("]\n");
609  break;
610  case COAP_OPTION_URI_QUERY:
611  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
612  coap_merge_multi_option((char **)&(coap_pkt->uri_query),
613  &(coap_pkt->uri_query_len), current_option,
614  option_length, '&');
615  LOG_DBG_("Uri-Query[");
616  LOG_DBG_COAP_STRING(coap_pkt->uri_query, coap_pkt->uri_query_len);
617  LOG_DBG_("]\n");
618  break;
619 
620  case COAP_OPTION_LOCATION_PATH:
621  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
622  coap_merge_multi_option((char **)&(coap_pkt->location_path),
623  &(coap_pkt->location_path_len), current_option,
624  option_length, '/');
625 
626  LOG_DBG_("Location-Path [");
627  LOG_DBG_COAP_STRING(coap_pkt->location_path, coap_pkt->location_path_len);
628  LOG_DBG_("]\n");
629  break;
630  case COAP_OPTION_LOCATION_QUERY:
631  /* coap_merge_multi_option() operates in-place on the IPBUF, but final message field should be const string -> cast to string */
632  coap_merge_multi_option((char **)&(coap_pkt->location_query),
633  &(coap_pkt->location_query_len), current_option,
634  option_length, '&');
635  LOG_DBG_("Location-Query [");
636  LOG_DBG_COAP_STRING(coap_pkt->location_query, coap_pkt->location_query_len);
637  LOG_DBG_("]\n");
638  break;
639 
640  case COAP_OPTION_OBSERVE:
641  coap_pkt->observe = coap_parse_int_option(current_option,
642  option_length);
643  LOG_DBG_("Observe [%"PRId32"]\n", coap_pkt->observe);
644  break;
645  case COAP_OPTION_BLOCK2:
646  coap_pkt->block2_num = coap_parse_int_option(current_option,
647  option_length);
648  coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3;
649  coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07);
650  coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F)
651  << (coap_pkt->block2_num & 0x07);
652  coap_pkt->block2_num >>= 4;
653  LOG_DBG_("Block2 [%lu%s (%u B/blk)]\n",
654  (unsigned long)coap_pkt->block2_num,
655  coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size);
656  break;
657  case COAP_OPTION_BLOCK1:
658  coap_pkt->block1_num = coap_parse_int_option(current_option,
659  option_length);
660  coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3;
661  coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07);
662  coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F)
663  << (coap_pkt->block1_num & 0x07);
664  coap_pkt->block1_num >>= 4;
665  LOG_DBG_("Block1 [%lu%s (%u B/blk)]\n",
666  (unsigned long)coap_pkt->block1_num,
667  coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size);
668  break;
669  case COAP_OPTION_SIZE2:
670  coap_pkt->size2 = coap_parse_int_option(current_option, option_length);
671  LOG_DBG_("Size2 [%"PRIu32"]\n", coap_pkt->size2);
672  break;
673  case COAP_OPTION_SIZE1:
674  coap_pkt->size1 = coap_parse_int_option(current_option, option_length);
675  LOG_DBG_("Size1 [%"PRIu32"]\n", coap_pkt->size1);
676  break;
677  default:
678  LOG_DBG_("unknown (%u)\n", option_number);
679  /* check if critical (odd) */
680  if(option_number & 1) {
681  coap_error_message = "Unsupported critical option";
682  return BAD_OPTION_4_02;
683  }
684  }
685 
686  current_option += option_length;
687  } /* for */
688  LOG_DBG("-Done parsing-------\n");
689 
690  return NO_ERROR;
691 }
692 /*---------------------------------------------------------------------------*/
693 /*- CoAP Engine API ---------------------------------------------------------*/
694 /*---------------------------------------------------------------------------*/
695 int
696 coap_get_query_variable(coap_message_t *coap_pkt,
697  const char *name, const char **output)
698 {
699  if(coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
700  return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len,
701  name, output);
702  }
703  return 0;
704 }
705 int
706 coap_get_post_variable(coap_message_t *coap_pkt,
707  const char *name, const char **output)
708 {
709  if(coap_pkt->payload_len) {
710  return coap_get_variable((const char *)coap_pkt->payload,
711  coap_pkt->payload_len, name, output);
712  }
713  return 0;
714 }
715 /*---------------------------------------------------------------------------*/
716 int
717 coap_set_status_code(coap_message_t *message, unsigned int code)
718 {
719  if(code <= 0xFF) {
720  message->code = (uint8_t)code;
721  return 1;
722  } else {
723  return 0;
724  }
725 }
726 /*---------------------------------------------------------------------------*/
727 int
728 coap_set_token(coap_message_t *coap_pkt, const uint8_t *token, size_t token_len)
729 {
730  coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len);
731  memcpy(coap_pkt->token, token, coap_pkt->token_len);
732 
733  return coap_pkt->token_len;
734 }
735 /*---------------------------------------------------------------------------*/
736 /*- CoAP Implementation API -------------------------------------------------*/
737 /*---------------------------------------------------------------------------*/
738 int
739 coap_get_header_content_format(coap_message_t *coap_pkt, unsigned int *format)
740 {
741  if(!coap_is_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) {
742  return 0;
743  }
744  *format = coap_pkt->content_format;
745  return 1;
746 }
747 int
748 coap_set_header_content_format(coap_message_t *coap_pkt, unsigned int format)
749 {
750  coap_pkt->content_format = format;
751  coap_set_option(coap_pkt, COAP_OPTION_CONTENT_FORMAT);
752  return 1;
753 }
754 /*---------------------------------------------------------------------------*/
755 int
756 coap_get_header_accept(coap_message_t *coap_pkt, unsigned int *accept)
757 {
758  if(!coap_is_option(coap_pkt, COAP_OPTION_ACCEPT)) {
759  return 0;
760  }
761  *accept = coap_pkt->accept;
762  return 1;
763 }
764 int
765 coap_set_header_accept(coap_message_t *coap_pkt, unsigned int accept)
766 {
767  coap_pkt->accept = accept;
768  coap_set_option(coap_pkt, COAP_OPTION_ACCEPT);
769  return 1;
770 }
771 /*---------------------------------------------------------------------------*/
772 int
773 coap_get_header_max_age(coap_message_t *coap_pkt, uint32_t *age)
774 {
775  if(!coap_is_option(coap_pkt, COAP_OPTION_MAX_AGE)) {
776  *age = COAP_DEFAULT_MAX_AGE;
777  } else {
778  *age = coap_pkt->max_age;
779  } return 1;
780 }
781 int
782 coap_set_header_max_age(coap_message_t *coap_pkt, uint32_t age)
783 {
784  coap_pkt->max_age = age;
785  coap_set_option(coap_pkt, COAP_OPTION_MAX_AGE);
786  return 1;
787 }
788 /*---------------------------------------------------------------------------*/
789 int
790 coap_get_header_etag(coap_message_t *coap_pkt, const uint8_t **etag)
791 {
792  if(!coap_is_option(coap_pkt, COAP_OPTION_ETAG)) {
793  return 0;
794  }
795  *etag = coap_pkt->etag;
796  return coap_pkt->etag_len;
797 }
798 int
799 coap_set_header_etag(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
800 {
801  coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len);
802  memcpy(coap_pkt->etag, etag, coap_pkt->etag_len);
803 
804  coap_set_option(coap_pkt, COAP_OPTION_ETAG);
805  return coap_pkt->etag_len;
806 }
807 /*---------------------------------------------------------------------------*/
808 /*FIXME support multiple ETags */
809 int
810 coap_get_header_if_match(coap_message_t *coap_pkt, const uint8_t **etag)
811 {
812  if(!coap_is_option(coap_pkt, COAP_OPTION_IF_MATCH)) {
813  return 0;
814  }
815  *etag = coap_pkt->if_match;
816  return coap_pkt->if_match_len;
817 }
818 int
819 coap_set_header_if_match(coap_message_t *coap_pkt, const uint8_t *etag, size_t etag_len)
820 {
821  coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len);
822  memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len);
823 
824  coap_set_option(coap_pkt, COAP_OPTION_IF_MATCH);
825  return coap_pkt->if_match_len;
826 }
827 /*---------------------------------------------------------------------------*/
828 int
829 coap_get_header_if_none_match(coap_message_t *message)
830 {
831  return coap_is_option(message, COAP_OPTION_IF_NONE_MATCH) ? 1 : 0;
832 }
833 int
834 coap_set_header_if_none_match(coap_message_t *message)
835 {
836  coap_set_option(message, COAP_OPTION_IF_NONE_MATCH);
837  return 1;
838 }
839 /*---------------------------------------------------------------------------*/
840 int
841 coap_get_header_proxy_uri(coap_message_t *coap_pkt, const char **uri)
842 {
843  if(!coap_is_option(coap_pkt, COAP_OPTION_PROXY_URI)) {
844  return 0;
845  }
846  *uri = coap_pkt->proxy_uri;
847  return coap_pkt->proxy_uri_len;
848 }
849 int
850 coap_set_header_proxy_uri(coap_message_t *coap_pkt, const char *uri)
851 {
852  /* TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide coap-conf define */
853 
854  coap_pkt->proxy_uri = uri;
855  coap_pkt->proxy_uri_len = strlen(uri);
856 
857  coap_set_option(coap_pkt, COAP_OPTION_PROXY_URI);
858  return coap_pkt->proxy_uri_len;
859 }
860 /*---------------------------------------------------------------------------*/
861 int
862 coap_get_header_uri_host(coap_message_t *coap_pkt, const char **host)
863 {
864  if(!coap_is_option(coap_pkt, COAP_OPTION_URI_HOST)) {
865  return 0;
866  }
867  *host = coap_pkt->uri_host;
868  return coap_pkt->uri_host_len;
869 }
870 int
871 coap_set_header_uri_host(coap_message_t *coap_pkt, const char *host)
872 {
873  coap_pkt->uri_host = host;
874  coap_pkt->uri_host_len = strlen(host);
875 
876  coap_set_option(coap_pkt, COAP_OPTION_URI_HOST);
877  return coap_pkt->uri_host_len;
878 }
879 /*---------------------------------------------------------------------------*/
880 int
881 coap_get_header_uri_path(coap_message_t *coap_pkt, const char **path)
882 {
883  if(!coap_is_option(coap_pkt, COAP_OPTION_URI_PATH)) {
884  return 0;
885  }
886  *path = coap_pkt->uri_path;
887  return coap_pkt->uri_path_len;
888 }
889 int
890 coap_set_header_uri_path(coap_message_t *coap_pkt, const char *path)
891 {
892  while(path[0] == '/') {
893  ++path;
894  }
895 
896  coap_pkt->uri_path = path;
897  coap_pkt->uri_path_len = strlen(path);
898 
899  coap_set_option(coap_pkt, COAP_OPTION_URI_PATH);
900  return coap_pkt->uri_path_len;
901 }
902 /*---------------------------------------------------------------------------*/
903 int
904 coap_get_header_uri_query(coap_message_t *coap_pkt, const char **query)
905 {
906  if(!coap_is_option(coap_pkt, COAP_OPTION_URI_QUERY)) {
907  return 0;
908  }
909  *query = coap_pkt->uri_query;
910  return coap_pkt->uri_query_len;
911 }
912 int
913 coap_set_header_uri_query(coap_message_t *coap_pkt, const char *query)
914 {
915  while(query[0] == '?') {
916  ++query;
917  }
918 
919  coap_pkt->uri_query = query;
920  coap_pkt->uri_query_len = strlen(query);
921 
922  coap_set_option(coap_pkt, COAP_OPTION_URI_QUERY);
923  return coap_pkt->uri_query_len;
924 }
925 /*---------------------------------------------------------------------------*/
926 int
927 coap_get_header_location_path(coap_message_t *coap_pkt, const char **path)
928 {
929  if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_PATH)) {
930  return 0;
931  }
932  *path = coap_pkt->location_path;
933  return coap_pkt->location_path_len;
934 }
935 int
936 coap_set_header_location_path(coap_message_t *coap_pkt, const char *path)
937 {
938  char *query;
939 
940  while(path[0] == '/') {
941  ++path;
942  }
943 
944  if((query = strchr(path, '?'))) {
945  coap_set_header_location_query(coap_pkt, query + 1);
946  coap_pkt->location_path_len = query - path;
947  } else {
948  coap_pkt->location_path_len = strlen(path);
949  } coap_pkt->location_path = path;
950 
951  if(coap_pkt->location_path_len > 0) {
952  coap_set_option(coap_pkt, COAP_OPTION_LOCATION_PATH);
953  }
954  return coap_pkt->location_path_len;
955 }
956 /*---------------------------------------------------------------------------*/
957 int
958 coap_get_header_location_query(coap_message_t *coap_pkt, const char **query)
959 {
960  if(!coap_is_option(coap_pkt, COAP_OPTION_LOCATION_QUERY)) {
961  return 0;
962  }
963  *query = coap_pkt->location_query;
964  return coap_pkt->location_query_len;
965 }
966 int
967 coap_set_header_location_query(coap_message_t *coap_pkt, const char *query)
968 {
969  while(query[0] == '?') {
970  ++query;
971  }
972 
973  coap_pkt->location_query = query;
974  coap_pkt->location_query_len = strlen(query);
975 
976  coap_set_option(coap_pkt, COAP_OPTION_LOCATION_QUERY);
977  return coap_pkt->location_query_len;
978 }
979 /*---------------------------------------------------------------------------*/
980 int
981 coap_get_header_observe(coap_message_t *coap_pkt, uint32_t *observe)
982 {
983  if(!coap_is_option(coap_pkt, COAP_OPTION_OBSERVE)) {
984  return 0;
985  }
986  *observe = coap_pkt->observe;
987  return 1;
988 }
989 int
990 coap_set_header_observe(coap_message_t *coap_pkt, uint32_t observe)
991 {
992  coap_pkt->observe = observe;
993  coap_set_option(coap_pkt, COAP_OPTION_OBSERVE);
994  return 1;
995 }
996 /*---------------------------------------------------------------------------*/
997 int
998 coap_get_header_block2(coap_message_t *coap_pkt, uint32_t *num, uint8_t *more,
999  uint16_t *size, uint32_t *offset)
1000 {
1001  if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK2)) {
1002  return 0;
1003  }
1004  /* pointers may be NULL to get only specific block parameters */
1005  if(num != NULL) {
1006  *num = coap_pkt->block2_num;
1007  }
1008  if(more != NULL) {
1009  *more = coap_pkt->block2_more;
1010  }
1011  if(size != NULL) {
1012  *size = coap_pkt->block2_size;
1013  }
1014  if(offset != NULL) {
1015  *offset = coap_pkt->block2_offset;
1016  }
1017  return 1;
1018 }
1019 int
1020 coap_set_header_block2(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1021  uint16_t size)
1022 {
1023  if(size < 16) {
1024  return 0;
1025  }
1026  if(size > 2048) {
1027  return 0;
1028  }
1029  if(num > 0x0FFFFF) {
1030  return 0;
1031  }
1032  coap_pkt->block2_num = num;
1033  coap_pkt->block2_more = more ? 1 : 0;
1034  coap_pkt->block2_size = size;
1035 
1036  coap_set_option(coap_pkt, COAP_OPTION_BLOCK2);
1037  return 1;
1038 }
1039 /*---------------------------------------------------------------------------*/
1040 int
1041 coap_get_header_block1(coap_message_t *coap_pkt, uint32_t *num, uint8_t *more,
1042  uint16_t *size, uint32_t *offset)
1043 {
1044  if(!coap_is_option(coap_pkt, COAP_OPTION_BLOCK1)) {
1045  return 0;
1046  }
1047  /* pointers may be NULL to get only specific block parameters */
1048  if(num != NULL) {
1049  *num = coap_pkt->block1_num;
1050  }
1051  if(more != NULL) {
1052  *more = coap_pkt->block1_more;
1053  }
1054  if(size != NULL) {
1055  *size = coap_pkt->block1_size;
1056  }
1057  if(offset != NULL) {
1058  *offset = coap_pkt->block1_offset;
1059  }
1060  return 1;
1061 }
1062 int
1063 coap_set_header_block1(coap_message_t *coap_pkt, uint32_t num, uint8_t more,
1064  uint16_t size)
1065 {
1066  if(size < 16) {
1067  return 0;
1068  }
1069  if(size > 2048) {
1070  return 0;
1071  }
1072  if(num > 0x0FFFFF) {
1073  return 0;
1074  }
1075  coap_pkt->block1_num = num;
1076  coap_pkt->block1_more = more;
1077  coap_pkt->block1_size = size;
1078 
1079  coap_set_option(coap_pkt, COAP_OPTION_BLOCK1);
1080  return 1;
1081 }
1082 /*---------------------------------------------------------------------------*/
1083 int
1084 coap_get_header_size2(coap_message_t *coap_pkt, uint32_t *size)
1085 {
1086  if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE2)) {
1087  return 0;
1088  }
1089  *size = coap_pkt->size2;
1090  return 1;
1091 }
1092 int
1093 coap_set_header_size2(coap_message_t *coap_pkt, uint32_t size)
1094 {
1095  coap_pkt->size2 = size;
1096  coap_set_option(coap_pkt, COAP_OPTION_SIZE2);
1097  return 1;
1098 }
1099 /*---------------------------------------------------------------------------*/
1100 int
1101 coap_get_header_size1(coap_message_t *coap_pkt, uint32_t *size)
1102 {
1103  if(!coap_is_option(coap_pkt, COAP_OPTION_SIZE1)) {
1104  return 0;
1105  }
1106  *size = coap_pkt->size1;
1107  return 1;
1108 }
1109 int
1110 coap_set_header_size1(coap_message_t *coap_pkt, uint32_t size)
1111 {
1112  coap_pkt->size1 = size;
1113  coap_set_option(coap_pkt, COAP_OPTION_SIZE1);
1114  return 1;
1115 }
1116 /*---------------------------------------------------------------------------*/
1117 int
1118 coap_get_payload(coap_message_t *coap_pkt, const uint8_t **payload)
1119 {
1120  if(payload != NULL) {
1121  *payload = coap_pkt->payload;
1122  }
1123  return coap_pkt->payload != NULL ? coap_pkt->payload_len : 0;
1124 }
1125 int
1126 coap_set_payload(coap_message_t *coap_pkt, const void *payload, size_t length)
1127 {
1128  coap_pkt->payload = (uint8_t *)payload;
1129  coap_pkt->payload_len = MIN(COAP_MAX_CHUNK_SIZE, length);
1130 
1131  return coap_pkt->payload_len;
1132 }
1133 /*---------------------------------------------------------------------------*/
1134 /** @} */
Log support for CoAP
static uint8_t accept(uint8_t in)
Definition: mpl.c:1391
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:1565
static void start(void)
Start measurement.
CoAP module for reliable transport
An implementation of the Constrained Application Protocol (RFC 7252).
Default definitions of C compiler quirk work-arounds.
unsigned short random_rand(void)
Generates a new random number using the cc2538 RNG.
Definition: random.c:58