coap_option.c
Go to the documentation of this file.
1 /**
2  * @file coap_option.c
3  * @brief Formatting and parsing of CoAP options
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL COAP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "coap/coap_client.h"
37 #include "coap/coap_server.h"
38 #include "coap/coap_option.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (COAP_CLIENT_SUPPORT == ENABLED || COAP_SERVER_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief List of supported CoAP options
47  **/
48 
50 {
52  {COAP_OPT_URI_HOST, TRUE, TRUE, FALSE, FALSE, "Uri-Host", COAP_OPT_FORMAT_STRING, 1, 255},
54  {COAP_OPT_IF_NONE_MATCH, TRUE, FALSE, FALSE, FALSE, "If-None-Match", COAP_OPT_FORMAT_EMPTY, 0, 0},
56  {COAP_OPT_URI_PORT, TRUE, TRUE, FALSE, FALSE, "Uri-Port", COAP_OPT_FORMAT_UINT, 0, 2},
57  {COAP_OPT_LOCATION_PATH, FALSE, FALSE, FALSE, TRUE, "Location-Path", COAP_OPT_FORMAT_STRING, 0, 255},
58  {COAP_OPT_URI_PATH, TRUE, TRUE, FALSE, TRUE, "Uri-Path", COAP_OPT_FORMAT_STRING, 0, 255},
59  {COAP_OPT_CONTENT_FORMAT, FALSE, FALSE, FALSE, FALSE, "Content-Format", COAP_OPT_FORMAT_UINT, 0, 2},
61  {COAP_OPT_URI_QUERY, TRUE, TRUE, FALSE, TRUE, "Uri-Query", COAP_OPT_FORMAT_STRING, 0, 255},
63  {COAP_OPT_LOCATION_QUERY, FALSE, FALSE, FALSE, TRUE, "Location-Query", COAP_OPT_FORMAT_STRING, 0, 255},
67  {COAP_OPT_PROXY_URI, TRUE, TRUE, FALSE, FALSE, "Proxy-Uri", COAP_OPT_FORMAT_STRING, 1, 1034},
68  {COAP_OPT_PROXY_SCHEME, TRUE, TRUE, FALSE, FALSE, "Proxy-Scheme", COAP_OPT_FORMAT_STRING, 1, 255},
70 };
71 
72 
73 /**
74  * @brief Parse the list of CoAP options
75  * @param[in] p Input stream where to read the CoAP options
76  * @param[in] length Number of bytes available in the input stream
77  * @param[out] consumed Total number of bytes that have been consumed
78  * @return Error code
79  **/
80 
81 error_t coapParseOptions(const uint8_t *p, size_t length, size_t *consumed)
82 {
83  error_t error;
84  size_t n;
85  CoapOption option;
86 
87  //Initialize status code
88  error = NO_ERROR;
89 
90  //Total number of bytes that have been consumed
91  *consumed = 0;
92 
93  //For the first option in a message, a preceding option instance with
94  //Option Number zero is assumed
95  option.number = 0;
96 
97  //Loop through CoAP options
98  while(length > 0)
99  {
100  //Payload marker found?
101  if(*p == COAP_PAYLOAD_MARKER)
102  break;
103 
104  //Parse current option
105  error = coapParseOption(p, length, option.number, &option, &n);
106  //Any error to report?
107  if(error)
108  break;
109 
110  //Total number of bytes that have been consumed
111  *consumed += n;
112 
113  //Jump to the next option
114  p += n;
115  length -= n;
116  }
117 
118  //Return status code
119  return error;
120 }
121 
122 
123 /**
124  * @brief Parse CoAP option
125  * @param[in] p Input stream where to read the CoAP option
126  * @param[in] length Number of bytes available in the input stream
127  * @param[in] prevOptionNum Option number of the previous instance
128  * @param[out] option CoAP option content
129  * @param[out] consumed Total number of bytes that have been consumed
130  * @return Error code
131  **/
132 
133 error_t coapParseOption(const uint8_t *p, size_t length,
134  uint16_t prevOptionNum, CoapOption *option, size_t *consumed)
135 {
136  const CoapOptionHeader *header;
137 
138  //Malformed CoAP option?
139  if(length < sizeof(CoapOptionHeader))
140  return ERROR_BUFFER_UNDERFLOW;
141 
142  //Point to the CoAP option header
143  header = (CoapOptionHeader *) p;
144 
145  //Point to the next field
146  p += sizeof(CoapOptionHeader);
147  length -= sizeof(CoapOptionHeader);
148 
149  //Check the value of the Option Delta field
150  if(header->delta == COAP_OPT_DELTA_RESERVED)
151  {
152  //If the field is set to 15 but the entire byte is not the payload
153  //marker, this must be processed as a message format error
154  return ERROR_INVALID_MESSAGE;
155  }
156  else if(header->delta == COAP_OPT_DELTA_16_BITS)
157  {
158  //Malformed CoAP option?
159  if(length < sizeof(uint16_t))
160  return ERROR_BUFFER_UNDERFLOW;
161 
162  //A 16-bit unsigned integer in network byte order follows the initial
163  //byte and indicates the Option Delta minus 269
165 
166  //Point to the next field
167  p += sizeof(uint16_t);
168  length -= sizeof(uint16_t);
169  }
170  else if(header->delta == COAP_OPT_DELTA_8_BITS)
171  {
172  //Malformed CoAP option?
173  if(length < sizeof(uint8_t))
174  return ERROR_BUFFER_UNDERFLOW;
175 
176  //An 8-bit unsigned integer follows the initial byte and indicates
177  //the Option Delta minus 13
178  option->delta = *p + COAP_OPT_DELTA_MINUS_8_BITS;
179 
180  //Point to the next field
181  p += sizeof(uint8_t);
182  length -= sizeof(uint8_t);
183  }
184  else
185  {
186  //A value between 0 and 12 indicates the Option Delta
187  option->delta = header->delta;
188  }
189 
190  //Check the value of the Option Length field
191  if(header->length == COAP_OPT_LEN_RESERVED)
192  {
193  //If the field is set to this value, it must be processed as a
194  //message format error
195  return ERROR_INVALID_MESSAGE;
196  }
197  else if(header->length == COAP_OPT_LEN_16_BITS)
198  {
199  //Malformed CoAP option?
200  if(length < sizeof(uint16_t))
201  return ERROR_BUFFER_UNDERFLOW;
202 
203  //A 16-bit unsigned integer in network byte order precedes the
204  //Option Value and indicates the Option Length minus 269
206 
207  //Point to the next field
208  p += sizeof(uint16_t);
209  length -= sizeof(uint16_t);
210  }
211  else if(header->length == COAP_OPT_LEN_8_BITS)
212  {
213  //Malformed CoAP option?
214  if(length < sizeof(uint8_t))
215  return ERROR_BUFFER_UNDERFLOW;
216 
217  //An 8-bit unsigned integer precedes the Option Value and indicates
218  //the Option Length minus 13
219  option->length = *p + COAP_OPT_LEN_MINUS_8_BITS;
220 
221  //Point to the next field
222  p += sizeof(uint8_t);
223  length -= sizeof(uint8_t);
224  }
225  else
226  {
227  //A value between 0 and 12 indicates the length of the Option Value,
228  //in bytes
229  option->length = header->length;
230  }
231 
232  //Malformed CoAP option?
233  if(length < option->length)
234  return ERROR_BUFFER_UNDERFLOW;
235 
236  //Save option value
237  option->value = p;
238  //Advance data pointer
239  p += option->length;
240 
241  //the Option Number for each instance is calculated as the sum of its delta
242  //and the Option Number of the preceding instance in the message
243  option->number = option->delta + prevOptionNum;
244 
245  //Total number of bytes that have been consumed
246  *consumed = p - (uint8_t *) header;
247 
248  //Successful processing
249  return NO_ERROR;
250 }
251 
252 
253 /**
254  * @brief Format CoAP option
255  * @param[in] p Buffer where to format the CoAP option (optional parameter)
256  * @param[in] prevOptionNum Option number of the previous instance
257  * @param[in] option CoAP option content
258  * @param[out] written Total number of bytes that have been written
259  * @return Error code
260  **/
261 
262 error_t coapFormatOption(uint8_t *p, uint16_t prevOptionNum,
263  CoapOption *option, size_t *written)
264 {
265  size_t n;
266  CoapOptionHeader *header;
267 
268  //The Option Delta is the difference between the Option Number of this
269  //option and that of the previous option (or zero for the first option)
270  option->delta = option->number - prevOptionNum;
271 
272  //Point to the buffer where to write the CoAP option
273  header = (CoapOptionHeader *) p;
274  //Length of the CoAP option
275  n = sizeof(CoapOptionHeader);
276 
277  //Encode the Option Delta field
278  if(option->delta >= COAP_OPT_DELTA_MINUS_16_BITS)
279  {
280  //The first parameter is optional
281  if(p != NULL)
282  {
283  //Fix the initial byte of the CoAP option
284  header->delta = COAP_OPT_DELTA_16_BITS;
285 
286  //A 16-bit unsigned integer in network byte order follows the
287  //initial byte and indicates the Option Delta minus 269
289  }
290 
291  //Adjust the length of the CoAP option
292  n += sizeof(uint16_t);
293  }
294  else if(option->delta >= COAP_OPT_DELTA_MINUS_8_BITS)
295  {
296  //The first parameter is optional
297  if(p != NULL)
298  {
299  //Fix the initial byte of the CoAP option
300  header->delta = COAP_OPT_DELTA_8_BITS;
301 
302  //An 8-bit unsigned integer follows the initial byte and
303  //indicates the Option Delta minus 13
304  p[n] = (uint8_t) (option->delta - COAP_OPT_DELTA_MINUS_8_BITS);
305  }
306 
307  //Adjust the length of the CoAP option
308  n += sizeof(uint8_t);
309  }
310  else
311  {
312  //The first parameter is optional
313  if(p != NULL)
314  {
315  //The Option Delta is directly encoded in the initial byte
316  header->delta = (uint8_t) option->delta;
317  }
318  }
319 
320  //Encode the Option Length field
321  if(option->length >= COAP_OPT_LEN_MINUS_16_BITS)
322  {
323  //The first parameter is optional
324  if(p != NULL)
325  {
326  //Fix the initial byte of the CoAP option
327  header->length = COAP_OPT_LEN_16_BITS;
328 
329  //A 16-bit unsigned integer in network byte order precedes the
330  //Option Value and indicates the Option Length minus 269
332  }
333 
334  //Adjust the length of the CoAP option
335  n += sizeof(uint16_t);
336  }
337  else if(option->length >= COAP_OPT_LEN_MINUS_8_BITS)
338  {
339  //The first parameter is optional
340  if(p != NULL)
341  {
342  //Fix the initial byte of the CoAP option
343  header->length = COAP_OPT_LEN_8_BITS;
344 
345  //An 8-bit unsigned integer precedes the Option Value and
346  //indicates the Option Length minus 13
347  p[n] = (uint8_t) (option->length - COAP_OPT_LEN_MINUS_8_BITS);
348  }
349 
350  //Adjust the length of the CoAP option
351  n += sizeof(uint8_t);
352  }
353  else
354  {
355  //The first parameter is optional
356  if(p != NULL)
357  {
358  //The Option Length is directly encoded in the initial byte
359  header->length = (uint8_t) option->length;
360  }
361  }
362 
363  //The first parameter is optional
364  if(p != NULL)
365  {
366  //The Option Value is a sequence of exactly Option Length bytes
367  osMemmove(p + n, option->value, option->length);
368  }
369 
370  //Total number of bytes that have been written
371  *written = n + option->length;
372 
373  //Successful processing
374  return NO_ERROR;
375 }
376 
377 
378 /**
379  * @brief Add an option to the specified CoAP message
380  * @param[in] message Pointer to the CoAP message
381  * @param[in] optionNum Option number
382  * @param[in] optionIndex Occurrence index (for repeatable options only)
383  * @param[in] optionValue Pointer to the first byte of the option value
384  * @param[in] optionLen Length of the option, in bytes
385  * @return Error code
386  **/
387 
389  uint_t optionIndex, const uint8_t *optionValue, size_t optionLen)
390 {
391  error_t error;
392  bool_t replace;
393  size_t n;
394  size_t m;
395  size_t length;
396  uint_t index;
397  uint16_t prevOptionNum;
398  uint8_t *p;
399  CoapOption option;
400 
401  //Initialize variables
402  replace = FALSE;
403  index = 0;
404 
405  //Point to the first byte of the CoAP message
406  p = message->buffer;
407  //Retrieve the length of the message
408  length = message->length;
409 
410  //Parse message header
411  error = coapParseMessageHeader(p, length, &n);
412  //Any error to report?
413  if(error)
414  return error;
415 
416  //Point to the first option of the message
417  p += n;
418  //Number of bytes left to process
419  length -= n;
420 
421  //For the first option in a message, a preceding option instance with
422  //Option Number zero is assumed
423  prevOptionNum = 0;
424 
425  //Loop through CoAP options
426  while(length > 0)
427  {
428  //Payload marker found?
429  if(*p == COAP_PAYLOAD_MARKER)
430  break;
431 
432  //Parse current option
433  error = coapParseOption(p, length, prevOptionNum, &option, &n);
434  //Any error to report?
435  if(error)
436  return error;
437 
438  //Options are inserted in ascending order
439  if(option.number > optionNum)
440  break;
441 
442  //Matching option number?
443  if(option.number == optionNum)
444  {
445  //Matching occurrence found?
446  if(index++ == optionIndex)
447  {
448  //The current option will be replaced
449  replace = TRUE;
450  break;
451  }
452  }
453 
454  //Keep track of the current option number
455  prevOptionNum = option.number;
456 
457  //Jump to the next option
458  p += n;
459  length -= n;
460  }
461 
462  //Check whether the current option should be replaced
463  if(replace)
464  {
465  //Remove the current occurrence of the option
466  osMemmove(p, p + n, length - n);
467  //Number of bytes left to process
468  length -= n;
469  //Adjust the length of the CoAP message
470  message->length -= n;
471  }
472 
473  //Each option instance in a message specifies the Option Number of the
474  //defined CoAP option, the length of the Option Value, and the Option
475  //Value itself
476  option.number = optionNum;
477  option.length = optionLen;
478  option.value = optionValue;
479 
480  //The first pass calculates the required length
481  error = coapFormatOption(NULL, prevOptionNum, &option, &n);
482  //Any error to report?
483  if(error)
484  return error;
485 
486  //Make sure the output buffer is large enough to hold the new option
487  if((message->length + n) > COAP_MAX_MSG_SIZE)
488  return ERROR_BUFFER_OVERFLOW;
489 
490  //Make room for the new option
491  osMemmove(p + n, p, length);
492 
493  //The second pass formats the CoAP option
494  error = coapFormatOption(p, prevOptionNum, &option, &n);
495  //Any error to report?
496  if(error)
497  return error;
498 
499  //Advance data pointer
500  p += n;
501  //Adjust the length of the CoAP message
502  message->length += n;
503 
504  //Check whether another CoAP option is following
505  if(length > 0 && *p != COAP_PAYLOAD_MARKER && !replace)
506  {
507  //Parse the following option
508  error = coapParseOption(p, length, prevOptionNum, &option, &n);
509  //Any error to report?
510  if(error)
511  return error;
512 
513  //Fix the Option Delta field
514  error = coapFormatOption(p, optionNum, &option, &m);
515  //Any error to report?
516  if(error)
517  return error;
518 
519  //Test if the length of the option has changed
520  if(m < n)
521  {
522  //Move the rest of the CoAP message
523  osMemmove(p + m, p + n, length - n);
524  //Fix the length of the message
525  message->length -= n - m;
526  }
527  }
528 
529  //Return status code
530  return NO_ERROR;
531 }
532 
533 
534 /**
535  * @brief Add a uint option to the specified CoAP message
536  * @param[in] message Pointer to the CoAP message
537  * @param[in] optionNum Option number
538  * @param[in] optionIndex Occurrence index (for repeatable options only)
539  * @param[in] optionValue Option value (unsigned integer)
540  * @return Error code
541  **/
542 
544  uint_t optionIndex, uint32_t optionValue)
545 {
546  size_t i;
547  uint8_t buffer[4];
548 
549  //A sender should represent the integer with as few bytes as possible
550  for(i = 4; optionValue != 0; i--)
551  {
552  buffer[i - 1] = optionValue & 0xFF;
553  optionValue >>= 8;
554  }
555 
556  //Add the specified option to the CoAP message
557  return coapSetOption(message, optionNum, optionIndex, buffer + i, 4 - i);
558 }
559 
560 
561 /**
562  * @brief Get the value of the specified option
563  * @param[in] message Pointer to the CoAP message
564  * @param[in] optionNum Option number
565  * @param[in] optionIndex Occurrence index (for repeatable options only)
566  * @param[out] optionValue Pointer to the first byte of the option value
567  * @param[out] optionLen Length of the option, in bytes
568  * @return Error code
569  **/
570 
571 error_t coapGetOption(const CoapMessage *message, uint16_t optionNum,
572  uint_t optionIndex, const uint8_t **optionValue, size_t *optionLen)
573 {
574  error_t error;
575  size_t n;
576  size_t length;
577  uint_t index;
578  const uint8_t *p;
579  CoapOption option;
580 
581  //Initialize index
582  index = 0;
583 
584  //Point to the first byte of the CoAP message
585  p = message->buffer;
586  //Retrieve the length of the message
587  length = message->length;
588 
589  //Parse message header
590  error = coapParseMessageHeader(p, length, &n);
591  //Any error to report?
592  if(error)
593  return error;
594 
595  //Point to the first option of the message
596  p += n;
597  //Number of bytes left to process
598  length -= n;
599 
600  //For the first option in a message, a preceding option instance with
601  //Option Number zero is assumed
602  option.number = 0;
603 
604  //Loop through CoAP options
605  while(length > 0)
606  {
607  //Payload marker found?
608  if(*p == COAP_PAYLOAD_MARKER)
609  break;
610 
611  //Parse current option
612  error = coapParseOption(p, length, option.number, &option, &n);
613  //Any error to report?
614  if(error)
615  return error;
616 
617  //Matching option number?
618  if(option.number == optionNum)
619  {
620  //Matching occurrence found?
621  if(index++ == optionIndex)
622  {
623  //Return option value
624  *optionValue = option.value;
625  *optionLen = option.length;
626 
627  //We are done
628  return NO_ERROR;
629  }
630  }
631 
632  //Jump to the next option
633  p += n;
634  length -= n;
635  }
636 
637  //The specified option number was not found
638  return ERROR_NOT_FOUND;
639 }
640 
641 
642 /**
643  * @brief Get the value of the specified uint option
644  * @param[in] message Pointer to the CoAP message
645  * @param[in] optionNum Option number to search for
646  * @param[in] optionIndex Occurrence index (for repeatable options only)
647  * @param[out] optionValue Option value (unsigned integer)
648  * @return Error code
649  **/
650 
651 error_t coapGetUintOption(const CoapMessage *message, uint16_t optionNum,
652  uint_t optionIndex, uint32_t *optionValue)
653 {
654  error_t error;
655  size_t i;
656  size_t n;
657  const uint8_t *p;
658 
659  //Search the CoAP message for the specified option number
660  error = coapGetOption(message, optionNum, optionIndex, &p, &n);
661  //Any error to report ?
662  if(error)
663  return error;
664 
665  //Initialize integer value
666  *optionValue = 0;
667 
668  //Convert the integer from network byte order
669  for(i = 0; i < n; i++)
670  {
671  *optionValue <<= 8;
672  *optionValue += p[i];
673  }
674 
675  //Successful processing
676  return NO_ERROR;
677 }
678 
679 
680 /**
681  * @brief Remove an option from the specified CoAP message
682  * @param[in] message Pointer to the CoAP message
683  * @param[in] optionNum Option number
684  * @param[in] optionIndex Occurrence index (for repeatable options only)
685  * @return Error code
686  **/
687 
689  uint_t optionIndex)
690 {
691  error_t error;
692  bool_t found;
693  size_t n;
694  size_t m;
695  size_t length;
696  uint_t index;
697  uint16_t prevOptionNum;
698  uint8_t *p;
699  CoapOption option;
700 
701  //Initialize variables
702  found = FALSE;
703  index = 0;
704 
705  //Point to the first byte of the CoAP message
706  p = message->buffer;
707  //Retrieve the length of the message
708  length = message->length;
709 
710  //Parse message header
711  error = coapParseMessageHeader(p, length, &n);
712  //Any error to report?
713  if(error)
714  return error;
715 
716  //Point to the first option of the message
717  p += n;
718  //Number of bytes left to process
719  length -= n;
720 
721  //For the first option in a message, a preceding option instance with
722  //Option Number zero is assumed
723  prevOptionNum = 0;
724 
725  //Loop through CoAP options
726  while(length > 0)
727  {
728  //Payload marker found?
729  if(*p == COAP_PAYLOAD_MARKER)
730  break;
731 
732  //Parse current option
733  error = coapParseOption(p, length, prevOptionNum, &option, &n);
734  //Any error to report?
735  if(error)
736  return error;
737 
738  //Options are inserted in ascending order
739  if(option.number > optionNum)
740  break;
741 
742  //Matching option number?
743  if(option.number == optionNum)
744  {
745  //Matching occurrence found?
746  if(index++ == optionIndex)
747  {
748  //The current option will be removed
749  found = TRUE;
750  break;
751  }
752  }
753 
754  //Keep track of the current option number
755  prevOptionNum = option.number;
756 
757  //Jump to the next option
758  p += n;
759  length -= n;
760  }
761 
762  //Check whether the option has been found
763  if(found)
764  {
765  //Remove the current occurrence of the option
766  osMemmove(p, p + n, length - n);
767  //Number of bytes left to process
768  length -= n;
769  //Adjust the length of the CoAP message
770  message->length -= n;
771 
772  //Check whether another CoAP option is following
773  if(length > 0 && *p != COAP_PAYLOAD_MARKER)
774  {
775  //Parse the following option
776  error = coapParseOption(p, length, optionNum, &option, &n);
777  //Any error to report?
778  if(error)
779  return error;
780 
781  //The first pass calculates the required length
782  error = coapFormatOption(NULL, prevOptionNum, &option, &m);
783  //Any error to report?
784  if(error)
785  return error;
786 
787  //Test if the length of the option has changed
788  if(m > n)
789  {
790  //Move the rest of the CoAP message
791  osMemmove(p + m - option.length, p + n - option.length,
792  length + option.length - n);
793 
794  //Fix the value of the option
795  option.value += m - n;
796  //Fix the length of the message
797  message->length += m - n;
798  }
799 
800  //The second pass fixes the Option Delta field
801  error = coapFormatOption(p, prevOptionNum, &option, &m);
802  //Any error to report?
803  if(error)
804  return error;
805  }
806  }
807 
808  //Return status code
809  return NO_ERROR;
810 }
811 
812 
813 /**
814  * @brief Encode a path or query component into multiple repeatable options
815  * @param[in] message Pointer to the CoAP message
816  * @param[in] optionNum Option number
817  * @param[in] optionValue Path or a query component to be encoded
818  * @param[in] separator Delimiting character
819  * @return Error code
820  **/
821 
823  const char_t *optionValue, char_t separator)
824 {
825  error_t error;
826  size_t i;
827  size_t j;
828  uint_t index;
829 
830  //Initialize status code
831  error = NO_ERROR;
832 
833  //Initialize variables
834  i = 0;
835  j = 0;
836  index = 0;
837 
838  //Split the path or query component into multiple repeatable options
839  do
840  {
841  //Delimiting character found?
842  if(optionValue[i] == separator || optionValue[i] == '\0')
843  {
844  //Discard empty segments
845  if((i - j) > 0)
846  {
847  //Each option specifies one segment of the component
848  error = coapSetOption(message, optionNum, index++,
849  (uint8_t *) optionValue + j, i - j);
850  //Any error to report?
851  if(error)
852  break;
853  }
854 
855  //Move to the next segment
856  j = i + 1;
857  }
858 
859  //Loop until the NULL character is reached
860  } while(optionValue[i++] != '\0');
861 
862  //Return status code
863  return error;
864 }
865 
866 
867 /**
868  * @brief Decode a path or query component from multiple repeatable options
869  * @param[in] message Pointer to the CoAP message
870  * @param[in] optionNum Option number
871  * @param[out] optionValue Buffer where to copy the path or query component
872  * @param[in] maxLen Maximum number of characters the buffer can hold
873  * @param[in] separator Delimiting character
874  * @return Error code
875  **/
876 
878  uint16_t optionNum, char_t *optionValue, size_t maxLen, char_t separator)
879 {
880  error_t error;
881  size_t i;
882  size_t n;
883  uint_t index;
884  const uint8_t *p;
885 
886  //Initialize status code
887  error = NO_ERROR;
888 
889  //Initialize variables
890  i = 0;
891  index = 0;
892 
893  //Build path or query component
894  while(!error)
895  {
896  //Each option specifies one segment of the component
897  error = coapGetOption(message, optionNum, index++, &p, &n);
898 
899  //Check status code
900  if(!error)
901  {
902  //Check separator
903  if(separator != '&' || i != 0)
904  {
905  //Make sure the output buffer is large enough
906  if(i < maxLen)
907  {
908  //Append a delimiting character
909  optionValue[i++] = separator;
910  }
911  }
912 
913  //Make sure the output buffer is large enough
914  if((i + n) <= maxLen)
915  {
916  //Copy option's value
917  osMemcpy(optionValue + i, p, n);
918  //Update the length of the absolute path
919  i += n;
920  }
921  else
922  {
923  //Report an error
924  error = ERROR_BUFFER_OVERFLOW;
925  }
926  }
927  }
928 
929  //Check status code
930  if(error == ERROR_NOT_FOUND)
931  {
932  //Catch exception
933  error = NO_ERROR;
934  }
935 
936  //Properly terminate the string with a NULL character
937  optionValue[i] = '\0';
938 
939  //Return status code
940  return error;
941 }
942 
943 
944 /**
945  * @brief Retrieve parameters for a given option number
946  * @param[in] optionNum Option number
947  * @return Option parameters
948  **/
949 
951 {
952  uint_t i;
953  const CoapOptionParameters *optionParams;
954 
955  //Initialize variable
956  optionParams = NULL;
957 
958  //Loop through the list of supported options
959  for(i = 0; i < arraysize(coapOptionList); i++)
960  {
961  //Check option number against the expected value
962  if(coapOptionList[i].number == optionNum)
963  {
964  optionParams = &coapOptionList[i];
965  break;
966  }
967  }
968 
969  //Return option parameters
970  return optionParams;
971 }
972 
973 #endif
size_t length
Definition: coap_option.h:220
error_t coapSetUintOption(CoapMessage *message, uint16_t optionNum, uint_t optionIndex, uint32_t optionValue)
Add a uint option to the specified CoAP message.
Definition: coap_option.c:543
#define COAP_MAX_MSG_SIZE
Definition: coap_message.h:40
error_t coapGetUintOption(const CoapMessage *message, uint16_t optionNum, uint_t optionIndex, uint32_t *optionValue)
Get the value of the specified uint option.
Definition: coap_option.c:651
int bool_t
Definition: compiler_port.h:53
@ ERROR_NOT_FOUND
Definition: error.h:147
#define COAP_OPT_DELTA_RESERVED
Definition: coap_option.h:42
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
@ COAP_OPT_ETAG
Definition: coap_option.h:94
#define COAP_OPT_LEN_MINUS_16_BITS
Definition: coap_option.h:51
error_t coapParseOptions(const uint8_t *p, size_t length, size_t *consumed)
Parse the list of CoAP options.
Definition: coap_option.c:81
#define COAP_OPT_DELTA_8_BITS
Definition: coap_option.h:40
@ COAP_OPT_LOCATION_PATH
Definition: coap_option.h:98
uint8_t p
Definition: ndp.h:300
#define COAP_OPT_DELTA_16_BITS
Definition: coap_option.h:41
#define COAP_OPT_LEN_16_BITS
Definition: coap_option.h:48
uint8_t message[]
Definition: chap.h:154
error_t coapDeleteOption(CoapMessage *message, uint16_t optionNum, uint_t optionIndex)
Remove an option from the specified CoAP message.
Definition: coap_option.c:688
#define TRUE
Definition: os_port.h:50
@ COAP_OPT_FORMAT_UINT
Non-negative integer.
Definition: coap_option.h:125
error_t coapJoinRepeatableOption(const CoapMessage *message, uint16_t optionNum, char_t *optionValue, size_t maxLen, char_t separator)
Decode a path or query component from multiple repeatable options.
Definition: coap_option.c:877
#define COAP_PAYLOAD_MARKER
Definition: coap_common.h:48
uint16_t number
Definition: coap_option.h:219
#define COAP_OPT_LEN_MINUS_8_BITS
Definition: coap_option.h:50
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ COAP_OPT_CONTENT_FORMAT
Definition: coap_option.h:100
const CoapOptionParameters coapOptionList[]
List of supported CoAP options.
Definition: coap_option.c:49
@ COAP_OPT_URI_HOST
Definition: coap_option.h:93
#define COAP_OPT_DELTA_MINUS_16_BITS
Definition: coap_option.h:44
@ COAP_OPT_FORMAT_STRING
UTF-8 string.
Definition: coap_option.h:126
#define FALSE
Definition: os_port.h:46
@ COAP_OPT_URI_QUERY
Definition: coap_option.h:102
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define COAP_OPT_LEN_RESERVED
Definition: coap_option.h:49
@ COAP_OPT_ACCEPT
Definition: coap_option.h:103
error_t
Error codes.
Definition: error.h:43
#define COAP_OPT_DELTA_MINUS_8_BITS
Definition: coap_option.h:43
error_t coapSetOption(CoapMessage *message, uint16_t optionNum, uint_t optionIndex, const uint8_t *optionValue, size_t optionLen)
Add an option to the specified CoAP message.
Definition: coap_option.c:388
const CoapOptionParameters * coapGetOptionParameters(uint16_t optionNum)
Retrieve parameters for a given option number.
Definition: coap_option.c:950
@ COAP_OPT_FORMAT_EMPTY
Zero-length sequence of bytes.
Definition: coap_option.h:123
CoapOptionHeader
Definition: coap_common.h:198
#define STORE16BE(a, p)
Definition: cpu_endian.h:262
@ COAP_OPT_PROXY_URI
Definition: coap_option.h:108
CoAP message.
Definition: coap_message.h:56
CoAP client.
@ COAP_OPT_BLOCK1
Definition: coap_option.h:106
CoAP option parameters.
Definition: coap_option.h:230
@ COAP_OPT_OBSERVE
Definition: coap_option.h:96
@ COAP_OPT_PROXY_SCHEME
Definition: coap_option.h:109
uint8_t length
Definition: tcp.h:368
@ COAP_OPT_URI_PATH
Definition: coap_option.h:99
error_t coapSplitRepeatableOption(CoapMessage *message, uint16_t optionNum, const char_t *optionValue, char_t separator)
Encode a path or query component into multiple repeatable options.
Definition: coap_option.c:822
#define COAP_OPT_LEN_8_BITS
Definition: coap_option.h:47
@ COAP_OPT_SIZE1
Definition: coap_option.h:110
CoAP server.
char char_t
Definition: compiler_port.h:48
@ COAP_OPT_MAX_AGE
Definition: coap_option.h:101
@ COAP_OPT_IF_NONE_MATCH
Definition: coap_option.h:95
uint8_t m
Definition: ndp.h:304
uint8_t n
@ COAP_OPT_URI_PORT
Definition: coap_option.h:97
@ COAP_OPT_LOCATION_QUERY
Definition: coap_option.h:104
const uint8_t * value
Definition: coap_option.h:221
@ ERROR_BUFFER_UNDERFLOW
Definition: error.h:143
@ COAP_OPT_BLOCK2
Definition: coap_option.h:105
error_t coapGetOption(const CoapMessage *message, uint16_t optionNum, uint_t optionIndex, const uint8_t **optionValue, size_t *optionLen)
Get the value of the specified option.
Definition: coap_option.c:571
@ COAP_OPT_FORMAT_OPAQUE
Opaque sequence of bytes.
Definition: coap_option.h:124
uint16_t delta
Definition: coap_option.h:218
CoAP option.
Definition: coap_option.h:217
error_t coapParseOption(const uint8_t *p, size_t length, uint16_t prevOptionNum, CoapOption *option, size_t *consumed)
Parse CoAP option.
Definition: coap_option.c:133
@ COAP_OPT_SIZE2
Definition: coap_option.h:107
@ COAP_OPT_IF_MATCH
Definition: coap_option.h:92
unsigned int uint_t
Definition: compiler_port.h:50
#define LOAD16BE(p)
Definition: cpu_endian.h:186
TCP/IP stack core.
error_t coapParseMessageHeader(const uint8_t *p, size_t length, size_t *consumed)
Parse CoAP message header.
Definition: coap_message.c:112
error_t coapFormatOption(uint8_t *p, uint16_t prevOptionNum, CoapOption *option, size_t *written)
Format CoAP option.
Definition: coap_option.c:262
Formatting and parsing of CoAP options.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define arraysize(a)
Definition: os_port.h:71