From: Jin-Seong Kim Date: Fri, 28 Jul 2017 07:13:40 +0000 (+0900) Subject: netutils/libcoap : major patches to handle TCP packets on libcoap X-Git-Tag: 1.1_Public_Release~318^2~39 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2307ccbe1466587a4b89889ea554c08e1da77f0f;p=rtos%2Ftinyara.git netutils/libcoap : major patches to handle TCP packets on libcoap This commit is major patches to handle TCP packets on libcoap Change-Id: I4c760487fd83f3d49611c2dbe3b91f860ba02680 Signed-off-by: Jin-Seong Kim --- diff --git a/apps/examples/libcoap_client/libcoap-client.c b/apps/examples/libcoap_client/libcoap-client.c index b594117..f8c041c 100644 --- a/apps/examples/libcoap_client/libcoap-client.c +++ b/apps/examples/libcoap_client/libcoap-client.c @@ -313,7 +313,7 @@ finish: return len; } -static inline coap_opt_t *get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter) +static inline coap_opt_t *get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter, coap_transport_t transport) { coap_opt_filter_t f; @@ -323,7 +323,7 @@ static inline coap_opt_t *get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_it coap_option_setb(f, COAP_OPTION_BLOCK1); coap_option_setb(f, COAP_OPTION_BLOCK2); - coap_option_iterator_init(pdu, opt_iter, f); + coap_option_iterator_init2(pdu, opt_iter, f, transport); return coap_option_next(opt_iter); } @@ -338,9 +338,17 @@ inline int check_token(coap_pdu_t *received) return received->hdr->token_length == the_token.length && memcmp(received->hdr->token, the_token.s, the_token.length) == 0; } -void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) +int check_token_by_value(unsigned char *token, size_t len) { + if (len == the_token.length) { + if (!strncmp((char *)token, (char *)the_token.s, len)) + return 1; + } + return 0; +} +void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) +{ coap_pdu_t *pdu = NULL; coap_opt_t *block_opt; coap_opt_iterator_t opt_iter; @@ -350,46 +358,73 @@ void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, c unsigned char *databuf; coap_tid_t tid; -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { - debug("** process incoming %d.%02d response:\n", (received->hdr->code >> 5), received->hdr->code & 0x1F); - coap_show_pdu(received); + coap_transport_t transport = COAP_UDP; + + size_t tokenlen; + unsigned char *token_ptr = NULL; + char token[8] = {0,}; + + unsigned short code; + + if (ctx->protocol == COAP_PROTO_TCP || ctx->protocol == COAP_PROTO_TLS) { + transport = coap_get_tcp_header_type_from_size(received->length); + } + + coap_get_token2((received->transport_hdr), transport, &token_ptr, &tokenlen); + + if (tokenlen > 0) { + strncpy(token, (const char *)token_ptr, tokenlen); + printf("message_handler : token %s, len %d, the_token %s, len %d, token_ptr %s\n", + token, tokenlen, the_token.s, the_token.length, token_ptr); } -#endif /* check if this is a response to our original request */ - if (!check_token(received)) { + if (!check_token_by_value((unsigned char *)token, tokenlen)) { /* drop if this was just some message, or send RST in case of notification */ - if (!sent && (received->hdr->type == COAP_MESSAGE_CON || received->hdr->type == COAP_MESSAGE_NON)) { - coap_send_rst(ctx, remote, received); + if (!sent) { + if (ctx->protocol == COAP_PROTO_UDP || ctx->protocol == COAP_PROTO_DTLS) { + if (received->transport_hdr->udp.type == COAP_MESSAGE_CON || + received->transport_hdr->udp.type == COAP_MESSAGE_NON) { + coap_send_rst(ctx, remote, received); + } + } else if (ctx->protocol == COAP_PROTO_TCP || ctx->protocol == COAP_PROTO_TLS) { + /* TODO: do nothing? */ + } else { + /* should not enter here */ + } } + printf("message_handler : unmatched token, ignore it\n"); return; } - switch (received->hdr->type) { - case COAP_MESSAGE_CON: - /* acknowledge received response if confirmable (TODO: check Token) */ - coap_send_ack(ctx, remote, received); - break; - case COAP_MESSAGE_RST: - info("got RST\n"); - return; - default: - ; + if (ctx->protocol == COAP_PROTO_UDP || ctx->protocol == COAP_PROTO_DTLS) { + switch (received->hdr->type) { + case COAP_MESSAGE_CON: + /* acknowledge received response if confirmable (TODO: check Token) */ + coap_send_ack(ctx, remote, received); + break; + case COAP_MESSAGE_RST: + info("got RST\n"); + return; + default: + break; + } } + code = (unsigned short)coap_get_code(received, transport); + /* output the received data, if any */ - if (received->hdr->code == COAP_RESPONSE_CODE(205)) { + if (code == COAP_RESPONSE_CODE(205)) { /* set obs timer if we have successfully subscribed a resource */ - if (sent && coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter)) { + if (sent && coap_check_option2(received, COAP_OPTION_SUBSCRIPTION, &opt_iter, transport)) { debug("observation relationship established, set timeout to %d\n", obs_seconds); set_timeout(&obs_wait, obs_seconds); } /* Got some data, check if block option is set. Behavior is undefined if * both, Block1 and Block2 are present. */ - block_opt = get_block(received, &opt_iter); + block_opt = get_block(received, &opt_iter, transport); if (!block_opt) { /* There is no block option set, just read the data and we are done. */ if (coap_get_data(received, &len, &databuf)) { @@ -417,34 +452,48 @@ void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, c case COAP_OPTION_URI_PORT: case COAP_OPTION_URI_PATH: case COAP_OPTION_URI_QUERY: - coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) option->data), COAP_OPTION_LENGTH(*(coap_option *) option->data), COAP_OPTION_DATA(*(coap_option *) option->data)); + coap_add_option2(pdu, COAP_OPTION_KEY(*(coap_option *) option->data), + COAP_OPTION_LENGTH(*(coap_option *) option->data), + COAP_OPTION_DATA(*(coap_option *) option->data), transport); break; default: - ; /* skip other options */ + break; /* skip other options */ } } /* finally add updated block option from response, clear M bit */ /* blocknr = (blocknr & 0xfffffff7) + 0x10; */ debug("query block %d\n", (coap_opt_block_num(block_opt) + 1)); - coap_add_option(pdu, blktype, coap_encode_var_bytes(buf, ((coap_opt_block_num(block_opt) + 1) << 4) | COAP_OPT_BLOCK_SZX(block_opt)), buf); - - if (received->hdr->type == COAP_MESSAGE_CON) { - tid = coap_send_confirmed(ctx, remote, pdu); - } else { - tid = coap_send(ctx, remote, pdu); - } + coap_add_option2(pdu, blktype, coap_encode_var_bytes(buf, ((coap_opt_block_num(block_opt) + 1) << 4) | COAP_OPT_BLOCK_SZX(block_opt)), buf, transport); + + switch (ctx->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + if (received->hdr->type == COAP_MESSAGE_CON) { + tid = coap_send_confirmed(ctx, remote, pdu); + } else { + tid = coap_send(ctx, remote, pdu); + } - if (tid == COAP_INVALID_TID) { - debug("message_handler: error sending new request"); - coap_delete_pdu(pdu); - } else { - set_timeout(&max_wait, wait_seconds); - if (received->hdr->type != COAP_MESSAGE_CON) { + if (tid == COAP_INVALID_TID) { + debug("message_handler: error sending new request"); coap_delete_pdu(pdu); + } else { + set_timeout(&max_wait, wait_seconds); + if (received->hdr->type != COAP_MESSAGE_CON) { + coap_delete_pdu(pdu); + } } + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + tid = coap_send(ctx, remote, pdu); + set_timeout(&max_wait, wait_seconds); + coap_delete_pdu(pdu); + break; + default: /* should not be entered here */ + break; } - return; } } @@ -452,7 +501,7 @@ void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, c } else { /* no 2.05 */ /* check if an error was signaled and output payload if so */ - if (COAP_RESPONSE_CLASS(received->hdr->code) >= 4) { + if (COAP_RESPONSE_CLASS(code) >= 4) { fprintf(stderr, "%d.%02d", (received->hdr->code >> 5), received->hdr->code & 0x1F); if (coap_get_data(received, &len, &databuf)) { fprintf(stderr, " "); @@ -472,7 +521,7 @@ void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, c coap_delete_pdu(pdu); /* our job is done, we can exit at any time */ - ready = coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter) == NULL; + ready = coap_check_option2(received, COAP_OPTION_SUBSCRIPTION, &opt_iter, transport) == NULL; } void usage(const char *program, const char *version) @@ -1213,14 +1262,31 @@ int main(int argc, char **argv) } #endif - if (pdu->transport_hdr->udp.type == COAP_MESSAGE_CON) { - tid = coap_send_confirmed(ctx, &dst, pdu); - } else { + + switch(protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + if (pdu->transport_hdr->udp.type == COAP_MESSAGE_CON) { + tid = coap_send_confirmed(ctx, &dst, pdu); + } else { + tid = coap_send(ctx, &dst, pdu); + } + + if (pdu->transport_hdr->udp.type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) { + coap_delete_pdu(pdu); + } + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: tid = coap_send(ctx, &dst, pdu); - } - if (pdu->transport_hdr->udp.type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) { - coap_delete_pdu(pdu); + if (tid == COAP_INVALID_TID) { + coap_delete_pdu(pdu); + } + break; + default : + /* should not enter here */ + break; } set_timeout(&max_wait, wait_seconds); diff --git a/apps/include/netutils/libcoap/block.h b/apps/include/netutils/libcoap/block.h index d9f4098..d58c7f4 100644 --- a/apps/include/netutils/libcoap/block.h +++ b/apps/include/netutils/libcoap/block.h @@ -96,6 +96,21 @@ static inline void coap_opt_block_set_m(coap_opt_t *block_opt, int m) int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block); /** + * Initializes @p block from @p pdu. @p type must be either COAP_OPTION_BLOCK1 + * or COAP_OPTION_BLOCK2. When option @p type was found in @p pdu, @p block + * is initialized with values from this option and the function returns the + * value @c 1. Otherwise, @c 0 is returned. + * + * @param pdu The pdu to search for option @p type. + * @param type The option to search for (must be COAP_OPTION_BLOCK1 or + * COAP_OPTION_BLOCK2) + * @param block The block structure to initilize. + * @param transport The transport type of pdu + * @return @c 1 on success, @c 0 otherwise. + */ +int coap_get_block2(coap_pdu_t *pdu, unsigned short type, coap_block_t *block, coap_transport_t transport); + +/** * Writes a block option of type @p type to message @p pdu. If the * requested block size is too large to fit in @p pdu, it is reduced * accordingly. An exception is made for the final block when less diff --git a/apps/include/netutils/libcoap/net.h b/apps/include/netutils/libcoap/net.h index 381ef3c..13f0b07 100644 --- a/apps/include/netutils/libcoap/net.h +++ b/apps/include/netutils/libcoap/net.h @@ -69,6 +69,8 @@ typedef struct coap_queue_t { /**< remote address */ coap_tid_t id; /**< unique transaction id */ + coap_transport_t transport; /**< CoAP PDU transport type */ + coap_pdu_t *pdu;/**< the CoAP PDU to send */ } coap_queue_t; @@ -287,6 +289,25 @@ coap_tid_t coap_send_confirmed(coap_context_t *context, const coap_address_t *ds * @return A pointer to the new message or @c NULL on error. */ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts); + +/** + * Creates a new ACK PDU with specified error @p code. The options + * specified by the filter expression @p opts will be copied from the + * original request contained in @p request. Unless @c + * SHORT_ERROR_RESPONSE was defined at build time, the textual reason + * phrase for @p code will be added as payload, with Content-Type @c + * 0. This function returns a pointer to the new response message, or + * @c NULL on error. The storage allocated for the new message must be + * relased with coap_free(). + * + * @param request Specification of the received (confirmable) request. + * @param code The error code to set. + * @param opts An option filter that specifies which options to copy + * from the original request in @p node. + * @param protocol Using transport protocol of the session + * @return A pointer to the new message or @c NULL on error. + */ +coap_pdu_t *coap_new_error_response2(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts, coap_protocol_t protocol); /** * Sends a non-confirmed CoAP message to given destination. The memory * that is allocated by pdu will not be released by coap_send(). @@ -382,6 +403,16 @@ int coap_read(coap_context_t *context); void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id); /** + * Calculates a unique transaction id from given arguments @p peer and + * @p pdu. The id is returned in @p id. + * + * @param peer The remote party who sent @p pdu. + * @param pdu The message that initiated the transaction. + * @param id Set to the new id. + */ +void coap_transaction_id2(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id, coap_protocol_t protocol); + +/** * This function removes the element with given @p id from the list * given list. If @p id was found, @p node is updated to point to the * removed element. Note that the storage allocated by @p node is @@ -487,6 +518,41 @@ void coap_ticks(coap_tick_t *); */ int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown); +/** + * Verifies that @p pdu contains no unknown critical options. Options + * must be registered at @p ctx, using the function + * coap_register_option(). A basic set of options is registered + * automatically by coap_new_context(). This function returns @c 1 if + * @p pdu is ok, @c 0 otherwise. The given filter object @p unknown + * will be updated with the unknown options. As only @c COAP_MAX_OPT + * options can be signalled this way, remaining options must be + * examined manually. + * + * @code + coap_opt_filter_t f = COAP_OPT_NONE; + coap_opt_iterator_t opt_iter; + + if (coap_option_check_critical(ctx, pdu, f) == 0) { + coap_option_iterator_init(pdu, &opt_iter, f); + + while (coap_option_next(&opt_iter)) { + if (opt_iter.type & 0x01) { + ... handle unknown critical option in opt_iter ... + } + } + } + * @endcode + * + * @param ctx The context where all known options are registered. + * @param pdu The PDU to check. + * @param unknown The output filter that will be updated to indicate the + * unknown critical options found in @p pdu. + * @param transport The transport type of PDU + * + * @return @c 1 if everything was ok, @c 0 otherwise. + */ +int coap_option_check_critical2(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown, coap_transport_t transport); + #ifdef __cplusplus } #endif diff --git a/apps/include/netutils/libcoap/option.h b/apps/include/netutils/libcoap/option.h index d29800a..53f54ad 100644 --- a/apps/include/netutils/libcoap/option.h +++ b/apps/include/netutils/libcoap/option.h @@ -250,6 +250,23 @@ coap_opt_t *coap_option_next(coap_opt_iterator_t *oi); coap_opt_t *coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi); /** + * Retrieves the first option of type @p type from @p pdu. @p oi must + * point to a coap_opt_iterator_t object that will be initialized by + * this function to filter only options with code @p type. This + * function returns the first option with this type, or @c NULL if not + * found. + * + * @param pdu The PDU to parse for options. + * @param type The option type code to search for. + * @param oi An iterator object to use. + * @param transport The transport header type of PDU + * + * @return A pointer to the first option of type @p type, or @c NULL + * if not found. + */ +coap_opt_t *coap_check_option2(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi, coap_transport_t transport); + +/** * Encodes the given delta and length values into @p opt. This * function returns the number of bytes that were required to encode * @p delta and @p length or @c 0 on error. Note that the result diff --git a/apps/include/netutils/libcoap/resource.h b/apps/include/netutils/libcoap/resource.h index 31ae6d5..850026c 100644 --- a/apps/include/netutils/libcoap/resource.h +++ b/apps/include/netutils/libcoap/resource.h @@ -250,6 +250,16 @@ coap_resource_t *coap_get_resource_from_key(coap_context_t *context, coap_key_t void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key); /** + * Calculates the hash key for the resource requested by the + * Uri-Options of @p request. This function calls coap_hash() for + * every path segment. + * + * @param request The requesting pdu. + * @param key The resulting hash is stored in @p key + * @param transport The type of transport protocol header type + */ +void coap_hash_request_uri2(const coap_pdu_t *request, coap_key_t key, coap_transport_t transport); +/** * @addtogroup observe */ diff --git a/apps/netutils/libcoap/async.c b/apps/netutils/libcoap/async.c index ab733f7..fc82412 100644 --- a/apps/netutils/libcoap/async.c +++ b/apps/netutils/libcoap/async.c @@ -27,7 +27,7 @@ coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t coap_async_state_t *s; coap_tid_t id; - coap_transaction_id(peer, request, &id); + coap_transaction_id2(peer, request, &id, context->protocol); LL_SEARCH_SCALAR(context->async_state, s, id, id); if (s != NULL) { diff --git a/apps/netutils/libcoap/block.c b/apps/netutils/libcoap/block.c index e34ec9e..fe6e56b 100644 --- a/apps/netutils/libcoap/block.c +++ b/apps/netutils/libcoap/block.c @@ -41,7 +41,7 @@ unsigned int coap_opt_block_num(const coap_opt_t *block_opt) return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4); } -int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) +int coap_get_block2(coap_pdu_t *pdu, unsigned short type, coap_block_t *block, coap_transport_t transport) { coap_opt_iterator_t opt_iter; coap_opt_t *option; @@ -49,7 +49,7 @@ int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) assert(block); memset(block, 0, sizeof(coap_block_t)); - if (pdu && (option = coap_check_option(pdu, type, &opt_iter))) { + if (pdu && (option = coap_check_option2(pdu, type, &opt_iter, transport))) { block->szx = COAP_OPT_BLOCK_SZX(option); if (COAP_OPT_BLOCK_MORE(option)) { block->m = 1; @@ -61,6 +61,11 @@ int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) return 0; } +int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) +{ + return coap_get_block2(pdu, type, block, COAP_UDP); +} + int coap_write_block_opt(coap_block_t *block, unsigned short type, coap_pdu_t *pdu, size_t data_length) { size_t start, want, avail; diff --git a/apps/netutils/libcoap/debug.c b/apps/netutils/libcoap/debug.c index bdfd6bc..25acb1d 100644 --- a/apps/netutils/libcoap/debug.c +++ b/apps/netutils/libcoap/debug.c @@ -336,7 +336,7 @@ void coap_log_impl(coap_log_t level, const char *format, ...) return; } - log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + log_fd = stderr; coap_ticks(&now); if (print_timestamp(timebuf, sizeof(timebuf), now)) { diff --git a/apps/netutils/libcoap/net.c b/apps/netutils/libcoap/net.c index 68d5081..18c4f95 100644 --- a/apps/netutils/libcoap/net.c +++ b/apps/netutils/libcoap/net.c @@ -522,13 +522,12 @@ void coap_free_context(coap_context_t *context) #endif /* WITH_CONTIKI */ } -int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown) +int coap_option_check_critical2(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown, coap_transport_t transport) { - coap_opt_iterator_t opt_iter; int ok = 1; - coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL); + coap_option_iterator_init2(pdu, &opt_iter, COAP_OPT_ALL, transport); while (coap_option_next(&opt_iter)) { @@ -555,12 +554,23 @@ int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_fi return ok; } -void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id) +int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown) +{ + return coap_option_check_critical2(ctx, pdu, unknown, COAP_UDP); +} + +void coap_transaction_id2(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id, coap_protocol_t protocol) { coap_key_t h; memset(h, 0, sizeof(coap_key_t)); + /* FIXME : CoAP over TCP doesn't need to check mid */ + if (protocol == COAP_PROTO_TCP || protocol == COAP_PROTO_TLS) { + *id = protocol; + return; + } + /* Compare the complete address structure in case of IPv4. For IPv6, * we need to look at the transport address only. */ @@ -588,12 +598,16 @@ void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h); coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h); #endif /* WITH_LWIP || WITH_CONTIKI */ - /* TODO : Considering TCP Case */ coap_hash((const unsigned char *)&pdu->transport_hdr->udp.id, sizeof(unsigned short), h); *id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]); } +void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id) +{ + coap_transaction_id2(peer, pdu, id, COAP_PROTO_UDP); +} + coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *request) { coap_pdu_t *response; @@ -640,7 +654,8 @@ coap_tid_t coap_send_impl(coap_context_t *context, const coap_address_t *dst, co } if (bytes_written >= 0) { - coap_transaction_id(dst, pdu, &id); + coap_transaction_id2(dst, pdu, &id, context->protocol); + debug("coap_send_impl : protocol %d, bytes_written %d, tid %d\n", context->protocol, bytes_written, id); } else { coap_log(LOG_CRIT, "coap_send: sendto\n"); } @@ -959,10 +974,13 @@ int coap_read(coap_context_t *ctx) goto error_early; } +#ifndef WITH_TCP + /* TCP header can be smaller than coap_hdr_t */ if ((size_t) bytes_read < sizeof(coap_hdr_t)) { debug("coap_read: discarded invalid frame\n"); goto error_early; } +#endif /* TCP doesn't have version field in PDU */ if ((ctx->protocol == COAP_PROTO_UDP || ctx->protocol == COAP_PROTO_DTLS) @@ -989,13 +1007,36 @@ int coap_read(coap_context_t *ctx) memcpy(&node->local, &dst, sizeof(coap_address_t)); memcpy(&node->remote, &src, sizeof(coap_address_t)); - if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) { - warn("discard malformed PDU"); - goto error; + coap_transport_t transport; + + switch (ctx->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + if (!coap_pdu_parse((unsigned char *)buf, bytes_read, node->pdu)) { + warn("coap_read : discard malformed PDU"); + goto error; + } + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)buf)[0] >> 4); + debug("coap_read : received header type, transport %d, len %u, bytes_read %d\n", transport, ((buf[0] >> 4) & 0x0f), bytes_read); + if (!coap_pdu_parse2((unsigned char*)buf, bytes_read, node->pdu, transport)) { + warn("coap_read : discard malformed TCP PDU\n"); + goto error; + } + node->transport = transport; + debug("coap_read : Received %d type pdu\n", transport); +#if 0 + coap_debug_pdu_print(node->pdu, transport); +#endif + break; + default: + break; } /* and add new node to receive queue */ - coap_transaction_id(&node->remote, node->pdu, &node->id); + coap_transaction_id2(&node->remote, node->pdu, &node->id, ctx->protocol); coap_insert_node(&ctx->recvqueue, node); #ifndef NDEBUG @@ -1125,8 +1166,7 @@ coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id) return queue; } - -coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts) +coap_pdu_t *coap_new_error_response2(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts, coap_protocol_t protocol) { coap_opt_iterator_t opt_iter; coap_pdu_t *response; @@ -1216,9 +1256,28 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coa #endif } - return response; + if (protocol == COAP_PROTO_TCP || protocol == COAP_PROTO_TLS) { + coap_pdu_t *tcp_response = NULL; + tcp_response = coap_convert_to_tcp_pdu(response); + if (tcp_response == NULL) { + warn("coap_new_error_response2 : failed to convert to TCP pdu\n"); + } else { + debug("coap_new_error_response2 : succeed to convert to TCP pdu\n"); +#if 0 + coap_debug_pdu_print(response, COAP_UDP); + coap_debug_pdu_print(tcp_response, coap_get_tcp_header_type_from_size((response->length - COAP_UDP_HEADER))); +#endif + } + return tcp_response; + } else { + return response; + } } +coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts) +{ + return coap_new_error_response2(request, code, opts, COAP_PROTO_UDP); +} /** * Quick hack to determine the size of the resource description for * .well-known/core. @@ -1252,24 +1311,52 @@ coap_pdu_t *wellknown_response(coap_context_t *context, coap_pdu_t *request) coap_opt_t *query_filter; size_t offset = 0; - /* TODO : Considering TCP Case */ - resp = coap_pdu_init(request->transport_hdr->udp.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, - COAP_RESPONSE_CODE(205), request->transport_hdr->udp.id, COAP_MAX_PDU_SIZE); + coap_pdu_t *tcp_resp = NULL; /* used for TCP pdu */ + + coap_transport_t transport = COAP_UDP; /* Request pdu transport type */ + + unsigned char msgType = COAP_MESSAGE_NON; + unsigned short msgId = 0; + + size_t tokenlen = 0; + unsigned char *token_ptr = NULL; /* Token pointer for request */ + + if (context->protocol == COAP_PROTO_TCP || context->protocol == COAP_PROTO_TLS) { + transport = coap_get_tcp_header_type_from_size((request->length - COAP_UDP_HEADER)); + + } else if (context->protocol == COAP_PROTO_UDP || context->protocol == COAP_PROTO_DTLS) { + if (request->transport_hdr->udp.type == COAP_MESSAGE_CON) { + msgType = COAP_MESSAGE_ACK; + } else { + msgType = COAP_MESSAGE_NON; + } + msgId = request->transport_hdr->udp.id; + } else { + /* Should not enter here */ + } + + coap_get_token2(request->transport_hdr, transport, &token_ptr, &tokenlen); + + if (tokenlen > 0) { + debug("wellknown_response : token %s, tokenlen %d\n", token_ptr, tokenlen); + } + + resp = coap_pdu_init(msgType, COAP_RESPONSE_CODE(205), msgId, COAP_MAX_PDU_SIZE); if (!resp) { debug("wellknown_response: cannot create PDU\n"); return NULL; } /* TODO : Considering TCP Case */ - if (!coap_add_token(resp, request->transport_hdr->udp.token_length, request->transport_hdr->udp.token)) { + if (!coap_add_token(resp, tokenlen, token_ptr)) { debug("wellknown_response: cannot add token\n"); goto error; } - query_filter = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter); + query_filter = coap_check_option2(request, COAP_OPTION_URI_QUERY, &opt_iter, transport); wkc_len = get_wkc_len(context, query_filter); /* check whether the request contains the Block2 option */ - if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) { + if (coap_get_block2(request, COAP_OPTION_BLOCK2, &block, transport)) { offset = block.num << (block.szx + 4); if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */ @@ -1337,18 +1424,52 @@ coap_pdu_t *wellknown_response(coap_context_t *context, coap_pdu_t *request) result = print_wellknown(context, resp->data, &len, offset, query_filter); if ((result & COAP_PRINT_STATUS_ERROR) != 0) { - debug("print_wellknown failed\n"); + debug("wellknown_response : print_wellknown failed\n"); goto error; } resp->length += COAP_PRINT_OUTPUT_LENGTH(result); - return resp; + + if (context->protocol == COAP_PROTO_TCP || context->protocol == COAP_PROTO_TLS) { + + tcp_resp = coap_convert_to_tcp_pdu(resp); + + if (tcp_resp == NULL) { + warn("wellknown_response : failed to convert to TCP pdu\n"); + } else { + debug("wellknown_response : convert to new TCP pdu\n"); +#if 0 + coap_debug_pdu_print(resp, COAP_UDP); + coap_debug_pdu_print(tcp_resp, coap_get_tcp_header_type_from_size((resp->length - COAP_UDP_HEADER))); +#endif + } + + return tcp_resp; + } else { + + debug("wellknown_response : create well-known response\n"); + return resp; + } error: /* set error code 5.03 and remove all options and data from response */ /* TODO : Considering TCP Case */ resp->transport_hdr->udp.code = COAP_RESPONSE_CODE(503); resp->length = sizeof(coap_hdr_t) + resp->transport_hdr->udp.token_length; + + if (context->protocol == COAP_PROTO_TCP || context->protocol == COAP_PROTO_TLS) { + tcp_resp = coap_convert_to_tcp_pdu(resp); + if (tcp_resp == NULL) { + warn("wellknown_response : failed to convert to TCP pdu\n"); + } else { + debug("wellknown_response : convert to new TCP pdu\n"); +#if 0 + coap_debug_pdu_print(resp, COAP_UDP); + coap_debug_pdu_print(tcp_resp, coap_get_tcp_header_type_from_size((resp->length - COAP_UDP_HEADER))); +#endif + } + + } return resp; } @@ -1364,44 +1485,54 @@ void handle_request(coap_context_t *context, coap_queue_t *node) coap_resource_t *resource; coap_key_t key; + unsigned int code = 0; + coap_transport_t transport = 0; + + coap_pdu_t *tcp_response = NULL; + coap_option_filter_clear(opt_filter); /* try to find the resource from the request URI */ - coap_hash_request_uri(node->pdu, key); + transport = node->transport; + coap_hash_request_uri2(node->pdu, key, transport); resource = coap_get_resource_from_key(context, key); + code = coap_get_code(node->pdu, transport); + + debug("handle_request : code %d transport %d\n", code, transport); + if (!resource) { /* The resource was not found. Check if the request URI happens to * be the well-known URI. In that case, we generate a default * response, otherwise, we return 4.04 */ - switch (node->pdu->transport_hdr->udp.code) { + switch (code) { case COAP_REQUEST_GET: if (is_wkc(key)) { /* GET request for .well-known/core */ - info("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); + info("handle_request : create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); response = wellknown_response(context, node->pdu); } else { /* GET request for any another resource, return 4.04 */ - debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", key[0], key[1], key[2], key[3]); - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), opt_filter); + debug("handle_request : GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", key[0], key[1], key[2], key[3]); + response = coap_new_error_response2(node->pdu, COAP_RESPONSE_CODE(404), opt_filter, context->protocol); } break; default: /* any other request type */ - debug("unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", key[0], key[1], key[2], key[3]); + debug("handle_request : unhandled request for unknown resource 0x%02x%02x%02x%02x\r\n", key[0], key[1], key[2], key[3]); if (!coap_is_mcast(&node->local)) { - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter); + response = coap_new_error_response2(node->pdu, COAP_RESPONSE_CODE(405), opt_filter, context->protocol); } } if (response && coap_send(context, &node->remote, response) == COAP_INVALID_TID) { - warn("cannot send response for transaction %u\n", node->id); + warn("handle_request : cannot send response for transaction %u\n", node->id); } coap_delete_pdu(response); @@ -1409,12 +1540,12 @@ void handle_request(coap_context_t *context, coap_queue_t *node) } /* the resource was found, check if there is a registered handler */ - if ((size_t) node->pdu->transport_hdr->udp.code - 1 < sizeof(resource->handler) / sizeof(coap_method_handler_t)) { - h = resource->handler[node->pdu->transport_hdr->udp.code - 1]; + if ((size_t)(code - 1) < sizeof(resource->handler) / sizeof(coap_method_handler_t)) { + h = resource->handler[code - 1]; } if (h) { - debug("call custom handler for resource 0x%02x%02x%02x%02x\n", key[0], key[1], key[2], key[3]); + debug("handle_request : call custom handler for resource 0x%02x%02x%02x%02x\n", key[0], key[1], key[2], key[3]); response = coap_pdu_init(node->pdu->transport_hdr->udp.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, 0, node->pdu->transport_hdr->udp.id, COAP_MAX_PDU_SIZE); @@ -1425,28 +1556,59 @@ void handle_request(coap_context_t *context, coap_queue_t *node) h(context, resource, &node->remote, node->pdu, &token, response); - if (response->transport_hdr->udp.type != COAP_MESSAGE_NON - || (response->transport_hdr->udp.code >= 64 && !coap_is_mcast(&node->local))) { + switch(context->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + if (response->transport_hdr->udp.type != COAP_MESSAGE_NON + || (response->transport_hdr->udp.code >= 64 && !coap_is_mcast(&node->local))) { - if (coap_send(context, &node->remote, response) == COAP_INVALID_TID) { - debug("cannot send response for message %d\n", node->pdu->transport_hdr->udp.id); + if (coap_send(context, &node->remote, response) == COAP_INVALID_TID) { + debug("handle_request : cannot send response for message %d\n", node->pdu->transport_hdr->udp.id); + } + } + coap_delete_pdu(response); + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + tcp_response = coap_convert_to_tcp_pdu(response); + if (tcp_response == NULL) { + warn("handle_request : failed to convert TCP pdu\n"); + } else { + debug("handle_request : succeed to convert TCP pdu\n"); + transport = coap_get_tcp_header_type_from_size((response->length - COAP_UDP_HEADER)); +#if 0 + coap_debug_pdu_print(response, COAP_UDP); + coap_debug_pdu_print(tcp_response, transport); +#endif } - } - coap_delete_pdu(response); + code = coap_get_code(tcp_response, transport); + + if (code >= 64 && !coap_is_mcast(&node->local)) { + if (coap_send(context, &node->remote, tcp_response) == COAP_INVALID_TID) { + debug("handle_request : cannot send TCP reponse\n"); + } + } + coap_delete_pdu(tcp_response); + break; + default: + warn("handle_request : error! un-known protocol %d\n", context->protocol); + break; + + } } else { - warn("cannot generate response\r\n"); + warn("handle_request : cannot generate response\r\n"); } } else { if (WANT_WKC(node->pdu, key)) { - debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); + debug("handle_request : create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN); response = wellknown_response(context, node->pdu); } else { - response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter); + response = coap_new_error_response2(node->pdu, COAP_RESPONSE_CODE(405), opt_filter, context->protocol); } if (!response || (coap_send(context, &node->remote, response) == COAP_INVALID_TID)) { - debug("cannot send response for transaction %u\n", node->id); + debug("handle_request : cannot send response for transaction %u\n", node->id); } coap_delete_pdu(response); } @@ -1523,6 +1685,9 @@ void coap_dispatch(coap_context_t *context) coap_pdu_t *response; coap_opt_filter_t opt_filter; + coap_transport_t transport; + unsigned int code; + if (!context) { return; } @@ -1536,85 +1701,118 @@ void coap_dispatch(coap_context_t *context) context->recvqueue = context->recvqueue->next; rcvd->next = NULL; - if (rcvd->pdu->transport_hdr->udp.version != COAP_DEFAULT_VERSION) { - debug("dropped packet with unknown version %u\n", rcvd->pdu->transport_hdr->udp.version); - goto cleanup; - } + if (context->protocol == COAP_PROTO_TCP || context->protocol == COAP_PROTO_TLS) { + /* CoAP over TCP pdu will be handled as NON */ + transport = rcvd->transport; - switch (rcvd->pdu->transport_hdr->udp.type) { - case COAP_MESSAGE_ACK: - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + if (coap_option_check_critical2(context, rcvd->pdu, opt_filter, transport) == 0) { + goto cleanup; + } - if (rcvd->pdu->transport_hdr->udp.code == 0) { + if (transport == COAP_UDP) { + warn("coap_dispatch : wrong header (something wrong..)\n"); goto cleanup; } - /* FIXME: if sent code was >= 64 the message might have been a - * notification. Then, we must flag the observer to be alive - * by setting obs->fail_cnt = 0. */ - if (sent && COAP_RESPONSE_CLASS(sent->pdu->transport_hdr->udp.code) == 2) { - const str token = { sent->pdu->transport_hdr->udp.token_length, - sent->pdu->transport_hdr->udp.token - }; + code = coap_get_code(rcvd->pdu, transport); - coap_touch_observer(context, &sent->remote, &token); + debug("coap_dispatch : code %d, transport %d\n", code, transport); + + if (code > 0 && code < 32 ) { + /* REQUEST */ + handle_request(context, rcvd); + } else if (code >= 64 && code <= 191) { + /* RESPONSE */ + handle_response(context, sent, rcvd); + } else { + warn("coap_dispatch : dropped message with invalied code %d", code); + goto cleanup; + } + } else if (context->protocol == COAP_PROTO_UDP || context->protocol == COAP_PROTO_DTLS) { + if (rcvd->pdu->transport_hdr->udp.version != COAP_DEFAULT_VERSION) { + debug("dropped packet with unknown version %u\n", + rcvd->pdu->transport_hdr->udp.version); + goto cleanup; } - break; - case COAP_MESSAGE_RST: - /* We have sent something the receiver disliked, so we remove - * not only the transaction but also the subscriptions we might - * have. */ + switch (rcvd->pdu->transport_hdr->udp.type) { + case COAP_MESSAGE_ACK: + /* find transaction in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); - coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->transport_hdr->udp.id)); + if (rcvd->pdu->transport_hdr->udp.code == 0) { + goto cleanup; + } - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + /* FIXME: if sent code was >= 64 the message might have been a + * notification. Then, we must flag the observer to be alive + * by setting obs->fail_cnt = 0. */ + if (sent && COAP_RESPONSE_CLASS(sent->pdu->transport_hdr->udp.code) == 2) { + const str token = {sent->pdu->transport_hdr->udp.token_length, + sent->pdu->transport_hdr->udp.token + }; - if (sent) { - coap_handle_rst(context, sent); - } - goto cleanup; + coap_touch_observer(context, &sent->remote, &token); + } + break; + + case COAP_MESSAGE_RST: + /* We have sent something the receiver disliked, so we remove + * not only the transaction but also the subscriptions we might + * have. */ + + coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->transport_hdr->udp.id)); - case COAP_MESSAGE_NON: /* check for unknown critical options */ - if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { + /* find transaction in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + + if (sent) { + coap_handle_rst(context, sent); + } goto cleanup; - } - break; - case COAP_MESSAGE_CON: /* check for unknown critical options */ - if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { + case COAP_MESSAGE_NON: /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { + goto cleanup; + } + break; - /* FIXME: send response only if we have received a request. Otherwise, - * send RST. */ - response = coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter); + case COAP_MESSAGE_CON: /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) { - if (!response) { - warn("coap_dispatch: cannot create error reponse\n"); - } else { - if (coap_send(context, &rcvd->remote, response) == COAP_INVALID_TID) { - warn("coap_dispatch: error sending reponse\n"); + /* FIXME: send response only if we have received a request. Otherwise, + * send RST. */ + response = coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter); + + if (!response) { + warn("coap_dispatch: cannot create error reponse\n"); + } else { + if (coap_send(context, &rcvd->remote, response) == COAP_INVALID_TID) { + warn("coap_dispatch: error sending reponse\n"); + } + coap_delete_pdu(response); } - coap_delete_pdu(response); - } - goto cleanup; + goto cleanup; + } + break; } - break; - } - /* Pass message to upper layer if a specific handler was - * registered for a request that should be handled locally. */ - if (handle_locally(context, rcvd)) { - if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->transport_hdr->udp)) { - handle_request(context, rcvd); - } else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->transport_hdr->udp)) { - handle_response(context, sent, rcvd); - } else { - debug("dropped message with invalid code\n"); - coap_send_message_type(context, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST); + /* Pass message to upper layer if a specific handler was + * registered for a request that should be handled locally. */ + if (handle_locally(context, rcvd)) { + if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->transport_hdr->udp)) { + handle_request(context, rcvd); + } else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->transport_hdr->udp)) { + handle_response(context, sent, rcvd); + } else { + debug("dropped message with invalid code\n"); + coap_send_message_type(context, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST); + } } + } else { + warn("coap_dispatch : error! un-known protocol type\n"); + goto cleanup; } cleanup: @@ -1723,7 +1921,7 @@ static void coap_retransmittimer_restart(coap_context_t *ctx) coap_tick_t now, elapsed, delay; if (ctx->timer_configured) { - printf("clearing\n"); + debug("coap_retransmittimer_restart : clearing\n"); sys_untimeout(coap_retransmittimer_execute, (void *)ctx); ctx->timer_configured = 0; } @@ -1747,7 +1945,7 @@ static void coap_retransmittimer_restart(coap_context_t *ctx) delay = 0; } - printf("scheduling for %d ticks\n", delay); + debug("coap_retransmittimer_restart : scheduling for %d ticks\n", delay); sys_timeout(delay, coap_retransmittimer_execute, (void *)ctx); ctx->timer_configured = 1; } diff --git a/apps/netutils/libcoap/option.c b/apps/netutils/libcoap/option.c index 88d97b9..0a80746 100644 --- a/apps/netutils/libcoap/option.c +++ b/apps/netutils/libcoap/option.c @@ -43,7 +43,6 @@ coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_t transport) size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { - const coap_opt_t *opt_start = opt; /* store where parsing starts */ assert(opt); @@ -253,18 +252,23 @@ coap_opt_t *coap_option_next(coap_opt_iterator_t *oi) return current_opt; } -coap_opt_t *coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi) +coap_opt_t *coap_check_option2(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi, coap_transport_t transport) { coap_opt_filter_t f; coap_option_filter_clear(f); coap_option_setb(f, type); - coap_option_iterator_init(pdu, oi, f); + coap_option_iterator_init2(pdu, oi, f, transport); return coap_option_next(oi); } +coap_opt_t *coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi) +{ + return coap_check_option2(pdu, type, oi, COAP_UDP); +} + unsigned short coap_opt_delta(const coap_opt_t *opt) { unsigned short n; diff --git a/apps/netutils/libcoap/pdu.c b/apps/netutils/libcoap/pdu.c index ffb272c..6489f99 100644 --- a/apps/netutils/libcoap/pdu.c +++ b/apps/netutils/libcoap/pdu.c @@ -107,6 +107,7 @@ coap_pdu_t *coap_pdu_init2(unsigned char type, unsigned char code, unsigned shor #endif unsigned int length = 0; + switch (transport) { case COAP_UDP: length = sizeof(pdu->transport_hdr->udp); @@ -129,6 +130,8 @@ coap_pdu_t *coap_pdu_init2(unsigned char type, unsigned char code, unsigned shor debug("it has wrong type\n"); } + debug("coap_pdu_init2 : transport %d, length %d, size %d\n", transport, length, size); + #ifndef WITH_TCP assert(size <= COAP_MAX_PDU_SIZE); /* Size must be large enough to fit the header. */ @@ -820,8 +823,7 @@ int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu, coap_tr assert(pdu); if (pdu->max_size < length) { - debug("insufficient space to store parsed PDU\n"); - printf("[COAP] insufficient space to store parsed PDU\n"); + printf("coap_pdu_parse2 : insufficient space to store parsed PDU\n"); return -1; } @@ -882,7 +884,7 @@ int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu, coap_tr opt = ((unsigned char *)&(pdu->transport_hdr->tcp_32bit)) + headerSize + tokenLength; break; default: - printf("it has wrong type\n"); + printf("coap_pdu_parse2 : it has wrong type\n"); } #endif pdu->length = length; @@ -973,31 +975,40 @@ discard: coap_pdu_t *coap_convert_to_tcp_pdu(coap_pdu_t *pdu) { - coap_transport_t transport = COAP_UDP; + coap_transport_t transport = COAP_TCP; coap_pdu_t *tcp_pdu = NULL; coap_opt_t *tcp_opt = NULL, *udp_opt = NULL; size_t tokenlen = 0; size_t newsize = 0; /* size of UDP pdu without UDP Header */ - size_t length = 0; + int length = 0; /* size of UDP pdu length including UDP header */ if (pdu == NULL) { warn("coap_convert_to_tcp_pdu : do not allow empty pdu\n"); return pdu; } - transport = coap_get_tcp_header_type_from_size((pdu->length - COAP_UDP_HEADER)); + if (pdu->length <= COAP_UDP_HEADER) { + transport = COAP_TCP; + } else { + transport = coap_get_tcp_header_type_from_size((pdu->length - COAP_UDP_HEADER)); + } + + if ((pdu->length - COAP_UDP_HEADER) < 0) { + newsize = 0; + } else { + newsize = (pdu->length - COAP_UDP_HEADER); + } - newsize = (pdu->length - COAP_UDP_HEADER); - length = newsize; /* Used to find pdu->data pointer */ + debug("coap_convert_to_tcp_pdu : transport %d, newsize %d\n", transport, newsize); tcp_pdu = coap_pdu_init2(0, pdu->transport_hdr->udp.code, 0, (newsize + 1), transport); if (!tcp_pdu) { - warn("coap_new_request : failed to create pdu for TCP\n"); + warn("coap_convert_to_tcp_pdu : failed to create pdu for TCP\n"); goto convert_error_discard; } else { - debug("coap_new_request : new tcp pdu is created, size %d\n", pdu->length); + debug("coap_convert_to_tcp_pdu : new tcp pdu is created, size %d\n", pdu->length); /* Fill extended length field on CoAP over TCP header */ coap_add_length(tcp_pdu, transport, newsize); @@ -1038,6 +1049,13 @@ coap_pdu_t *coap_convert_to_tcp_pdu(coap_pdu_t *pdu) break; } + /* Fill extra TCP pdu Info */ + tcp_pdu->max_size = pdu->max_size; + tcp_pdu->max_delta = pdu->max_delta; + tcp_pdu->length = newsize + tokenlen + coap_get_tcp_header_length_for_transport(transport); + + length = (int)tcp_pdu->length; + /* Move UDP pdu pointer to start of option */ udp_opt = (unsigned char *)(&(pdu->transport_hdr->udp) +1) + tokenlen; @@ -1045,13 +1063,18 @@ coap_pdu_t *coap_convert_to_tcp_pdu(coap_pdu_t *pdu) newsize = newsize - tokenlen; memcpy(tcp_opt, udp_opt, newsize); - /* Copy payload data from UDP pdu */ length -= (tokenlen + coap_get_tcp_header_length_for_transport(transport)); + + if (length < 0) { + /* Reset to length to 0 when there are no options and no payload */ + length = 0; + } + while (length && *tcp_opt != COAP_PAYLOAD_START) { coap_option_t option; memset(&option, 0, sizeof(coap_option_t)); - if (!next_option_safe(&tcp_opt, &length, &option)) { - debug("coap_convert_to_tcp_pdu : drop\n"); + if (!next_option_safe(&tcp_opt, (size_t *)&length, &option)) { + printf("coap_convert_to_tcp_pdu : drop\n"); goto convert_error_discard; } } @@ -1059,6 +1082,7 @@ coap_pdu_t *coap_convert_to_tcp_pdu(coap_pdu_t *pdu) if (length) { if (*tcp_opt != COAP_PAYLOAD_START) { /* somethings wrong ..*/ + printf("coap_convert_to_tcp_pdu : cannot find COAP_PAYLOAD_START\n"); goto convert_error_discard; } else { tcp_opt++; @@ -1068,10 +1092,6 @@ coap_pdu_t *coap_convert_to_tcp_pdu(coap_pdu_t *pdu) } } - /* Fill extra TCP pdu Info */ - tcp_pdu->max_size = pdu->max_size; - tcp_pdu->max_delta = pdu->max_delta; - tcp_pdu->length = newsize + tokenlen + coap_get_tcp_header_length_for_transport(transport); /* If you want to see the PDU in details, enable below functions */ #if 0 coap_debug_pdu_print(pdu, COAP_UDP); diff --git a/apps/netutils/libcoap/resource.c b/apps/netutils/libcoap/resource.c index 8a890fb..332fcdb 100644 --- a/apps/netutils/libcoap/resource.c +++ b/apps/netutils/libcoap/resource.c @@ -421,7 +421,7 @@ void coap_delete_attr(coap_attr_t *attr) #endif } -void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) +void coap_hash_request_uri2(const coap_pdu_t *request, coap_key_t key, coap_transport_t transport) { coap_opt_iterator_t opt_iter; coap_opt_filter_t filter; @@ -432,12 +432,17 @@ void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) coap_option_filter_clear(filter); coap_option_setb(filter, COAP_OPTION_URI_PATH); - coap_option_iterator_init((coap_pdu_t *) request, &opt_iter, filter); + coap_option_iterator_init2((coap_pdu_t *) request, &opt_iter, filter, transport); while ((option = coap_option_next(&opt_iter))) { coap_hash(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), key); } } +void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) +{ + coap_hash_request_uri2(request, key, COAP_UDP); +} + void coap_add_resource(coap_context_t *context, coap_resource_t *resource) { #ifndef WITH_CONTIKI