1 /* pdu.c -- CoAP message structure
3 * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
5 * This file is part of the CoAP library libcoap. Please see
6 * README for terms of use.
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
18 #ifdef HAVE_ARPA_INET_H
19 #include <arpa/inet.h>
34 typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
36 MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
39 coap_pdu_resources_init()
41 memb_init(&pdu_storage);
43 #else /* WITH_CONTIKI */
45 #endif /* WITH_CONTIKI */
47 void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
51 memset(pdu, 0, sizeof(coap_pdu_t) + size);
53 pdu->hdr = (coap_hdr_t *) ((unsigned char *) pdu + sizeof(coap_pdu_t));
54 pdu->hdr->version = COAP_DEFAULT_VERSION;
56 /* data is NULL unless explicitly set by coap_add_data() */
57 pdu->length = sizeof(coap_hdr_t);
62 coap_pdu_from_pbuf(struct pbuf *pbuf)
64 LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
65 LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
67 void *data = pbuf->payload;
70 u8_t header_error = pbuf_header(pbuf, sizeof(coap_pdu_t));
71 LWIP_ASSERT("CoAP PDU header does not fit in existing header space", header_error == 0);
73 result = (coap_pdu_t *)pbuf->payload;
75 memset(result, 0, sizeof(coap_pdu_t));
77 result->max_size = pbuf->tot_len - sizeof(coap_pdu_t);
78 result->length = pbuf->tot_len - sizeof(coap_pdu_t);
87 coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
94 assert(size <= COAP_MAX_PDU_SIZE);
95 /* Size must be large enough to fit the header. */
96 if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
99 /* size must be large enough for hdr */
100 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
101 pdu = (coap_pdu_t *) coap_malloc(sizeof(coap_pdu_t) + size);
104 pdu = (coap_pdu_t *)memb_alloc(&pdu_storage);
107 p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
110 u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t));
111 /* we could catch that case and allocate larger memory in advance, but then
112 * again, we'd run into greater trouble with incoming packages anyway */
113 LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0);
123 coap_pdu_clear(pdu, size);
125 pdu->hdr->type = type;
126 pdu->hdr->code = code;
140 pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
141 #else /* WITH_CONTIKI */
142 pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
143 #endif /* WITH_CONTIKI */
147 coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
152 void coap_delete_pdu(coap_pdu_t *pdu)
154 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
158 if (pdu != NULL) /* accepting double free as the other implementation accept that too */
159 pbuf_free(pdu->pbuf);
162 memb_free(&pdu_storage, pdu);
166 int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
168 const size_t HEADERLENGTH = len + 4;
169 /* must allow for pdu == NULL as callers may rely on this */
170 if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
173 pdu->hdr->token_length = len;
175 memcpy(pdu->hdr->token, data, len);
177 pdu->length = HEADERLENGTH;
183 /** @FIXME de-duplicate code with coap_add_option_later */
184 size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
185 const unsigned char *data)
193 if (type < pdu->max_delta)
195 warn("coap_add_option: options are not in correct order\n");
199 opt = (unsigned char *) pdu->hdr + pdu->length;
201 /* encode option and check length */
202 optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
206 warn("coap_add_option: cannot add option\n");
212 pdu->max_delta = type;
213 pdu->length += optsize;
219 /** @FIXME de-duplicate code with coap_add_option */
221 coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
229 if (type < pdu->max_delta)
231 warn("coap_add_option: options are not in correct order\n");
235 opt = (unsigned char *) pdu->hdr + pdu->length;
237 /* encode option and check length */
238 optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, NULL, len);
242 warn("coap_add_option: cannot add option\n");
248 pdu->max_delta = type;
249 pdu->length += optsize;
252 return ((unsigned char*) opt) + optsize - len;
255 int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
258 assert(pdu->data == NULL);
263 if (pdu->length + len + 1 > pdu->max_size)
265 warn("coap_add_data: cannot add: data too large for PDU\n");
266 assert(pdu->data == NULL);
270 pdu->data = (unsigned char *) pdu->hdr + pdu->length;
271 *pdu->data = COAP_PAYLOAD_START;
274 memcpy(pdu->data, data, len);
275 pdu->length += len + 1;
279 int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data)
287 *len = (unsigned char *) pdu->hdr + pdu->length - pdu->data;
291 { /* no data, clear everything */
296 return *data != NULL;
299 #ifndef SHORT_ERROR_RESPONSE
306 /* if you change anything here, make sure, that the longest string does not
307 * exceed COAP_ERROR_PHRASE_LENGTH. */
308 error_desc_t coap_error[] =
310 { COAP_RESPONSE_CODE(65), "2.01 Created" },
311 { COAP_RESPONSE_CODE(66), "2.02 Deleted" },
312 { COAP_RESPONSE_CODE(67), "2.03 Valid" },
313 { COAP_RESPONSE_CODE(68), "2.04 Changed" },
314 { COAP_RESPONSE_CODE(69), "2.05 Content" },
315 { COAP_RESPONSE_CODE(400), "Bad Request" },
316 { COAP_RESPONSE_CODE(401), "Unauthorized" },
317 { COAP_RESPONSE_CODE(402), "Bad Option" },
318 { COAP_RESPONSE_CODE(403), "Forbidden" },
319 { COAP_RESPONSE_CODE(404), "Not Found" },
320 { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
321 { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
322 { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
323 { COAP_RESPONSE_CODE(415), "Unsupported Media Type" },
324 { COAP_RESPONSE_CODE(500), "Internal Server Error" },
325 { COAP_RESPONSE_CODE(501), "Not Implemented" },
326 { COAP_RESPONSE_CODE(502), "Bad Gateway" },
327 { COAP_RESPONSE_CODE(503), "Service Unavailable" },
328 { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
329 { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
330 { 0, NULL } /* end marker */
334 coap_response_phrase(unsigned char code)
337 for (i = 0; coap_error[i].code; ++i)
339 if (coap_error[i].code == code)
340 return coap_error[i].phrase;
347 * Advances *optp to next option if still in PDU. This function
348 * returns the number of bytes opt has been advanced or @c 0
351 static size_t next_option_safe(coap_opt_t **optp, size_t *length, coap_option_t* option)
353 //coap_option_t option;
359 optsize = coap_opt_parse(*optp, *length, option);
362 assert(optsize <= *length);
371 int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
378 if (pdu->max_size < length)
380 debug("insufficient space to store parsed PDU\n");
381 printf("[COAP] insufficient space to store parsed PDU\n");
385 if (length < sizeof(coap_hdr_t))
387 debug("discarded invalid PDU\n");
390 pdu->hdr->version = data[0] >> 6;
391 pdu->hdr->type = (data[0] >> 4) & 0x03;
392 pdu->hdr->token_length = data[0] & 0x0f;
393 pdu->hdr->code = data[1];
395 printf("[COAP] pdu - version : %d\n", pdu->hdr->version);
396 printf("[COAP] pdu - type : %d\n", pdu->hdr->type);
397 printf("[COAP] pdu - token_length : %d\n", pdu->hdr->token_length);
398 printf("[COAP] pdu - code : %d\n", pdu->hdr->code);
403 if (pdu->hdr->code == 0)
405 if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length)
407 debug("coap_pdu_parse: empty message is not empty\n");
412 if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8)
414 debug("coap_pdu_parse: invalid Token\n");
418 /* Copy message id in network byte order, so we can easily write the
419 * response back to the network. */
420 memcpy(&pdu->hdr->id, data + 2, 2);
422 //printf("[COAP] pdu - id : %d\n", pdu->hdr->id);
424 /* append data (including the Token) to pdu structure */
425 memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
426 pdu->length = length;
428 /* Finally calculate beginning of data block and thereby check integrity
429 * of the PDU structure. */
431 /* skip header + token */
432 length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
433 opt = (unsigned char *) (pdu->hdr + 1) + pdu->hdr->token_length;
435 while (length && *opt != COAP_PAYLOAD_START)
437 coap_option_t option;
438 memset(&option, 0, sizeof(coap_option_t));
439 if (!next_option_safe(&opt, (size_t *) &length, &option))
441 debug("coap_pdu_parse: drop\n");
446 /* end of packet or start marker */
449 assert(*opt == COAP_PAYLOAD_START);
455 debug("coap_pdu_parse: message ending in payload start marker\n");
460 "set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length);
461 pdu->data = (unsigned char *) opt;
462 //printf("[COAP] pdu - data : %s\n", pdu->data);