coap_message.c
Go to the documentation of this file.
1 /**
2  * @file coap_message.c
3  * @brief CoAP message formatting and parsing
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.0
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_message.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 Parse CoAP message
47  * @param[in] message Pointer to the CoAP message
48  * @return Error code
49  **/
50 
52 {
53  error_t error;
54  size_t n;
55  size_t length;
56  const uint8_t *p;
57 
58  //Point to the first byte of the CoAP message
59  p = message->buffer;
60  //Retrieve the length of the message
61  length = message->length;
62 
63  //Parse message header
64  error = coapParseMessageHeader(p, length, &n);
65  //Any error to report?
66  if(error)
67  return error;
68 
69  //Point to the first option of the message
70  p += n;
71  //Number of bytes left to process
72  length -= n;
73 
74  //Parse the list of options
75  error = coapParseOptions(p, length, &n);
76  //Any error to report?
77  if(error)
78  return error;
79 
80  //Point to the payload
81  p += n;
82  //Number of bytes left to process
83  length -= n;
84 
85  //The payload is optional
86  if(length > 0)
87  {
88  //The payload is prefixed by a fixed, one-byte payload marker
89  p++;
90  //Retrieve the length of the payload
91  length--;
92 
93  //The presence of a marker followed by a zero-length payload must be
94  //processed as a message format error
95  if(length == 0)
96  return ERROR_INVALID_MESSAGE;
97  }
98 
99  //Successful processing
100  return NO_ERROR;
101 }
102 
103 
104 /**
105  * @brief Parse CoAP message header
106  * @param[in] p Input stream where to read the CoAP message header
107  * @param[in] length Number of bytes available in the input stream
108  * @param[out] consumed Total number of bytes that have been consumed
109  * @return Error code
110  **/
111 
112 error_t coapParseMessageHeader(const uint8_t *p, size_t length,
113  size_t *consumed)
114 {
115  CoapMessageHeader *header;
116 
117  //Malformed CoAP message?
118  if(length < sizeof(CoapMessageHeader))
119  return ERROR_INVALID_HEADER;
120 
121  //Point to the CoAP message header
122  header = (CoapMessageHeader *) p;
123 
124  //Check version field
125  if(header->version != COAP_VERSION_1)
126  return ERROR_INVALID_VERSION;
127 
128  //The length of the Token field must 0-8 bytes
129  if(header->tokenLen > COAP_MAX_TOKEN_LEN)
130  return ERROR_INVALID_HEADER;
131 
132  //Malformed CoAP message?
133  if(length < (sizeof(CoapMessageHeader) + header->tokenLen))
134  return ERROR_INVALID_HEADER;
135 
136  //Total number of bytes that have been consumed
137  *consumed = sizeof(CoapMessageHeader) + header->tokenLen;
138 
139  //Successful processing
140  return NO_ERROR;
141 }
142 
143 
144 /**
145  * @brief Set message type
146  * @param[in] message Pointer to the CoAP message
147  * @param[in] type Message type (Confirmable or Non-confirmable)
148  * @return Error code
149  **/
150 
152 {
153  CoapMessageHeader *header;
154 
155  //Malformed CoAP message?
156  if(message->length < sizeof(CoapMessageHeader))
157  return ERROR_INVALID_MESSAGE;
158 
159  //Point to the CoAP message header
160  header = (CoapMessageHeader *) message->buffer;
161  //Set message type
162  header->type = type;
163 
164  //Successful processing
165  return NO_ERROR;
166 }
167 
168 
169 /**
170  * @brief Get message type
171  * @param[in] message Pointer to the CoAP message
172  * @param[out] type Message type
173  * @return Error code
174  **/
175 
177 {
178  CoapMessageHeader *header;
179 
180  //Malformed CoAP message?
181  if(message->length < sizeof(CoapMessageHeader))
182  return ERROR_INVALID_MESSAGE;
183 
184  //Point to the CoAP message header
185  header = (CoapMessageHeader *) message->buffer;
186  //Retrieve message type
187  *type = (CoapMessageType) header->type;
188 
189  //Successful processing
190  return NO_ERROR;
191 }
192 
193 
194 /**
195  * @brief Set method or response code
196  * @param[in] message Pointer to the CoAP message
197  * @param[in] code Method or response code
198  * @return Error code
199  **/
200 
202 {
203  CoapMessageHeader *header;
204 
205  //Malformed CoAP message?
206  if(message->length < sizeof(CoapMessageHeader))
207  return ERROR_INVALID_MESSAGE;
208 
209  //Point to the CoAP message header
210  header = (CoapMessageHeader *) message->buffer;
211  //Set method or response code
212  header->code = code;
213 
214  //Successful processing
215  return NO_ERROR;
216 }
217 
218 
219 /**
220  * @brief Get method or response code
221  * @param[in] message Pointer to the CoAP message
222  * @param[out] code Method or response code
223  * @return Error code
224  **/
225 
227 {
228  CoapMessageHeader *header;
229 
230  //Malformed CoAP message?
231  if(message->length < sizeof(CoapMessageHeader))
232  return ERROR_INVALID_MESSAGE;
233 
234  //Point to the CoAP message header
235  header = (CoapMessageHeader *) message->buffer;
236  //Retrieve method or response code
237  *code = (CoapCode) header->code;
238 
239  //Successful processing
240  return NO_ERROR;
241 }
242 
243 
244 /**
245  * @brief Set CoAP message payload
246  * @param[in] message Pointer to the CoAP message
247  * @param[out] payload Pointer to payload data
248  * @param[out] payloadLen Length of the payload, in bytes
249  * @return Error code
250  **/
251 
253  size_t payloadLen)
254 {
255  error_t error;
256  size_t n;
257  size_t length;
258  uint8_t *p;
259 
260  //Point to the first byte of the CoAP message
261  p = message->buffer;
262  //Retrieve the length of the message
263  length = message->length;
264 
265  //Parse message header
266  error = coapParseMessageHeader(p, length, &n);
267  //Any error to report?
268  if(error)
269  return error;
270 
271  //Point to the first option of the message
272  p += n;
273  //Number of bytes left to process
274  length -= n;
275 
276  //Parse the list of options
277  error = coapParseOptions(p, length, &n);
278  //Any error to report?
279  if(error)
280  return error;
281 
282  //Point to the payload
283  p += n;
284  //Number of bytes left to process
285  length -= n;
286 
287  //Trim the existing payload
288  message->length -= length;
289 
290  //The payload is optional
291  if(payloadLen > 0)
292  {
293  //Make sure the output buffer is large enough to hold the payload
294  if((message->length + payloadLen + 1) > COAP_MAX_MSG_SIZE)
295  return ERROR_BUFFER_OVERFLOW;
296 
297  //The payload is prefixed by a fixed, one-byte payload marker
298  p[0] = COAP_PAYLOAD_MARKER;
299 
300  //The payload data extends from after the marker to the end of the
301  //UDP datagram
302  osMemcpy(p + 1, payload, payloadLen);
303 
304  //Terminate the payload with a NULL character
305  p[payloadLen + 1] = '\0';
306 
307  //Adjust the length of the CoAP message
308  message->length += payloadLen + 1;
309  }
310 
311  //Successful processing
312  return NO_ERROR;
313 }
314 
315 
316 /**
317  * @brief Get CoAP message payload
318  * @param[in] message Pointer to the CoAP message
319  * @param[out] payload Pointer to the first byte of the payload
320  * @param[out] payloadLen Length of the payload, in bytes
321  * @return Error code
322  **/
323 
325  size_t *payloadLen)
326 {
327  error_t error;
328  size_t n;
329  size_t length;
330  const uint8_t *p;
331 
332  //Point to the first byte of the CoAP message
333  p = message->buffer;
334  //Retrieve the length of the message
335  length = message->length;
336 
337  //Parse message header
338  error = coapParseMessageHeader(p, length, &n);
339  //Any error to report?
340  if(error)
341  return error;
342 
343  //Point to the first option of the message
344  p += n;
345  //Number of bytes left to process
346  length -= n;
347 
348  //Parse the list of options
349  error = coapParseOptions(p, length, &n);
350  //Any error to report?
351  if(error)
352  return error;
353 
354  //Point to the payload
355  p += n;
356  //Number of bytes left to process
357  length -= n;
358 
359  //The payload is optional
360  if(length > 0)
361  {
362  //The payload is prefixed by a fixed, one-byte payload marker
363  p++;
364  //Retrieve the length of the payload
365  length--;
366  }
367 
368  //Point to the first byte of the payload, if any
369  *payload = p;
370  //Save the length of the payload
371  *payloadLen = length;
372 
373  //Successful processing
374  return NO_ERROR;
375 }
376 
377 
378 /**
379  * @brief Write payload data
380  * @param[in] message Pointer to the CoAP message
381  * @param[in] data Pointer to a buffer containing the data to be written
382  * @param[in] length Number of bytes to written
383  * @return Error code
384  **/
385 
387  size_t length)
388 {
389  error_t error;
390  size_t k;
391  size_t n;
392  uint8_t *p;
393 
394  //Point to the first byte of the CoAP message
395  p = message->buffer;
396  //Retrieve the length of the message
397  n = message->length;
398 
399  //Parse message header
400  error = coapParseMessageHeader(p, n, &k);
401  //Any error to report?
402  if(error)
403  return error;
404 
405  //Point to the first option of the message
406  p += k;
407  //Number of bytes left to process
408  n -= k;
409 
410  //Parse the list of options
411  error = coapParseOptions(p, n, &k);
412  //Any error to report?
413  if(error)
414  return error;
415 
416  //Point to the payload
417  p += k;
418  //Number of bytes left to process
419  n -= k;
420 
421  //Any data to write?
422  if(length > 0)
423  {
424  //The absence of the payload marker denotes a zero-length payload
425  if(n == 0)
426  {
427  //Make sure the output buffer is large enough to hold the payload
428  if((message->length + length + 1) > COAP_MAX_MSG_SIZE)
429  return ERROR_BUFFER_OVERFLOW;
430 
431  //The payload is prefixed by a fixed, one-byte payload marker
432  p[n++] = COAP_PAYLOAD_MARKER;
433 
434  //Adjust the length of the CoAP message
435  message->length++;
436  }
437  else
438  {
439  //Make sure the output buffer is large enough to hold the payload
440  if((message->length + length) > COAP_MAX_MSG_SIZE)
441  return ERROR_BUFFER_OVERFLOW;
442  }
443 
444  //Copy data
445  osMemcpy(p + n, data, length);
446 
447  //Terminate the payload with a NULL character
448  p[n + length] = '\0';
449 
450  //Adjust the length of the CoAP message
451  message->length += length;
452  }
453 
454  //Successful processing
455  return NO_ERROR;
456 }
457 
458 
459 /**
460  * @brief Read payload data
461  * @param[in] message Pointer to the CoAP message
462  * @param[out] data Buffer into which received data will be placed
463  * @param[in] size Maximum number of bytes that can be received
464  * @param[out] length Number of bytes that have been received
465  * @return Error code
466  **/
467 
469  size_t *length)
470 {
471  error_t error;
472  size_t k;
473  size_t n;
474  const uint8_t *p;
475 
476  //Point to the first byte of the CoAP message
477  p = message->buffer;
478  //Retrieve the length of the message
479  n = message->length;
480 
481  //Parse message header
482  error = coapParseMessageHeader(p, n, &k);
483  //Any error to report?
484  if(error)
485  return error;
486 
487  //Point to the first option of the message
488  p += k;
489  //Number of bytes left to process
490  n -= k;
491 
492  //Parse the list of options
493  error = coapParseOptions(p, n, &k);
494  //Any error to report?
495  if(error)
496  return error;
497 
498  //Point to the payload
499  p += k;
500  //Number of bytes left to process
501  n -= k;
502 
503  //The payload is optional
504  if(n > 0)
505  {
506  //The payload is prefixed by a fixed, one-byte payload marker
507  p++;
508  //Retrieve the length of the payload
509  n--;
510  }
511 
512  //Any data to be copied?
513  if(message->pos < n)
514  {
515  //Limit the number of bytes to copy at a time
516  n = MIN(n - message->pos, size);
517 
518  //Copy data
519  osMemcpy(data, p + message->pos, n);
520 
521  //Advance current position
522  message->pos += n;
523  //Total number of data that have been read
524  *length = n;
525 
526  //Successful processing
527  error = NO_ERROR;
528  }
529  else
530  {
531  //No more data available
532  error = ERROR_END_OF_STREAM;
533  }
534 
535  //Return status code
536  return error;
537 }
538 
539 
540 /**
541  * @brief Token comparison
542  * @param[in] header1 Pointer to the first CoAP message header
543  * @param[in] header2 Pointer to the second CoAP message header
544  * @return TRUE if the tokens match, else FALSE
545  **/
546 
548  const CoapMessageHeader *header2)
549 {
550  bool_t res = FALSE;
551 
552  //Check token lengths
553  if(header1->tokenLen == header2->tokenLen)
554  {
555  //Compare tokens
556  if(!osMemcmp(header1->token, header2->token, header1->tokenLen))
557  {
558  //The tokens match
559  res = TRUE;
560  }
561  }
562 
563  //Return comparison result
564  return res;
565 }
566 
567 #endif
uint8_t message[]
Definition: chap.h:154
CoAP client.
uint8_t type
Definition: coap_common.h:176
@ COAP_VERSION_1
CoAP version 1.
Definition: coap_common.h:69
uint8_t code
Definition: coap_common.h:179
CoapMessageHeader
Definition: coap_common.h:182
#define COAP_PAYLOAD_MARKER
Definition: coap_common.h:48
CoapMessageType
CoAP message types.
Definition: coap_common.h:88
#define COAP_MAX_TOKEN_LEN
Definition: coap_common.h:45
CoapCode
CoAP method and response codes.
Definition: coap_common.h:113
bool_t coapCompareToken(const CoapMessageHeader *header1, const CoapMessageHeader *header2)
Token comparison.
Definition: coap_message.c:547
error_t coapReadPayload(CoapMessage *message, void *data, size_t size, size_t *length)
Read payload data.
Definition: coap_message.c:468
error_t coapParseMessageHeader(const uint8_t *p, size_t length, size_t *consumed)
Parse CoAP message header.
Definition: coap_message.c:112
error_t coapGetType(const CoapMessage *message, CoapMessageType *type)
Get message type.
Definition: coap_message.c:176
error_t coapGetCode(const CoapMessage *message, CoapCode *code)
Get method or response code.
Definition: coap_message.c:226
error_t coapWritePayload(CoapMessage *message, const void *data, size_t length)
Write payload data.
Definition: coap_message.c:386
error_t coapSetCode(CoapMessage *message, CoapCode code)
Set method or response code.
Definition: coap_message.c:201
error_t coapSetPayload(CoapMessage *message, const void *payload, size_t payloadLen)
Set CoAP message payload.
Definition: coap_message.c:252
error_t coapSetType(CoapMessage *message, CoapMessageType type)
Set message type.
Definition: coap_message.c:151
error_t coapGetPayload(const CoapMessage *message, const uint8_t **payload, size_t *payloadLen)
Get CoAP message payload.
Definition: coap_message.c:324
error_t coapParseMessage(const CoapMessage *message)
Parse CoAP message.
Definition: coap_message.c:51
CoAP message formatting and parsing.
#define COAP_MAX_MSG_SIZE
Definition: coap_message.h:40
error_t coapParseOptions(const uint8_t *p, size_t length, size_t *consumed)
Parse the list of CoAP options.
Definition: coap_option.c:81
CoAP server.
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ ERROR_END_OF_STREAM
Definition: error.h:210
@ ERROR_INVALID_HEADER
Definition: error.h:87
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
@ ERROR_INVALID_VERSION
Definition: error.h:118
uint8_t data[]
Definition: ethernet.h:222
uint8_t payload[]
Definition: ipv6.h:277
uint16_t payloadLen
Definition: ipv6.h:272
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
const uint8_t res[]
CoAP message.
Definition: coap_message.h:56
uint8_t length
Definition: tcp.h:368