netutils/libcoap : major patches to handle TCP packets on libcoap
authorJin-Seong Kim <jseong82.kim@samsung.com>
Fri, 28 Jul 2017 07:13:40 +0000 (16:13 +0900)
committerEunBong Song <eunb.song@samsung.com>
Wed, 30 Aug 2017 04:15:47 +0000 (21:15 -0700)
This commit is major patches to handle TCP packets on libcoap

Change-Id: I4c760487fd83f3d49611c2dbe3b91f860ba02680
Signed-off-by: Jin-Seong Kim <jseong82.kim@samsung.com>
12 files changed:
apps/examples/libcoap_client/libcoap-client.c
apps/include/netutils/libcoap/block.h
apps/include/netutils/libcoap/net.h
apps/include/netutils/libcoap/option.h
apps/include/netutils/libcoap/resource.h
apps/netutils/libcoap/async.c
apps/netutils/libcoap/block.c
apps/netutils/libcoap/debug.c
apps/netutils/libcoap/net.c
apps/netutils/libcoap/option.c
apps/netutils/libcoap/pdu.c
apps/netutils/libcoap/resource.c

index b594117..f8c041c 100644 (file)
@@ -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);
index d9f4098..d58c7f4 100644 (file)
@@ -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
index 381ef3c..13f0b07 100644 (file)
@@ -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
index d29800a..53f54ad 100644 (file)
@@ -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
index 31ae6d5..850026c 100644 (file)
@@ -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
  */
 
index ab733f7..fc82412 100644 (file)
@@ -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) {
index e34ec9e..fe6e56b 100644 (file)
@@ -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;
index bdfd6bc..25acb1d 100644 (file)
@@ -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)) {
index 68d5081..18c4f95 100644 (file)
@@ -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;
        }
index 88d97b9..0a80746 100644 (file)
@@ -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;
index ffb272c..6489f99 100644 (file)
@@ -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);
index 8a890fb..332fcdb 100644 (file)
@@ -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