libcoap  4.1.1
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
pdu.c
Go to the documentation of this file.
1 /* pdu.c -- CoAP message structure
2  *
3  * Copyright (C) 2010,2011 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 "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 
27 #ifdef WITH_CONTIKI
28 #include "memb.h"
29 
30 typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
31 
32 MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
33 
34 void
35 coap_pdu_resources_init() {
36  memb_init(&pdu_storage);
37 }
38 #else /* WITH_CONTIKI */
39 #include "mem.h"
40 #endif /* WITH_CONTIKI */
41 
42 void
43 coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
44  assert(pdu);
45 
46  memset(pdu, 0, sizeof(coap_pdu_t) + size);
47  pdu->max_size = size;
48  pdu->hdr = (coap_hdr_t *)((unsigned char *)pdu + sizeof(coap_pdu_t));
50 
51  /* data is NULL unless explicitly set by coap_add_data() */
52  pdu->length = sizeof(coap_hdr_t);
53 }
54 
55 #ifdef WITH_LWIP
56 coap_pdu_t *
57 coap_pdu_from_pbuf(struct pbuf *pbuf)
58 {
59  LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
60  LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
61 
62  void *data = pbuf->payload;
63  coap_pdu_t *result;
64 
65  u8_t header_error = pbuf_header(pbuf, sizeof(coap_pdu_t));
66  LWIP_ASSERT("CoAP PDU header does not fit in existing header space", header_error == 0);
67 
68  result = (coap_pdu_t *)pbuf->payload;
69 
70  memset(result, 0, sizeof(coap_pdu_t));
71 
72  result->max_size = pbuf->tot_len - sizeof(coap_pdu_t);
73  result->length = pbuf->tot_len - sizeof(coap_pdu_t);
74  result->hdr = data;
75  result->pbuf = pbuf;
76 
77  return result;
78 }
79 #endif
80 
81 coap_pdu_t *
82 coap_pdu_init(unsigned char type, unsigned char code,
83  unsigned short id, size_t size) {
84  coap_pdu_t *pdu;
85 #ifdef WITH_LWIP
86  struct pbuf *p;
87 #endif
88 
89  assert(size <= COAP_MAX_PDU_SIZE);
90  /* Size must be large enough to fit the header. */
91  if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
92  return NULL;
93 
94  /* size must be large enough for hdr */
95 #ifdef WITH_POSIX
96  pdu = coap_malloc(sizeof(coap_pdu_t) + size);
97 #endif
98 #ifdef WITH_CONTIKI
99  pdu = (coap_pdu_t *)memb_alloc(&pdu_storage);
100 #endif
101 #ifdef WITH_LWIP
102  p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
103  if (p != NULL) {
104  u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t));
105  /* we could catch that case and allocate larger memory in advance, but then
106  * again, we'd run into greater trouble with incoming packages anyway */
107  LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0);
108  pdu = p->payload;
109  } else {
110  pdu = NULL;
111  }
112 #endif
113  if (pdu) {
114  coap_pdu_clear(pdu, size);
115  pdu->hdr->id = id;
116  pdu->hdr->type = type;
117  pdu->hdr->code = code;
118 #ifdef WITH_LWIP
119  pdu->pbuf = p;
120 #endif
121  }
122  return pdu;
123 }
124 
125 coap_pdu_t *
127  coap_pdu_t *pdu;
128 
129 #ifndef WITH_CONTIKI
130  pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
131 #else /* WITH_CONTIKI */
132  pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
133 #endif /* WITH_CONTIKI */
134 
135 #ifndef NDEBUG
136  if (!pdu)
137  coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
138 #endif
139  return pdu;
140 }
141 
142 void
144 #ifdef WITH_POSIX
145  coap_free( pdu );
146 #endif
147 #ifdef WITH_LWIP
148  if (pdu != NULL) /* accepting double free as the other implementation accept that too */
149  pbuf_free(pdu->pbuf);
150 #endif
151 #ifdef WITH_CONTIKI
152  memb_free(&pdu_storage, pdu);
153 #endif
154 }
155 
156 int
157 coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) {
158  const size_t HEADERLENGTH = len + 4;
159  /* must allow for pdu == NULL as callers may rely on this */
160  if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
161  return 0;
162 
163  pdu->hdr->token_length = len;
164  if (len)
165  memcpy(pdu->hdr->token, data, len);
166  pdu->max_delta = 0;
167  pdu->length = HEADERLENGTH;
168  pdu->data = NULL;
169 
170  return 1;
171 }
172 
174 size_t
175 coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) {
176  size_t optsize;
177  coap_opt_t *opt;
178 
179  assert(pdu);
180  pdu->data = NULL;
181 
182  if (type < pdu->max_delta) {
183  warn("coap_add_option: options are not in correct order\n");
184  return 0;
185  }
186 
187  opt = (unsigned char *)pdu->hdr + pdu->length;
188 
189  /* encode option and check length */
190  optsize = coap_opt_encode(opt, pdu->max_size - pdu->length,
191  type - pdu->max_delta, data, len);
192 
193  if (!optsize) {
194  warn("coap_add_option: cannot add option\n");
195  /* error */
196  return 0;
197  } else {
198  pdu->max_delta = type;
199  pdu->length += optsize;
200  }
201 
202  return optsize;
203 }
204 
206 unsigned char*
207 coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) {
208  size_t optsize;
209  coap_opt_t *opt;
210 
211  assert(pdu);
212  pdu->data = NULL;
213 
214  if (type < pdu->max_delta) {
215  warn("coap_add_option: options are not in correct order\n");
216  return NULL;
217  }
218 
219  opt = (unsigned char *)pdu->hdr + pdu->length;
220 
221  /* encode option and check length */
222  optsize = coap_opt_encode(opt, pdu->max_size - pdu->length,
223  type - pdu->max_delta, NULL, len);
224 
225  if (!optsize) {
226  warn("coap_add_option: cannot add option\n");
227  /* error */
228  return NULL;
229  } else {
230  pdu->max_delta = type;
231  pdu->length += optsize;
232  }
233 
234  return ((unsigned char*)opt) + optsize - len;
235 }
236 
237 int
238 coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data) {
239  assert(pdu);
240  assert(pdu->data == NULL);
241 
242  if (len == 0)
243  return 1;
244 
245  if (pdu->length + len + 1 > pdu->max_size) {
246  warn("coap_add_data: cannot add: data too large for PDU\n");
247  assert(pdu->data == NULL);
248  return 0;
249  }
250 
251  pdu->data = (unsigned char *)pdu->hdr + pdu->length;
252  *pdu->data = COAP_PAYLOAD_START;
253  pdu->data++;
254 
255  memcpy(pdu->data, data, len);
256  pdu->length += len + 1;
257  return 1;
258 }
259 
260 int
261 coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data) {
262  assert(pdu);
263  assert(len);
264  assert(data);
265 
266  if (pdu->data) {
267  *len = (unsigned char *)pdu->hdr + pdu->length - pdu->data;
268  *data = pdu->data;
269  } else { /* no data, clear everything */
270  *len = 0;
271  *data = NULL;
272  }
273 
274  return *data != NULL;
275 }
276 
277 #ifndef SHORT_ERROR_RESPONSE
278 typedef struct {
279  unsigned char code;
280  char *phrase;
281 } error_desc_t;
282 
283 /* if you change anything here, make sure, that the longest string does not
284  * exceed COAP_ERROR_PHRASE_LENGTH. */
286  { COAP_RESPONSE_CODE(65), "2.01 Created" },
287  { COAP_RESPONSE_CODE(66), "2.02 Deleted" },
288  { COAP_RESPONSE_CODE(67), "2.03 Valid" },
289  { COAP_RESPONSE_CODE(68), "2.04 Changed" },
290  { COAP_RESPONSE_CODE(69), "2.05 Content" },
291  { COAP_RESPONSE_CODE(400), "Bad Request" },
292  { COAP_RESPONSE_CODE(401), "Unauthorized" },
293  { COAP_RESPONSE_CODE(402), "Bad Option" },
294  { COAP_RESPONSE_CODE(403), "Forbidden" },
295  { COAP_RESPONSE_CODE(404), "Not Found" },
296  { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
297  { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
298  { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
299  { COAP_RESPONSE_CODE(415), "Unsupported Media Type" },
300  { COAP_RESPONSE_CODE(500), "Internal Server Error" },
301  { COAP_RESPONSE_CODE(501), "Not Implemented" },
302  { COAP_RESPONSE_CODE(502), "Bad Gateway" },
303  { COAP_RESPONSE_CODE(503), "Service Unavailable" },
304  { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
305  { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
306  { 0, NULL } /* end marker */
307 };
308 
309 char *
310 coap_response_phrase(unsigned char code) {
311  int i;
312  for (i = 0; coap_error[i].code; ++i) {
313  if (coap_error[i].code == code)
314  return coap_error[i].phrase;
315  }
316  return NULL;
317 }
318 #endif
319 
325 static size_t
326 next_option_safe(coap_opt_t **optp, size_t *length) {
327  coap_option_t option;
328  size_t optsize;
329 
330  assert(optp); assert(*optp);
331  assert(length);
332 
333  optsize = coap_opt_parse(*optp, *length, &option);
334  if (optsize) {
335  assert(optsize <= *length);
336 
337  *optp += optsize;
338  *length -= optsize;
339  }
340 
341  return optsize;
342 }
343 
344 int
345 coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) {
346  coap_opt_t *opt;
347 
348  assert(data);
349  assert(pdu);
350 
351  if (pdu->max_size < length) {
352  debug("insufficient space to store parsed PDU\n");
353  return 0;
354  }
355 
356  if (length < sizeof(coap_hdr_t)) {
357  debug("discarded invalid PDU\n");
358  }
359 
360  pdu->hdr->version = data[0] >> 6;
361  pdu->hdr->type = (data[0] >> 4) & 0x03;
362  pdu->hdr->token_length = data[0] & 0x0f;
363  pdu->hdr->code = data[1];
364  pdu->data = NULL;
365 
366  /* sanity checks */
367  if (pdu->hdr->code == 0) {
368  if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length) {
369  debug("coap_pdu_parse: empty message is not empty\n");
370  goto discard;
371  }
372  }
373 
374  if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length
375  || pdu->hdr->token_length > 8) {
376  debug("coap_pdu_parse: invalid Token\n");
377  goto discard;
378  }
379 
380  /* Copy message id in network byte order, so we can easily write the
381  * response back to the network. */
382  memcpy(&pdu->hdr->id, data + 2, 2);
383 
384  /* append data (including the Token) to pdu structure */
385  memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
386  pdu->length = length;
387 
388  /* Finally calculate beginning of data block and thereby check integrity
389  * of the PDU structure. */
390 
391  /* skip header + token */
392  length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
393  opt = (unsigned char *)(pdu->hdr + 1) + pdu->hdr->token_length;
394 
395  while (length && *opt != COAP_PAYLOAD_START) {
396 
397  if (!next_option_safe(&opt, (size_t *)&length)) {
398  debug("coap_pdu_parse: drop\n");
399  goto discard;
400  }
401  }
402 
403  /* end of packet or start marker */
404  if (length) {
405  assert(*opt == COAP_PAYLOAD_START);
406  opt++; length--;
407 
408  if (!length) {
409  debug("coap_pdu_parse: message ending in payload start marker\n");
410  goto discard;
411  }
412 
413  debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt,
414  (unsigned char *)pdu->hdr + pdu->length);
415  pdu->data = (unsigned char *)opt;
416  }
417 
418  return 1;
419 
420  discard:
421  return 0;
422 }
unsigned char token[]
Definition: pdu.h:174
#define warn(...)
Definition: debug.h:54
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:92
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:207
unsigned short id
Definition: pdu.h:173
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:326
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:211
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:157
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:345
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:261
#define coap_malloc(size)
Definition: mem.h:15
helpers for handling options in CoAP PDUs
coap_hdr_t * hdr
Definition: pdu.h:209
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:43
unsigned short max_delta
highest option number
Definition: pdu.h:210
#define debug(...)
Definition: debug.h:55
#define COAP_DEFAULT_VERSION
Definition: pdu.h:30
#define COAP_INVALID_TID
Definition: pdu.h:156
unsigned int code
Definition: pdu.h:172
#define coap_free(size)
Definition: mem.h:16
Header structure for CoAP PDUs.
Definition: pdu.h:206
error_desc_t coap_error[]
Definition: pdu.c:285
Representation of CoAP options.
Definition: option.h:30
static coap_tid_t id
Definition: tiny.c:23
size_t max_size
allocated storage for options and data
Definition: pdu.h:207
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:38
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:175
char * phrase
Definition: pdu.c:280
#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:238
void coap_delete_pdu(coap_pdu_t *pdu)
Definition: pdu.c:143
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:82
#define COAP_PAYLOAD_START
Definition: pdu.h:188
unsigned char code
Definition: pdu.c:279
unsigned int token_length
Definition: pdu.h:169
unsigned int version
Definition: pdu.h:171
unsigned int type
Definition: pdu.h:170
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:26
#define coap_log(...)
Definition: debug.h:47
char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition: pdu.c:310
coap_pdu_t * coap_new_pdu()
Creates a new CoAP PDU.
Definition: pdu.c:126
unsigned char * data
payload
Definition: pdu.h:212
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:382