diff --git a/ChangeLog b/ChangeLog index 2743f75e..56eed38b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2012-03-19 Olaf Bergmann + + * pdu.c (coap_add_option): allow more than 15 options. + +2012-03-15 Olaf Bergmann + + * examples/client.c (cmdline_uri): split path and query here to + make it easier to include these options in subsequent requests for + block transfer. + +2012-03-14 Olaf Bergmann + + * examples/etsi_iot_01.c: Support for POST, PUT, DELETE on /test + +2012-03-13 Olaf Bergmann + + * encode.c (coap_encode_var_bytes): more efficient coding for 0 + 2012-03-11 Olaf Bergmann * examples/etsi_iot_01.c: Test cases for 1st ETSI CoAP Plugtest, diff --git a/net.c b/net.c index 5aad409d..ce6f7fc8 100644 --- a/net.c +++ b/net.c @@ -373,6 +373,25 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, *id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]); } +coap_tid_t +coap_send_ack(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request) { + coap_pdu_t *response; + coap_tid_t result = COAP_INVALID_TID; + + if (request && request->hdr->type == COAP_MESSAGE_CON) { + response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, + sizeof(coap_pdu_t)); + if (response) { + result = coap_send(context, dst, response); + if (result == COAP_INVALID_TID) + coap_delete_pdu(response); + } + } + return result; +} + #ifndef WITH_CONTIKI /* releases space allocated by PDU if free_pdu is set */ coap_tid_t @@ -653,12 +672,21 @@ coap_read( coap_context_t *ctx ) { /* finally calculate beginning of data block */ { coap_opt_t *opt = options_start(node->pdu); - unsigned char cnt; + unsigned char cnt = node->pdu->hdr->optcnt; /* Note that we cannot use the official options iterator here as * it eats up the fence posts. */ - for (cnt = node->pdu->hdr->optcnt; cnt; --cnt) + while (cnt) { + if (node->pdu->hdr->optcnt == COAP_OPT_LONG) { + if (*opt == COAP_OPT_END) { + ++opt; + break; + } + } else { + --cnt; + } opt = options_next(opt); + } node->pdu->data = (unsigned char *)opt; } @@ -780,7 +808,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_add_option(response, opt_iter.type, COAP_OPT_LENGTH(opt_iter.option), COAP_OPT_VALUE(opt_iter.option)); - + #if COAP_ERROR_PHRASE_LENGTH > 0 if (phrase) coap_add_data(response, strlen(phrase), (unsigned char *)phrase); diff --git a/net.h b/net.h index bdbc93e9..d5cb3f8e 100644 --- a/net.h +++ b/net.h @@ -80,6 +80,12 @@ typedef void (*coap_response_handler_t)(struct coap_context_t *, coap_pdu_t *received, const coap_tid_t id); +#define COAP_MID_CACHE_SIZE 3 +typedef struct { + unsigned char flags[COAP_MID_CACHE_SIZE]; + coap_key_t item[COAP_MID_CACHE_SIZE]; +} coap_mid_cache_t; + /** The CoAP stack's global state is stored in a coap_context_t object */ typedef struct coap_context_t { coap_opt_filter_t known_options; @@ -272,15 +278,9 @@ coap_send_message_type(coap_context_t *context, * @return The transaction id if ACK was sent or @c COAP_INVALID_TID * on error. */ -static inline coap_tid_t -coap_send_ack(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *request) { - if (request && request->hdr->type == COAP_MESSAGE_CON) - return coap_send_message_type(context, dst, request, COAP_MESSAGE_ACK); - else - return COAP_INVALID_TID; -} +coap_tid_t coap_send_ack(coap_context_t *context, + const coap_address_t *dst, + coap_pdu_t *request); /** * Sends an RST message with code @c 0 for the specified @p request to diff --git a/option.c b/option.c index 86668a9e..e2e306aa 100644 --- a/option.c +++ b/option.c @@ -42,12 +42,18 @@ coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, #define IS_EMPTY_NOOP(Type,Option) \ ((Type) % COAP_OPTION_NOOP == 0 && COAP_OPT_LENGTH(Option) == 0) +#define opt_finished(oi) ((oi)->optcnt == COAP_OPT_LONG \ + ? ((oi)->option && *((oi)->option) == COAP_OPT_END) \ + : (oi->n > (oi)->optcnt)) + coap_opt_t * coap_option_next(coap_opt_iterator_t *oi) { - if (!oi || oi->n >= oi->optcnt) + assert(oi); + if (opt_finished(oi)) return NULL; + /* proceed to next option */ if (oi->n++) { oi->option = options_next(oi->option); oi->type += COAP_OPT_DELTA(oi->option); @@ -55,22 +61,19 @@ coap_option_next(coap_opt_iterator_t *oi) { /* Skip subsequent options if it is an empty no-op (used for * fence-posting) or the filter bit is not set. */ - while (oi->n <= oi->optcnt && + while (!opt_finished(oi) && (IS_EMPTY_NOOP(oi->type, oi->option) || coap_option_getb(oi->filter, oi->type) == 0)) { oi->n++; oi->option = options_next(oi->option); - if (oi->n > oi->optcnt) + if (opt_finished(oi)) break; oi->type += COAP_OPT_DELTA(oi->option); } - if (oi->n > oi->optcnt) - oi->option = NULL; - - return oi->option; + return opt_finished(oi) ? NULL : oi->option; } coap_opt_t * diff --git a/pdu.c b/pdu.c index 82854ad7..6d671570 100644 --- a/pdu.c +++ b/pdu.c @@ -106,57 +106,67 @@ coap_delete_pdu(coap_pdu_t *pdu) { } int -coap_add_option(coap_pdu_t *pdu, unsigned char type, unsigned int len, const unsigned char *data) { - unsigned char cnt, optcnt; +coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) { + size_t optsize, cnt, optcnt, opt_code = 0; + unsigned char fence; coap_opt_t *opt; - unsigned char opt_code = 0; - + size_t old_optcnt; /* for restoring old values */ + coap_opt_t *old_opt; + if (!pdu) return -1; - /* get last option from pdu to calculate the delta */ - - opt = options_start( pdu ); - for ( cnt = pdu->hdr->optcnt; cnt; --cnt ) { + /* Get last option from pdu to calculate the delta. For optcnt == + * 0x0F, opt will point at the end marker, so the new option will + * overwrite it. + */ + opt = options_start(pdu); + cnt = pdu->hdr->optcnt; + while ((pdu->hdr->optcnt == COAP_OPT_LONG && *opt != COAP_OPT_END) + || cnt--) { opt_code += COAP_OPT_DELTA(opt); opt = options_next(opt); } + if ((unsigned char *)opt > (unsigned char *)pdu->hdr + pdu->max_size) { + debug("illegal option list\n"); + return -1; + } + if ( type < opt_code ) { #ifndef NDEBUG coap_log(LOG_WARN, "options not added in correct order\n"); #endif return -1; } - - optcnt = pdu->hdr->optcnt; + + optcnt = old_optcnt = pdu->hdr->optcnt; + old_opt = opt; + optsize = len + (len > 14 ? 2 : 1); /* Create new option after last existing option: First check if we * need fence posts between type and last opt_code (i.e. delta > * 15), and then add actual option. */ - while (type - opt_code > 15) { - cnt = opt_code / COAP_OPTION_NOOP; + /* add fence post */ + fence = ((COAP_OPTION_NOOP * ((opt_code / COAP_OPTION_NOOP) + 1)) + - opt_code) << 4; + while (opt_code + 15 < type) { + if ((unsigned char *)opt + optsize + 1 > + (unsigned char *)pdu->hdr + pdu->max_size) + goto error; - if ((unsigned char *)opt + 1 > (unsigned char *)pdu->hdr + pdu->max_size) { - debug("cannot add fencepost option\n"); - return -1; - } - - /* add fence post */ optcnt += 1; - COAP_OPT_SETLENGTH( opt, 0 ); - COAP_OPT_SETDELTA( opt, (COAP_OPTION_NOOP * (cnt+1)) - opt_code ); + *opt = fence; opt_code += COAP_OPT_DELTA(opt); opt = options_next(opt); + fence = COAP_OPTION_NOOP << 4; } - if ((unsigned char *)opt + len + (len > 14 ? 2 : 1) > - (unsigned char *)pdu->hdr + pdu->max_size) { - debug("cannot add option\n"); - return -1; - } + if ((unsigned char *)opt + optsize + 1 > + (unsigned char *)pdu->hdr + pdu->max_size) + goto error; /* here, the actual option is added (delta <= 15) */ optcnt += 1; @@ -166,9 +176,28 @@ coap_add_option(coap_pdu_t *pdu, unsigned char type, unsigned int len, const uns memcpy(COAP_OPT_VALUE(opt), data, len); pdu->data = (unsigned char *)COAP_OPT_VALUE(opt) + len ; - pdu->hdr->optcnt = optcnt; + if (optcnt < COAP_OPT_LONG) { + pdu->hdr->optcnt = optcnt; + } else { + pdu->hdr->optcnt = COAP_OPT_LONG; + *pdu->data = COAP_OPT_END; + pdu->data++; + } pdu->length = pdu->data - (unsigned char *)pdu->hdr; return len; + + error: + /* Restore state before we have tried to add fencepost options. + * Because pdu->data and pdu->length have not yet been updated, + * there is no need to touch them. Only the end marker must been + * written anew if optcnt == 15; + */ + + pdu->hdr->optcnt = old_optcnt; + if (pdu->hdr->optcnt == COAP_OPT_LONG) + *old_opt = COAP_OPT_END; + + return -1; } int diff --git a/pdu.h b/pdu.h index 19dccc1a..dcda6013 100644 --- a/pdu.h +++ b/pdu.h @@ -175,6 +175,11 @@ typedef struct { && ((MSG)->code < 32)) #define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG)->code >= 64 && (MSG)->code <= 191) +#define COAP_OPT_LONG 0x0F /* OC == 0b1111 indicates that the option list in a + * CoAP message is limited by 0b11110000 marker */ + +#define COAP_OPT_END 0xF0 /* end marker */ + /** * Structures for more convenient handling of options. (To be used with ordered * coap_list_t.) The option's data will be added to the end of the coap_option @@ -244,7 +249,7 @@ void coap_delete_pdu(coap_pdu_t *); * destroys the PDU's data, so coap_add_data must be called after all options have been * added. */ -int coap_add_option(coap_pdu_t *pdu, unsigned char type, unsigned int len, const unsigned char *data); +int coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data); /** * Adds given data to the pdu that is passed as first parameter. Note that the PDU's