libcoap  4.1.2
pdu.c
Go to the documentation of this file.
1 /* pdu.c -- CoAP message structure
2  *
3  * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_config.h"
10 
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
20 #endif
21 
22 #include "debug.h"
23 #include "pdu.h"
24 #include "option.h"
25 #include "encode.h"
26 #include "mem.h"
27 
28 void
29 coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
30  assert(pdu);
31 
32 #ifdef WITH_LWIP
33  /* the pdu itself is not wiped as opposed to the other implementations,
34  * because we have to rely on the pbuf to be set there. */
35  pdu->hdr = pdu->pbuf->payload;
36 #else
37  pdu->max_delta = 0;
38  pdu->data = NULL;
39 #endif
40  memset(pdu->hdr, 0, size);
41  pdu->max_size = size;
43 
44  /* data is NULL unless explicitly set by coap_add_data() */
45  pdu->length = sizeof(coap_hdr_t);
46 }
47 
48 #ifdef WITH_LWIP
49 coap_pdu_t *
50 coap_pdu_from_pbuf(struct pbuf *pbuf)
51 {
52  if (pbuf == NULL) return NULL;
53 
54  LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
55  LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
56 
57  coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
58  if (!result) {
59  pbuf_free(pbuf);
60  return NULL;
61  }
62 
63  memset(result, 0, sizeof(coap_pdu_t));
64 
65  result->max_size = pbuf->tot_len;
66  result->length = pbuf->tot_len;
67  result->hdr = pbuf->payload;
68  result->pbuf = pbuf;
69 
70  return result;
71 }
72 #endif
73 
74 coap_pdu_t *
75 coap_pdu_init(unsigned char type, unsigned char code,
76  unsigned short id, size_t size) {
77  coap_pdu_t *pdu;
78 #ifdef WITH_LWIP
79  struct pbuf *p;
80 #endif
81 
82  assert(size <= COAP_MAX_PDU_SIZE);
83  /* Size must be large enough to fit the header. */
84  if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
85  return NULL;
86 
87  /* size must be large enough for hdr */
88 #if defined(WITH_POSIX) || defined(WITH_CONTIKI)
89  pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
90  if (!pdu) return NULL;
91  pdu->hdr = coap_malloc_type(COAP_PDU_BUF, size);
92  if (pdu->hdr == NULL) {
94  pdu = NULL;
95  }
96 #endif /* WITH_POSIX or WITH_CONTIKI */
97 #ifdef WITH_LWIP
99  if (!pdu) return NULL;
100  p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
101  if (p == NULL) {
102  coap_free_type(COAP_PDU, pdu);
103  pdu = NULL;
104  }
105 #endif
106  if (pdu) {
107 #ifdef WITH_LWIP
108  pdu->pbuf = p;
109 #endif
110  coap_pdu_clear(pdu, size);
111  pdu->hdr->id = id;
112  pdu->hdr->type = type;
113  pdu->hdr->code = code;
114  }
115  return pdu;
116 }
117 
118 coap_pdu_t *
120  coap_pdu_t *pdu;
121 
122 #ifndef WITH_CONTIKI
123  pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
124 #else /* WITH_CONTIKI */
125  pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
126 #endif /* WITH_CONTIKI */
127 
128 #ifndef NDEBUG
129  if (!pdu)
130  coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
131 #endif
132  return pdu;
133 }
134 
135 void
137 #if defined(WITH_POSIX) || defined(WITH_CONTIKI)
138  if (pdu != NULL) {
139  if (pdu->hdr != NULL) {
141  }
142  coap_free_type(COAP_PDU, pdu);
143  }
144 #endif
145 #ifdef WITH_LWIP
146  if (pdu != NULL) /* accepting double free as the other implementation accept that too */
147  pbuf_free(pdu->pbuf);
148  coap_free_type(COAP_PDU, pdu);
149 #endif
150 }
151 
152 int
153 coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) {
154  const size_t HEADERLENGTH = len + 4;
155  /* must allow for pdu == NULL as callers may rely on this */
156  if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
157  return 0;
158 
159  pdu->hdr->token_length = len;
160  if (len)
161  memcpy(pdu->hdr->token, data, len);
162  pdu->max_delta = 0;
163  pdu->length = HEADERLENGTH;
164  pdu->data = NULL;
165 
166  return 1;
167 }
168 
170 size_t
171 coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) {
172  size_t optsize;
173  coap_opt_t *opt;
174 
175  assert(pdu);
176  pdu->data = NULL;
177 
178  if (type < pdu->max_delta) {
179  warn("coap_add_option: options are not in correct order\n");
180  return 0;
181  }
182 
183  opt = (unsigned char *)pdu->hdr + pdu->length;
184 
185  /* encode option and check length */
186  optsize = coap_opt_encode(opt, pdu->max_size - pdu->length,
187  type - pdu->max_delta, data, len);
188 
189  if (!optsize) {
190  warn("coap_add_option: cannot add option\n");
191  /* error */
192  return 0;
193  } else {
194  pdu->max_delta = type;
195  pdu->length += optsize;
196  }
197 
198  return optsize;
199 }
200 
202 unsigned char*
203 coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) {
204  size_t optsize;
205  coap_opt_t *opt;
206 
207  assert(pdu);
208  pdu->data = NULL;
209 
210  if (type < pdu->max_delta) {
211  warn("coap_add_option: options are not in correct order\n");
212  return NULL;
213  }
214 
215  opt = (unsigned char *)pdu->hdr + pdu->length;
216 
217  /* encode option and check length */
218  optsize = coap_opt_encode(opt, pdu->max_size - pdu->length,
219  type - pdu->max_delta, NULL, len);
220 
221  if (!optsize) {
222  warn("coap_add_option: cannot add option\n");
223  /* error */
224  return NULL;
225  } else {
226  pdu->max_delta = type;
227  pdu->length += optsize;
228  }
229 
230  return ((unsigned char*)opt) + optsize - len;
231 }
232 
233 int
234 coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data) {
235  assert(pdu);
236  assert(pdu->data == NULL);
237 
238  if (len == 0)
239  return 1;
240 
241  if (pdu->length + len + 1 > pdu->max_size) {
242  warn("coap_add_data: cannot add: data too large for PDU\n");
243  assert(pdu->data == NULL);
244  return 0;
245  }
246 
247  pdu->data = (unsigned char *)pdu->hdr + pdu->length;
248  *pdu->data = COAP_PAYLOAD_START;
249  pdu->data++;
250 
251  memcpy(pdu->data, data, len);
252  pdu->length += len + 1;
253  return 1;
254 }
255 
256 int
257 coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data) {
258  assert(pdu);
259  assert(len);
260  assert(data);
261 
262  if (pdu->data) {
263  *len = (unsigned char *)pdu->hdr + pdu->length - pdu->data;
264  *data = pdu->data;
265  } else { /* no data, clear everything */
266  *len = 0;
267  *data = NULL;
268  }
269 
270  return *data != NULL;
271 }
272 
273 #ifndef SHORT_ERROR_RESPONSE
274 typedef struct {
275  unsigned char code;
276  char *phrase;
277 } error_desc_t;
278 
279 /* if you change anything here, make sure, that the longest string does not
280  * exceed COAP_ERROR_PHRASE_LENGTH. */
282  { COAP_RESPONSE_CODE(201), "Created" },
283  { COAP_RESPONSE_CODE(202), "Deleted" },
284  { COAP_RESPONSE_CODE(203), "Valid" },
285  { COAP_RESPONSE_CODE(204), "Changed" },
286  { COAP_RESPONSE_CODE(205), "Content" },
287  { COAP_RESPONSE_CODE(231), "Continue" },
288  { COAP_RESPONSE_CODE(400), "Bad Request" },
289  { COAP_RESPONSE_CODE(401), "Unauthorized" },
290  { COAP_RESPONSE_CODE(402), "Bad Option" },
291  { COAP_RESPONSE_CODE(403), "Forbidden" },
292  { COAP_RESPONSE_CODE(404), "Not Found" },
293  { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
294  { COAP_RESPONSE_CODE(406), "Not Acceptable" },
295  { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
296  { COAP_RESPONSE_CODE(412), "Precondition Failed" },
297  { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
298  { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
299  { COAP_RESPONSE_CODE(500), "Internal Server Error" },
300  { COAP_RESPONSE_CODE(501), "Not Implemented" },
301  { COAP_RESPONSE_CODE(502), "Bad Gateway" },
302  { COAP_RESPONSE_CODE(503), "Service Unavailable" },
303  { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
304  { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
305  { 0, NULL } /* end marker */
306 };
307 
308 char *
309 coap_response_phrase(unsigned char code) {
310  int i;
311  for (i = 0; coap_error[i].code; ++i) {
312  if (coap_error[i].code == code)
313  return coap_error[i].phrase;
314  }
315  return NULL;
316 }
317 #endif
318 
324 static size_t
325 next_option_safe(coap_opt_t **optp, size_t *length) {
326  coap_option_t option;
327  size_t optsize;
328 
329  assert(optp); assert(*optp);
330  assert(length);
331 
332  optsize = coap_opt_parse(*optp, *length, &option);
333  if (optsize) {
334  assert(optsize <= *length);
335 
336  *optp += optsize;
337  *length -= optsize;
338  }
339 
340  return optsize;
341 }
342 
343 int
344 coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) {
345  coap_opt_t *opt;
346 
347  assert(data);
348  assert(pdu);
349 
350  if (pdu->max_size < length) {
351  debug("insufficient space to store parsed PDU\n");
352  return 0;
353  }
354 
355  if (length < sizeof(coap_hdr_t)) {
356  debug("discarded invalid PDU\n");
357  }
358 
359 #ifdef WITH_LWIP
360  /* this verifies that with the classical copy-at-parse-time and lwip's
361  * zerocopy-into-place approaches, both share the same idea of destination
362  * addresses */
363  LWIP_ASSERT("coap_pdu_parse with unexpected addresses", data == (void*)pdu->hdr);
364  LWIP_ASSERT("coap_pdu_parse with unexpected length", length == pdu->length);
365 #else
366 
367  pdu->hdr->version = data[0] >> 6;
368  pdu->hdr->type = (data[0] >> 4) & 0x03;
369  pdu->hdr->token_length = data[0] & 0x0f;
370  pdu->hdr->code = data[1];
371 #endif
372  pdu->data = NULL;
373 
374  /* sanity checks */
375  if (pdu->hdr->code == 0) {
376  if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length) {
377  debug("coap_pdu_parse: empty message is not empty\n");
378  goto discard;
379  }
380  }
381 
382  if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length
383  || pdu->hdr->token_length > 8) {
384  debug("coap_pdu_parse: invalid Token\n");
385  goto discard;
386  }
387 
388 #ifndef WITH_LWIP
389  /* Copy message id in network byte order, so we can easily write the
390  * response back to the network. */
391  memcpy(&pdu->hdr->id, data + 2, 2);
392 
393  /* Append data (including the Token) to pdu structure, if any. */
394  if (length > sizeof(coap_hdr_t)) {
395  memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
396  }
397  pdu->length = length;
398 
399  /* Finally calculate beginning of data block and thereby check integrity
400  * of the PDU structure. */
401 #endif
402 
403  /* skip header + token */
404  length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
405  opt = (unsigned char *)(pdu->hdr + 1) + pdu->hdr->token_length;
406 
407  while (length && *opt != COAP_PAYLOAD_START) {
408  if (!next_option_safe(&opt, (size_t *)&length)) {
409  debug("coap_pdu_parse: drop\n");
410  goto discard;
411  }
412  }
413 
414  /* end of packet or start marker */
415  if (length) {
416  assert(*opt == COAP_PAYLOAD_START);
417  opt++; length--;
418 
419  if (!length) {
420  debug("coap_pdu_parse: message ending in payload start marker\n");
421  goto discard;
422  }
423 
424  debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt,
425  (unsigned char *)pdu->hdr + pdu->length);
426  pdu->data = (unsigned char *)opt;
427  }
428 
429  return 1;
430 
431  discard:
432  return 0;
433 }
unsigned char token[]
Definition: pdu.h:192
#define warn(...)
Definition: debug.h:65
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:96
unsigned char * coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
de-duplicate code with coap_add_option
Definition: pdu.c:203
unsigned short id
Definition: pdu.h:191
static size_t next_option_safe(coap_opt_t **optp, size_t *length)
Advances *optp to next option if still in PDU.
Definition: pdu.c:325
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:234
int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
Adds token of length len to pdu.
Definition: pdu.c:153
int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
Parses data into the CoAP PDU structure given in result.
Definition: pdu.c:344
int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:257
Helpers for handling options in CoAP PDUs.
coap_hdr_t * hdr
Address of the first byte of the CoAP message.
Definition: pdu.h:229
void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
Clears any contents from pdu and resets version field, length and data pointers.
Definition: pdu.c:29
unsigned short max_delta
highest option number
Definition: pdu.h:233
#define debug(...)
Definition: debug.h:66
#define COAP_DEFAULT_VERSION
Definition: pdu.h:30
#define COAP_INVALID_TID
Indicates an invalid transaction id.
Definition: pdu.h:166
unsigned int code
Definition: pdu.h:189
Header structure for CoAP PDUs.
Definition: pdu.h:227
error_desc_t coap_error[]
Definition: pdu.c:281
Representation of CoAP options.
Definition: option.h:29
#define assert(...)
Definition: mem.c:17
size_t max_size
allocated storage for options and data
Definition: pdu.h:228
size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result)
Parses the option pointed to by opt into result.
Definition: option.c:39
size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data)
de-duplicate code with coap_add_option_later
Definition: pdu.c:171
char * phrase
Definition: pdu.c:276
#define COAP_MAX_PDU_SIZE
Definition: pdu.h:27
int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
Adds given data to the pdu that is passed as first parameter.
Definition: pdu.c:234
Definition: debug.h:29
Pre-defined constants that reflect defaults for CoAP.
void coap_delete_pdu(coap_pdu_t *pdu)
Definition: pdu.c:136
coap_pdu_t * coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
Creates a new CoAP PDU of given size (must be large enough to hold the basic CoAP message header (coa...
Definition: pdu.c:75
#define COAP_PAYLOAD_START
Definition: pdu.h:207
unsigned char code
Definition: pdu.c:275
unsigned int token_length
Definition: pdu.h:186
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
unsigned int version
Definition: pdu.h:188
coap_pdu_t * coap_new_pdu(void)
Creates a new CoAP PDU.
Definition: pdu.c:119
unsigned int type
Definition: pdu.h:187
unsigned char coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:25
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
#define coap_log(...)
Definition: debug.h:58
char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition: pdu.c:309
Definition: mem.h:37
unsigned char * data
payload
Definition: pdu.h:235
size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, const unsigned char *val, size_t length)
Encodes option with given delta into opt.
Definition: option.c:384