mirror of
https://github.com/obgm/libcoap.git
synced 2026-11-12 11:40:39 +03:00
handling of long option lists
This commit is contained in:
1 parent
6f0a4550c7
commit
582e59f107
6 files changed
+129
-46
No files matched your search
@@ -1,3 +1,21 @@
|
||||
2012-03-19 Olaf Bergmann <bergmann@tzi.org>
|
||||
|
||||
* pdu.c (coap_add_option): allow more than 15 options.
|
||||
|
||||
2012-03-15 Olaf Bergmann <bergmann@tzi.org>
|
||||
|
||||
* 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 <bergmann@tzi.org>
|
||||
|
||||
* examples/etsi_iot_01.c: Support for POST, PUT, DELETE on /test
|
||||
|
||||
2012-03-13 Olaf Bergmann <bergmann@tzi.org>
|
||||
|
||||
* encode.c (coap_encode_var_bytes): more efficient coding for 0
|
||||
|
||||
2012-03-11 Olaf Bergmann <bergmann@tzi.org>
|
||||
|
||||
* examples/etsi_iot_01.c: Test cases for 1st ETSI CoAP Plugtest,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user