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