netutils/libcoap : introduce patch to support TCP
authorJin-Seong Kim <jseong82.kim@samsung.com>
Wed, 5 Jul 2017 07:51:20 +0000 (16:51 +0900)
committerEunBong Song <eunb.song@samsung.com>
Wed, 30 Aug 2017 04:15:47 +0000 (21:15 -0700)
This commit is to add patch to support TCP (iotivity 1.3.0-rel)
 - https://github.com/iotivity/iotivity

Change-Id: I2b10530c0e152663b3360f6e3247154f7769102e
Signed-off-by: Jin-Seong Kim <jseong82.kim@samsung.com>
14 files changed:
apps/examples/libcoap_client/Makefile
apps/examples/libcoap_client/libcoap-client.c
apps/examples/libcoap_server/Makefile
apps/examples/libcoap_server/libcoap-server.c
apps/include/netutils/libcoap/option.h
apps/include/netutils/libcoap/pdu.h
apps/netutils/libcoap/Makefile
apps/netutils/libcoap/async.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
apps/netutils/libcoap/uri.c

index 3c4bbaf..945d845 100644 (file)
@@ -66,6 +66,7 @@ endif
 ifeq ($(CONFIG_NET_SECURITY_TLS),y)
 CFLAGS += -DWITH_MBEDTLS
 endif
+CFLAGS += -DWITH_TCP
 #CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
 
 ifneq ($(CONFIG_BUILD_KERNEL),y)
index 4e74a68..a305f79 100644 (file)
@@ -158,9 +158,9 @@ coap_pdu_t *new_ack(coap_context_t *ctx, coap_queue_t *node)
        coap_pdu_t *pdu = coap_new_pdu();
 
        if (pdu) {
-               pdu->hdr->type = COAP_MESSAGE_ACK;
-               pdu->hdr->code = 0;
-               pdu->hdr->id = node->pdu->hdr->id;
+               pdu->transport_hdr->udp.type = COAP_MESSAGE_ACK;
+               pdu->transport_hdr->udp.code = 0;
+               pdu->transport_hdr->udp.id = node->pdu->transport_hdr->udp.id;
        }
 
        return pdu;
@@ -171,7 +171,7 @@ coap_pdu_t *new_response(coap_context_t *ctx, coap_queue_t *node, unsigned int c
        coap_pdu_t *pdu = new_ack(ctx, node);
 
        if (pdu) {
-               pdu->hdr->code = code;
+               pdu->transport_hdr->udp.code = code;
        }
 
        return pdu;
@@ -186,11 +186,11 @@ coap_pdu_t *coap_new_request(coap_context_t *ctx, method_t m, coap_list_t *optio
                return NULL;
        }
 
-       pdu->hdr->type = msgtype;
-       pdu->hdr->id = coap_new_message_id(ctx);
-       pdu->hdr->code = m;
+       pdu->transport_hdr->udp.type = msgtype;
+       pdu->transport_hdr->udp.id = coap_new_message_id(ctx);
+       pdu->transport_hdr->udp.code = m;
 
-       pdu->hdr->token_length = the_token.length;
+       pdu->transport_hdr->udp.token_length = the_token.length;
        if (!coap_add_token(pdu, the_token.length, the_token.s)) {
                debug("cannot add token to request\n");
        }
@@ -237,7 +237,7 @@ coap_tid_t clear_obs(coap_context_t *ctx, const coap_address_t *remote)
                        }
                }
 
-               if (pdu->hdr->type == COAP_MESSAGE_CON) {
+               if (pdu->transport_hdr->udp.type == COAP_MESSAGE_CON) {
                        tid = coap_send_confirmed(ctx, remote, pdu);
                } else {
                        tid = coap_send(ctx, remote, pdu);
@@ -246,7 +246,7 @@ coap_tid_t clear_obs(coap_context_t *ctx, const coap_address_t *remote)
                if (tid == COAP_INVALID_TID) {
                        debug("clear_obs: error sending new request");
                        coap_delete_pdu(pdu);
-               } else if (pdu->hdr->type != COAP_MESSAGE_CON) {
+               } else if (pdu->transport_hdr->udp.type != COAP_MESSAGE_CON) {
                        coap_delete_pdu(pdu);
                }
        }
@@ -1207,13 +1207,13 @@ int main(int argc, char **argv)
        }
 #endif
 
-       if (pdu->hdr->type == COAP_MESSAGE_CON) {
+       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->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) {
+       if (pdu->transport_hdr->udp.type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) {
                coap_delete_pdu(pdu);
        }
 
index c140e17..f50064a 100644 (file)
@@ -66,6 +66,7 @@ endif
 ifeq ($(CONFIG_NET_SECURITY_TLS),y)
 CFLAGS += -DWITH_MBEDTLS
 endif
+CFLAGS += -DWITH_TCP
 #CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
 
 ifneq ($(CONFIG_BUILD_KERNEL),y)
index 64e31e0..7a76e3e 100644 (file)
@@ -95,7 +95,7 @@ void hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource, coap_a
 {
        unsigned char buf[3];
 
-       response->hdr->code = COAP_RESPONSE_CODE(205);
+       response->transport_hdr->udp.code = COAP_RESPONSE_CODE(205);
 
        coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
 
@@ -118,12 +118,12 @@ void hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_ad
         * when query ?ticks is given. */
 
        /* if my_clock_base was deleted, we pretend to have no such resource */
-       response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
+       response->transport_hdr->udp.code = my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
 
        if (request != NULL && coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) {
                subscription = coap_add_observer(resource, peer, token);
                if (subscription) {
-                       subscription->non = request->hdr->type == COAP_MESSAGE_NON;
+                       subscription->non = request->transport_hdr->udp.type == COAP_MESSAGE_NON;
                        coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
                }
        }
@@ -170,7 +170,7 @@ void hnd_put_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_ad
         */
 
        /* if my_clock_base was deleted, we pretend to have no such resource */
-       response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
+       response->transport_hdr->udp.code = my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
 
        resource->dirty = 1;
 
@@ -193,7 +193,7 @@ void hnd_delete_time(coap_context_t *ctx, struct coap_resource_t *resource, coap
 {
        my_clock_base = 0;                      /* mark clock as "deleted" */
 
-       /* type = request->hdr->type == COAP_MESSAGE_CON  */
+       /* type = request->transport_hdr->udp.type == COAP_MESSAGE_CON  */
        /*   ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
 }
 
@@ -206,10 +206,10 @@ void hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource, coap_a
        size_t size;
 
        if (async) {
-               if (async->id != request->hdr->id) {
+               if (async->id != request->transport_hdr->udp.id) {
                        coap_opt_filter_t f;
                        coap_option_filter_clear(f);
-                       response->hdr->code = COAP_RESPONSE_CODE(503);
+                       response->transport_hdr->udp.code = COAP_RESPONSE_CODE(503);
                }
                return;
        }
@@ -245,7 +245,7 @@ void check_async(coap_context_t *ctx, coap_tick_t now)
                return;
        }
 
-       response->hdr->id = coap_new_message_id(ctx);
+       response->transport_hdr->udp.id = coap_new_message_id(ctx);
 
        if (async->tokenlen) {
                coap_add_token(response, async->tokenlen, async->token);
@@ -254,7 +254,7 @@ void check_async(coap_context_t *ctx, coap_tick_t now)
        coap_add_data(response, 4, (unsigned char *)"done");
 
        if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
-               debug("check_async: cannot send response for message %d\n", response->hdr->id);
+               debug("check_async: cannot send response for message %d\n", response->transport_hdr->udp.id);
        }
        coap_delete_pdu(response);
        coap_remove_async(ctx, async->id, &tmp);
index 84a2f90..d29800a 100644 (file)
@@ -69,7 +69,7 @@ size_t coap_opt_size(const coap_opt_t *opt);
  * @param pdu The PDU containing the options.
  * @return A pointer to the first option if available, or @c NULL otherwise.
  */
-coap_opt_t *options_start(coap_pdu_t *pdu);
+coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_t transport);
 
 /**
  * Interprets @p opt as pointer to a CoAP option and advances to
@@ -176,6 +176,24 @@ typedef struct {
 } coap_opt_iterator_t;
 
 /**
+ * Initializes the given option iterator @p oi to point to the beginning of the
+ * @p pdu's option list. This function returns @p oi on success, @c NULL
+ * otherwise (i.e. when no options exist). Note that a length check on the
+ * option list must be performed before coap_option_iterator_init() is called.
+ *
+ * @param pdu    The PDU the options of which should be walked through.
+ * @param oi     An iterator object that will be initilized.
+ * @param filter An optional option type filter.
+ *               With @p type != @c COAP_OPT_ALL, coap_option_next()
+ *               will return only options matching this bitmask.
+ *               Fence-post options @c 14, @c 28, @c 42, ... are always
+ *               skipped.
+ *
+ * @return       The iterator object @p oi on success, @c NULL otherwise.
+ */
+coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter);
+
+/**
  * Initializes the given option iterator @p oi to point to the
  * beginning of the @p pdu's option list. This function returns @p oi
  * on success, @c NULL otherwise (i.e. when no options exist).
@@ -192,7 +210,7 @@ typedef struct {
  *
  * @return The iterator object @p oi on success, @c NULL otherwise.
  */
-coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter);
+coap_opt_iterator_t *coap_option_iterator_init2(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter, coap_transport_t transport);
 
 /**
  * Updates the iterator @p oi to point to the next option. This
index 5a94536..f17fde0 100644 (file)
@@ -70,6 +70,7 @@
 #define COAP_OPTION_PROXY_URI    35    /* C, String, 1-1034 B, (none) */
 #define COAP_OPTION_PROXY_SCHEME 39    /* C, String, 1-255 B, (none) */
 #define COAP_OPTION_SIZE1        60    /* E, uint, 0-4 B, (none) */
+#define COAP_OPTION_SIZE2        28 /* E, uint, 0-4 B, (none) */
 
 /* option types from draft-ietf-coap-observe-09 */
 
@@ -150,35 +151,100 @@ char *coap_response_phrase(unsigned char code);
  * use an unallocated type here and hope for the best. */
 #define COAP_MEDIATYPE_ANY                         0xff        /* any media type */
 
-/* CoAP transaction id */
-/*typedef unsigned short coap_tid_t; */
+/**
+  * coap_tid_t is used to store CoAP transaction id, i.e. a hash value
+  * built from the remote transport address and the message id of a
+  * CoAP PDU.  Valid transaction ids are greater or equal zero.
+  */
 typedef int coap_tid_t;
+
+/** Indicates an invalid transaction id. */
 #define COAP_INVALID_TID -1
 
+#define COAP_TCP_HEADER_NO_FIELD    2
+#define COAP_TCP_HEADER_8_BIT       3
+#define COAP_TCP_HEADER_16_BIT      4
+#define COAP_TCP_HEADER_32_BIT      6
+
+#define COAP_TCP_LENGTH_FIELD_8_BIT      13
+#define COAP_TCP_LENGTH_FIELD_16_BIT     269
+#define COAP_TCP_LENGTH_FIELD_32_BIT     65805
+
+#define COAP_TCP_LENGTH_LIMIT_8_BIT      13
+#define COAP_TCP_LENGTH_LIMIT_16_BIT     256
+#define COAP_TCP_LENGTH_LIMIT_32_BIT     65536
+
+#define COAP_TCP_LENGTH_FIELD_NUM_8_BIT      13
+#define COAP_TCP_LENGTH_FIELD_NUM_16_BIT     14
+#define COAP_TCP_LENGTH_FIELD_NUM_32_BIT     15
+
+#define COAP_OPTION_FIELD_8_BIT      12
+#define COAP_OPTION_FIELD_16_BIT     256
+#define COAP_OPTION_FIELD_32_BIT     65536
+
+typedef enum {
+    COAP_UDP = 0,
+    COAP_TCP,
+    COAP_TCP_8BIT,
+    COAP_TCP_16BIT,
+    COAP_TCP_32BIT
+} coap_transport_t;
+
 #ifdef WORDS_BIGENDIAN
 typedef struct {
-       unsigned int version: 2;                /* protocol version */
-       unsigned int type: 2;           /* type flag */
-       unsigned int token_length: 4;   /* length of Token */
-       unsigned int code: 8;           /* request method (value 1--10) or response code (value 40-255) */
+       unsigned short version:2;      /* protocol version */
+       unsigned short type:2;         /* type flag */
+       unsigned short token_length:4; /* length of Token */
+       unsigned short code:8;         /* request method (value 1--10) or response */
        unsigned short id;                      /* message id */
        unsigned char token[];          /* the actual token, if any */
-} coap_hdr_t;
+} coap_hdr_udp_t;
 #else
 typedef struct {
-       unsigned int token_length: 4;   /* length of Token */
-       unsigned int type: 2;           /* type flag */
-       unsigned int version: 2;                /* protocol version */
-       unsigned int code: 8;           /* request method (value 1--10) or response code (value 40-255) */
+       unsigned short token_length:4; /* length of Token */
+       unsigned short type:2;         /* type flag */
+       unsigned short version:2;      /* protocol version */
+       unsigned short code:8;         /* request method (value 1--10) or response */
        unsigned short id;                      /* transaction id (network byte order!) */
        unsigned char token[];          /* the actual token, if any */
-} coap_hdr_t;
+} coap_hdr_udp_t;
 #endif
 
-#define COAP_MESSAGE_IS_EMPTY(MSG)    ((MSG)->code == 0)
+typedef struct {
+  unsigned char header_data[COAP_TCP_HEADER_NO_FIELD];
+  unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_t;
+
+typedef struct {
+  unsigned char header_data[COAP_TCP_HEADER_8_BIT];
+  unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_8bit_t;
+
+typedef struct {
+  unsigned char header_data[COAP_TCP_HEADER_16_BIT];
+  unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_16bit_t;
+
+typedef struct {
+  unsigned char header_data[6];
+  unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_32bit_t;
+
+typedef union {
+  coap_hdr_udp_t udp;
+  coap_hdr_tcp_t tcp;
+  coap_hdr_tcp_8bit_t tcp_8bit;
+  coap_hdr_tcp_16bit_t tcp_16bit;
+  coap_hdr_tcp_32bit_t tcp_32bit;
+} coap_hdr_transport_t;
+
+// Typedef for backwards compatibility.
+typedef coap_hdr_udp_t coap_hdr_t;
+
+#define COAP_MESSAGE_IS_EMPTY(MSG)    ((MSG).code == 0)
 #define COAP_MESSAGE_IS_REQUEST(MSG)  (!COAP_MESSAGE_IS_EMPTY(MSG)     \
-                                      && ((MSG)->code < 32))
-#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG)->code >= 64 && (MSG)->code <= 191)
+                                      && ((MSG).code < 32))
+#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG).code >= 64 && (MSG).code <= 191)
 
 #define COAP_OPT_LONG 0x0F             /* OC == 0b1111 indicates that the option list in a
                                                                 * CoAP message is limited by 0b11110000 marker */
@@ -206,10 +272,12 @@ typedef struct {
 typedef struct {
        size_t max_size;/**< allocated storage for options and data */
 
-       coap_hdr_t *hdr;
-       unsigned short max_delta;
-       /**< highest option number */
-       unsigned short length;  /**< PDU length (including header, options, data)  */
+       union {
+               coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message. This may or may not equal (coap_hdr_t*)(pdu+1) depending on the memory management implementation. */
+               coap_hdr_transport_t *transport_hdr; /**< Address of the first byte of the CoAP message. This may or may not equal (coap_hdr_t*)(pdu+1) depending on the memory management implementation. */
+       };
+       unsigned short max_delta; /**< highest option number */
+       unsigned int length; /**< PDU length (including header, options, data)  */
        unsigned char *data;    /**< payload */
 
 #ifdef WITH_LWIP
@@ -260,6 +328,24 @@ coap_pdu_t *coap_pdu_from_pbuf(struct pbuf *pbuf);
 coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size);
 
 /**
+ * Creates a new CoAP PDU of given @p size (must be large enough to hold the
+ * basic CoAP message header (coap_hdr_t). The function returns a pointer to
+ * the node coap_pdu_t object on success, or @c NULL on error. The storage
+ * allocated for the result must be released with coap_delete_pdu().
+ *
+ * @param type The type of the PDU (one of COAP_MESSAGE_CON,
+ *             COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST).
+ * @param code The message code.
+ * @param id   The message id to set or COAP_INVALID_TID if unknown.
+ * @param size The number of bytes to allocate for the actual message.
+ * @param transport The transport type.
+ *
+ * @return A pointer to the new PDU object or @c NULL on error.
+ */
+coap_pdu_t *
+coap_pdu_init2(unsigned char type, unsigned char code, unsigned short id, size_t size, coap_transport_t transport);
+
+/**
  * Clears any contents from @p pdu and resets @c version field, @c
  * length and @c data pointers. @c max_size is set to @p size, any
  * other field is set to @c 0. Note that @p pdu must be a valid
@@ -268,53 +354,228 @@ coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short
 void coap_pdu_clear(coap_pdu_t *pdu, size_t size);
 
 /**
- * Creates a new CoAP PDU. The object is created on the heap and must be released
- * using coap_delete_pdu();
+ * Clears any contents from @p pdu and resets @c version field, @c
+ * length and @c data pointers. @c max_size is set to @p size, any
+ * other field is set to @c 0. Note that @p pdu must be a valid
+ * pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
+ */
+void coap_pdu_clear2(coap_pdu_t *pdu, size_t size, coap_transport_t transport, unsigned int length);
+
+/**
+ * Creates a new CoAP PDU.
+ * The object is created on the heap and must be released using
+ * coap_delete_pdu();
  *
  * @deprecated This function allocates the maximum storage for each
  * PDU. Use coap_pdu_init() instead.
  */
 coap_pdu_t *coap_new_pdu(void);
 
+/**
+ * Creates a new CoAP PDU. The object is created on the heap and must be released
+ * using coap_delete_pdu();
+ *
+ * @deprecated This function allocates the maximum storage for each
+ * PDU. Use coap_pdu_init2() instead.
+ */
+coap_pdu_t *coap_new_pdu2(coap_transport_t transport, unsigned int size);
+
 void coap_delete_pdu(coap_pdu_t *);
 
 /**
- * Parses @p data into the CoAP PDU structure given in @p result. This
- * function returns @c 0 on error or a number greater than zero on
- * success.
+ * Parses @p data into the CoAP PDU structure given in @p result.
+ * This function returns @c 0 on error or a number greater than zero on success.
  *
  * @param data   The raw data to parse as CoAP PDU
  * @param length The actual size of @p data
  * @param result The PDU structure to fill. Note that the structure must
  *               provide space for at least @p length bytes to hold the
  *               entire CoAP PDU.
+ *
  * @return A value greater than zero on success or @c 0 on error.
  */
 int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *result);
 
 /**
+ * Parses @p data into the CoAP PDU structure given in @p result.
+ * This function returns @c 0 on error or a number greater than zero on success.
+ *
+ * @param data   The raw data to parse as CoAP PDU
+ * @param length The actual size of @p data
+ * @param result The PDU structure to fill. Note that the structure must
+ *               provide space for at least @p length bytes to hold the
+ *               entire CoAP PDU.
+ * @param transport The transport type.
+ * @return A value greater than zero on success or @c 0 on error.
+ */
+int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu, coap_transport_t transport);
+
+/**
+ * Get total pdu size including header + option + payload (with marker) from pdu data.
+ *
+ * @param data   The raw data to parse as CoAP PDU.
+ * @param size   payload size of pdu.
+ * @return Total message length.
+ */
+size_t coap_get_total_message_length(const unsigned char *data, size_t size);
+
+/**
+ * Get transport type of coap header for coap over tcp
+ * through payload size(including payload marker) + option size.
+ *
+ * @param size   payload size of pdu.
+ * @return The transport type.
+ */
+coap_transport_t coap_get_tcp_header_type_from_size(unsigned int size);
+
+/**
+ * Get transport type of coap header for coap over tcp
+ * through first nibble(0~E) of init-byte .
+ *
+ * @param legnth   length value of init byte.
+* @return The transport type.
+ */
+coap_transport_t coap_get_tcp_header_type_from_initbyte(unsigned int length);
+
+/**
+ * Add length of option/payload into 'Len+ byte...' field of coap header
+ * for coap over tcp.
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @param length  length value of init byte.
+ */
+void coap_add_length(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int length);
+
+/**
+ * Get the length of option/payload field of coap header for coap over tcp.
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @return length value of init byte.
+ */
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_t transport);
+
+/**
+ * Get the length of option/payload field of coap header for coap over tcp.
+ *
+ * @param header   The header to parse.
+ * @return transport The transport type.
+ */
+unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_t transport);
+
+/**
+ * Get length of header including len, TKL, Len+bytes, Code, token bytes for coap over tcp.
+ *
+ * @param data   The raw data to parse as CoAP PDU
+ * @return header length + token length
+ */
+unsigned int coap_get_tcp_header_length(unsigned char *data);
+
+/**
+ * Get length of header including len, TKL, Len+bytes, Code
+ * without token bytes for coap over tcp.
+ *
+ * @param transport The transport type.
+ * @return header length.
+ */
+unsigned int coap_get_tcp_header_length_for_transport(coap_transport_t transport);
+
+/**
+ * Get option length.
+ *
+ * @param key      delta of option
+ * @param length   length of option
+ * @return total option length
+ */
+size_t coap_get_opt_header_length(unsigned short key, size_t length);
+
+/**
+ * Add code in coap header.
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @param code  The message code.
+ */
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int code);
+
+/**
+ * Get message code from coap header
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @return The message code.
+ */
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_t transport);
+
+/**
+ * Adds token of length @p len to @p pdu.
+ * Adding the token destroys any following contents of the pdu. Hence options
+ * and data must be added after coap_add_token() has been called. In @p pdu,
+ * length is set to @p len + @c 4, and max_delta is set to @c 0.  This funtion
+ * returns @c 0 on error or a value greater than zero on success.
+ *
+ * @param pdu  The PDU where the token is to be added.
+ * @param len  The length of the new token.
+ * @param data The token to add.
+ *
+ * @return A value greater than zero on success, or @c 0 on error.
+ */
+int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
+
+/**
  * Adds token of length @p len to @p pdu. Adding the token destroys
  * any following contents of the pdu. Hence options and data must be
- * added after coap_add_token() has been called. In @p pdu, length is
+ * added after coap_add_token2() has been called. In @p pdu, length is
  * set to @p len + @c 4, and max_delta is set to @c 0.  This funtion
  * returns @c 0 on error or a value greater than zero on success.
  *
- * @param pdu  The PDU where the token is to be added.
+ * @param pdu  The pdu pointer.
  * @param len  The length of the new token.
  * @param data The token to add.
+ * @param transport The transport type.
  * @return A value greater than zero on success, or @c 0 on error.
  */
-int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
+int coap_add_token2(coap_pdu_t *pdu, size_t len, const unsigned char *data, coap_transport_t transport);
+
+/**
+ * Get token from coap header
+ *
+ * @param pdu_hdr  The header pointer of PDU.
+ * @param token  out parameter to get token.
+ * @param token_length  out parameter to get token length.
+ */
+void coap_get_token(const coap_hdr_t *pdu_hdr, unsigned char **token, unsigned int *token_length);
+
+/**
+ * Get token from coap header based on transport type
+ *
+ * @param pdu_hdr  The header pointer of PDU.
+ * @param transport The transport type.
+ * @param token  out parameter to get token.
+ * @param token_length  out parameter to get token length.
+ */
+void coap_get_token2(const coap_hdr_transport_t *pdu_hdr, coap_transport_t transport, unsigned char **token, unsigned int *token_length);
+
+/**
+ * Adds option of given type to pdu that is passed as first parameter. 
+ * coap_add_option() destroys the PDU's data, so coap_add_data() must be called
+ * after all options have been added. As coap_add_token() destroys the options
+ * following the token, the token must be added before coap_add_option() is
+ * called. This function returns the number of bytes written or @c 0 on error.
+ */
+size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data);
 
 /**
  * Adds option of given type to pdu that is passed as first
- * parameter. coap_add_option() destroys the PDU's data, so
+ * parameter. coap_add_option2() destroys the PDU's data, so
  * coap_add_data() must be called after all options have been added.
- * As coap_add_token() destroys the options following the token,
- * the token must be added before coap_add_option() is called.
+ * As coap_add_token2() destroys the options following the token,
+ * the token must be added before coap_add_option2() is called.
  * This function returns the number of bytes written or @c 0 on error.
  */
-size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data);
+size_t coap_add_option2(coap_pdu_t *pdu, unsigned short type, unsigned int len,
+                        const unsigned char *data, coap_transport_t transport);
 
 /**
  * Adds option of given type to pdu that is passed as first
index b7d68ca..780a34e 100644 (file)
@@ -88,6 +88,7 @@ endif
 ifeq ($(CONFIG_NET_SECURITY_TLS),y)
 CFLAGS += -DWITH_MBEDTLS
 endif
+CFLAGS += -DWITH_TCP
 #CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
 
 ifeq ($(CONFIG_WINDOWS_NATIVE),y)
index 719d564..ab733f7 100644 (file)
@@ -21,6 +21,7 @@
 #include <apps/netutils/libcoap/debug.h>
 #include <apps/netutils/libcoap/async.h>
 
+/* TODO : Considering TCP Case */
 coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data)
 {
        coap_async_state_t *s;
@@ -37,17 +38,18 @@ coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t
        }
 
        /* store information for handling the asynchronous task */
-       s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length);
+       s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) +
+                       request->transport_hdr->udp.token_length);
        if (!s) {
                coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
                return NULL;
        }
 
-       memset(s, 0, sizeof(coap_async_state_t) + request->hdr->token_length);
+       memset(s, 0, sizeof(coap_async_state_t) + request->transport_hdr->udp.token_length);
 
        /* set COAP_ASYNC_CONFIRM according to request's type */
        s->flags = flags & ~COAP_ASYNC_CONFIRM;
-       if (request->hdr->type == COAP_MESSAGE_CON) {
+       if (request->transport_hdr->udp.type == COAP_MESSAGE_CON) {
                s->flags |= COAP_ASYNC_CONFIRM;
        }
 
@@ -55,9 +57,9 @@ coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t
 
        memcpy(&s->peer, peer, sizeof(coap_address_t));
 
-       if (request->hdr->token_length) {
-               s->tokenlen = request->hdr->token_length;
-               memcpy(s->token, request->hdr->token, request->hdr->token_length);
+       if (request->transport_hdr->udp.token_length) {
+               s->tokenlen = request->transport_hdr->udp.token_length;
+               memcpy(s->token, request->transport_hdr->udp.token, request->transport_hdr->udp.token_length);
        }
 
        memcpy(&s->id, &id, sizeof(coap_tid_t));
index fbe7192..bdfd6bc 100644 (file)
@@ -236,12 +236,18 @@ size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, si
 #ifndef WITH_CONTIKI
 void coap_show_pdu(const coap_pdu_t *pdu)
 {
-       unsigned char buf[COAP_MAX_PDU_SIZE];   /* need some space for output creation */
+#ifndef WITH_TCP
+       unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
+#else
+       unsigned char buf[COAP_TCP_LENGTH_LIMIT_32_BIT]; /* need some space for output creation */
+#endif
        int encode = 0, have_options = 0;
        coap_opt_iterator_t opt_iter;
        coap_opt_t *option;
-
-       fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type, pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
+       /* TODO : Considering TCP Case */
+       fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->transport_hdr->udp.version,
+                       pdu->transport_hdr->udp.type, pdu->transport_hdr->udp.token_length,
+                                   pdu->transport_hdr->udp.code, ntohs(pdu->transport_hdr->udp.id));
 
        /* show options, if any */
        coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
@@ -254,7 +260,11 @@ void coap_show_pdu(const coap_pdu_t *pdu)
                        fprintf(COAP_DEBUG_FD, ",");
                }
 
-               if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI || opt_iter.type == COAP_OPTION_URI_HOST || opt_iter.type == COAP_OPTION_LOCATION_PATH || opt_iter.type == COAP_OPTION_LOCATION_QUERY || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY) {
+       if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI
+               || opt_iter.type == COAP_OPTION_URI_HOST
+               || opt_iter.type == COAP_OPTION_LOCATION_PATH
+               || opt_iter.type == COAP_OPTION_LOCATION_QUERY
+               || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY) {
                        encode = 0;
                } else {
                        encode = 1;
@@ -284,7 +294,10 @@ void coap_show_pdu(const coap_pdu_t *pdu)
 {
        unsigned char buf[80];          /* need some space for output creation */
 
-       PRINTF("v:%d t:%d oc:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type, pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
+       PRINTF("v:%d t:%d oc:%d c:%d id:%u",
+               pdu->transport_hdr->udp.version, pdu->transport_hdr->udp.type,
+               pdu->transport_hdr->udp.optcnt, pdu->transport_hdr->udp.code,
+               uip_ntohs(pdu->transport_hdr->udp.id));
 
        /* show options, if any */
        if (pdu->hdr->optcnt) {
index 1bfc400..68d5081 100644 (file)
@@ -588,8 +588,8 @@ 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 */
-
-       coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h);
+       /* 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]);
 }
@@ -599,8 +599,9 @@ coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst, coa
        coap_pdu_t *response;
        coap_tid_t result = COAP_INVALID_TID;
 
-       if (request && request->hdr->type == COAP_MESSAGE_CON) {
-               response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, sizeof(coap_pdu_t));
+       /* TODO : Considering TCP Case */
+       if (request && request->transport_hdr->udp.type == COAP_MESSAGE_CON) {
+               response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->transport_hdr->udp.id, sizeof(coap_pdu_t));
                if (response) {
                        result = coap_send(context, dst, response);
                        coap_delete_pdu(response);
@@ -745,7 +746,8 @@ coap_tid_t coap_send_message_type(coap_context_t *context, const coap_address_t
        coap_tid_t result = COAP_INVALID_TID;
 
        if (request) {
-               response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t));
+               /* TODO : Considering TCP Case */
+               response = coap_pdu_init(type, 0, request->transport_hdr->udp.id, sizeof(coap_pdu_t));
                if (response) {
                        result = coap_send(context, dst, response);
                        coap_delete_pdu(response);
@@ -818,7 +820,7 @@ coap_tid_t coap_send_confirmed(coap_context_t *context, const coap_address_t *ds
                etimer_set(&context->retransmit_timer, nextpdu->t);
                PROCESS_CONTEXT_END(&coap_retransmit_process);
        }
-#endif                                                 /* WITH_CONTIKI */
+#endif /* WITH_CONTIKI */
 
        return node->id;
 }
@@ -840,7 +842,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
                }
 #endif
 
-               debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->hdr->id));
+               debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->transport_hdr->udp.id));
 
                node->id = coap_send_impl(context, &node->remote, node->pdu);
                return node->id;
@@ -855,11 +857,12 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
 #ifndef WITHOUT_OBSERVE
        /* Check if subscriptions exist that should be canceled after
           COAP_MAX_NOTIFY_FAILURES */
-       if (node->pdu->hdr->code >= 64) {
+       /* TODO : Considering TCP Case */
+       if (node->pdu->transport_hdr->udp.code >= 64) {
                str token = { 0, NULL };
 
-               token.length = node->pdu->hdr->token_length;
-               token.s = node->pdu->hdr->token;
+               token.length = node->pdu->transport_hdr->udp.token_length;
+               token.s = node->pdu->transport_hdr->udp.token;
 
                coap_handle_failed_notify(context, &node->remote, &token);
        }
@@ -1082,10 +1085,12 @@ void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst
        coap_queue_t *p, *q;
 
        debug("cancel_all_messages\n");
-       while (context->sendqueue && coap_address_equals(dst, &context->sendqueue->remote) && token_match(token, token_length, context->sendqueue->pdu->hdr->token, context->sendqueue->pdu->hdr->token_length)) {
+       /* TODO : Considering TCP Case */
+       while (context->sendqueue && coap_address_equals(dst, &context->sendqueue->remote)
+                  && token_match(token, token_length, context->sendqueue->pdu->transport_hdr->udp.token, context->sendqueue->pdu->transport_hdr->udp.token_length)) {
                q = context->sendqueue;
                context->sendqueue = q->next;
-               debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+               debug("**** removed transaction %d\n", ntohs(q->pdu->transport_hdr->udp.id));
                coap_delete_node(q);
        }
 
@@ -1098,9 +1103,11 @@ void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst
 
        /* when q is not NULL, it does not match (dst, token), so we can skip it */
        while (q) {
-               if (coap_address_equals(dst, &q->remote) && token_match(token, token_length, q->pdu->hdr->token, q->pdu->hdr->token_length)) {
+               /* TODO : Considering TCP Case */
+               if (coap_address_equals(dst, &q->remote)
+                       && token_match(token, token_length, q->pdu->transport_hdr->udp.token, q->pdu->transport_hdr->udp.token_length)) {
                        p->next = q->next;
-                       debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+                       debug("**** removed transaction %d\n", ntohs(q->pdu->transport_hdr->udp.id));
                        coap_delete_node(q);
                        q = p->next;
                } else {
@@ -1123,7 +1130,8 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coa
 {
        coap_opt_iterator_t opt_iter;
        coap_pdu_t *response;
-       size_t size = sizeof(coap_hdr_t) + request->hdr->token_length;
+       /* TODO : Considering TCP Case */
+       size_t size = sizeof(coap_hdr_t) + request->transport_hdr->udp.token_length;
        int type;
        coap_opt_t *option;
        unsigned short opt_type = 0;    /* used for calculating delta-storage */
@@ -1140,7 +1148,8 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coa
        assert(request);
 
        /* cannot send ACK if original request was not confirmable */
-       type = request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
+       /* TODO : Considering TCP Case */
+       type = request->transport_hdr->udp.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
 
        /* Estimate how much space we need for options to copy from
         * request. We always need the Token, for 4.02 the unknown critical
@@ -1183,10 +1192,11 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coa
        }
 
        /* Now create the response and fill with options and payload data. */
-       response = coap_pdu_init(type, code, request->hdr->id, size);
+       /* TODO : Considering TCP Case */
+       response = coap_pdu_init(type, code, request->transport_hdr->udp.id, size);
        if (response) {
                /* copy token */
-               if (!coap_add_token(response, request->hdr->token_length, request->hdr->token)) {
+               if (!coap_add_token(response, request->transport_hdr->udp.token_length, request->transport_hdr->udp.token)) {
                        debug("cannot add token to error response\n");
                        coap_delete_pdu(response);
                        return NULL;
@@ -1218,8 +1228,7 @@ static inline size_t get_wkc_len(coap_context_t *context, coap_opt_t *query_filt
        unsigned char buf[1];
        size_t len = 0;
 
-       if (print_wellknown(context, buf, &len, UINT_MAX, query_filter)
-               & COAP_PRINT_STATUS_ERROR) {
+       if (print_wellknown(context, buf, &len, UINT_MAX, query_filter) & COAP_PRINT_STATUS_ERROR) {
                warn("cannot determine length of /.well-known/core\n");
                return 0;
        }
@@ -1243,13 +1252,15 @@ coap_pdu_t *wellknown_response(coap_context_t *context, coap_pdu_t *request)
        coap_opt_t *query_filter;
        size_t offset = 0;
 
-       resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, COAP_RESPONSE_CODE(205), request->hdr->id, COAP_MAX_PDU_SIZE);
+       /* 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);
        if (!resp) {
                debug("wellknown_response: cannot create PDU\n");
                return NULL;
        }
-
-       if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) {
+       /* TODO : Considering TCP Case */
+       if (!coap_add_token(resp, request->transport_hdr->udp.token_length, request->transport_hdr->udp.token)) {
                debug("wellknown_response: cannot add token\n");
                goto error;
        }
@@ -1260,8 +1271,9 @@ coap_pdu_t *wellknown_response(coap_context_t *context, coap_pdu_t *request)
        /* check whether the request contains the Block2 option */
        if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) {
                offset = block.num << (block.szx + 4);
-               if (block.szx > 6) {    /* invalid, MUST lead to 4.00 Bad Request */
-                       resp->hdr->code = COAP_RESPONSE_CODE(400);
+               if (block.szx > 6) {
+                       /* invalid, MUST lead to 4.00 Bad Request */
+                       resp->transport_hdr->udp.code = COAP_RESPONSE_CODE(400);
                        return resp;
                } else if (block.szx > COAP_MAX_BLOCK_SZX) {
                        block.szx = COAP_MAX_BLOCK_SZX;
@@ -1283,7 +1295,8 @@ coap_pdu_t *wellknown_response(coap_context_t *context, coap_pdu_t *request)
        /* Add Content-Format. As we have checked for available storage,
         * nothing should go wrong here. */
        assert(coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1);
-       coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
+       coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT,
+               coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
 
        /* check if Block2 option is required even if not requested */
        if (!need_block2 && (resp->max_size - (size_t) resp->length < wkc_len)) {
@@ -1333,13 +1346,15 @@ coap_pdu_t *wellknown_response(coap_context_t *context, coap_pdu_t *request)
 
 error:
        /* set error code 5.03 and remove all options and data from response */
-       resp->hdr->code = COAP_RESPONSE_CODE(503);
-       resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length;
+       /* 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;
        return resp;
 }
 
-#define WANT_WKC(Pdu,Key)                                      \
-  (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key))
+/* TODO : Considering TCP Case */
+#define WANT_WKC(Pdu,Key)                   \
+       (((Pdu)->transport_hdr->udp.code == COAP_REQUEST_GET) && is_wkc(Key))
 
 void handle_request(coap_context_t *context, coap_queue_t *node)
 {
@@ -1360,14 +1375,17 @@ void handle_request(coap_context_t *context, coap_queue_t *node)
                 * be the well-known URI. In that case, we generate a default
                 * response, otherwise, we return 4.04 */
 
-               switch (node->pdu->hdr->code) {
+               switch (node->pdu->transport_hdr->udp.code) {
 
                case COAP_REQUEST_GET:
-                       if (is_wkc(key)) {      /* GET request for .well-known/core */
+                       if (is_wkc(key)) {
+                               /* GET request for .well-known/core */
                                info("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 */
+                       } 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);
@@ -1391,23 +1409,27 @@ 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->hdr->code - 1 < sizeof(resource->handler) / sizeof(coap_method_handler_t)) {
-               h = resource->handler[node->pdu->hdr->code - 1];
+       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 (h) {
                debug("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->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, 0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE);
+               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);
 
                /* Implementation detail: coap_add_token() immediately returns 0
                   if response == NULL */
-               if (coap_add_token(response, node->pdu->hdr->token_length, node->pdu->hdr->token)) {
-                       str token = { node->pdu->hdr->token_length, node->pdu->hdr->token };
+               if (coap_add_token(response, node->pdu->transport_hdr->udp.token_length, node->pdu->transport_hdr->udp.token)) {
+                       str token = { node->pdu->transport_hdr->udp.token_length, node->pdu->transport_hdr->udp.token };
 
                        h(context, resource, &node->remote, node->pdu, &token, response);
-                       if (response->hdr->type != COAP_MESSAGE_NON || (response->hdr->code >= 64 && !coap_is_mcast(&node->local))) {
+
+                       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->hdr->id);
+                                       debug("cannot send response for message %d\n", node->pdu->transport_hdr->udp.id);
                                }
                        }
 
@@ -1423,8 +1445,7 @@ void handle_request(coap_context_t *context, coap_queue_t *node)
                        response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter);
                }
 
-               if (!response || (coap_send(context, &node->remote, response)
-                                                 == COAP_INVALID_TID)) {
+               if (!response || (coap_send(context, &node->remote, response) == COAP_INVALID_TID)) {
                        debug("cannot send response for transaction %u\n", node->id);
                }
                coap_delete_pdu(response);
@@ -1472,8 +1493,8 @@ static void coap_handle_rst(coap_context_t *context, const coap_queue_t *sent)
        /* remove observer for this resource, if any
         * get token from sent and try to find a matching resource. Uh!
         */
-
-       COAP_SET_STR(&token, sent->pdu->hdr->token_length, sent->pdu->hdr->token);
+       /* TODO : Considering TCP Case */
+       COAP_SET_STR(&token, sent->pdu->transport_hdr->udp.token_length, sent->pdu->transport_hdr->udp.token);
 
 #ifndef WITH_CONTIKI
 #ifdef COAP_RESOURCES_NOHASH
@@ -1515,25 +1536,28 @@ void coap_dispatch(coap_context_t *context)
                context->recvqueue = context->recvqueue->next;
                rcvd->next = NULL;
 
-               if (rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION) {
-                       debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version);
+               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;
                }
 
-               switch (rcvd->pdu->hdr->type) {
+               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 (rcvd->pdu->hdr->code == 0) {
+                       if (rcvd->pdu->transport_hdr->udp.code == 0) {
                                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->hdr->code) == 2) {
-                               const str token = { sent->pdu->hdr->token_length, sent->pdu->hdr->token };
+                       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
+                                                                 };
+
                                coap_touch_observer(context, &sent->remote, &token);
                        }
                        break;
@@ -1543,7 +1567,7 @@ void coap_dispatch(coap_context_t *context)
                         * not only the transaction but also the subscriptions we might
                         * have. */
 
-                       coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->hdr->id));
+                       coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->transport_hdr->udp.id));
 
                        /* find transaction in sendqueue to stop retransmission */
                        coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
@@ -1569,8 +1593,7 @@ void coap_dispatch(coap_context_t *context)
                                if (!response) {
                                        warn("coap_dispatch: cannot create error reponse\n");
                                } else {
-                                       if (coap_send(context, &rcvd->remote, response)
-                                               == COAP_INVALID_TID) {
+                                       if (coap_send(context, &rcvd->remote, response) == COAP_INVALID_TID) {
                                                warn("coap_dispatch: error sending reponse\n");
                                        }
                                        coap_delete_pdu(response);
@@ -1584,15 +1607,13 @@ void coap_dispatch(coap_context_t *context)
                /* 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->hdr)) {
+                       if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->transport_hdr->udp)) {
                                handle_request(context, rcvd);
-                       } else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) {
+                       } else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->transport_hdr->udp)) {
                                handle_response(context, sent, rcvd);
                        } else {
                                debug("dropped message with invalid code\n");
-                               if (coap_send_message_type(context, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST) == COAP_INVALID_TID) {
-                                       debug("failed to send RST message\n");
-                               }
+                               coap_send_message_type(context, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST);
                        }
                }
 
index 6c36de7..88d97b9 100644 (file)
 #include <apps/netutils/libcoap/option.h>
 #include <apps/netutils/libcoap/debug.h>
 
-coap_opt_t *options_start(coap_pdu_t *pdu)
+coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_t transport)
 {
-
-       if (pdu && pdu->hdr && (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *)pdu->hdr + pdu->length)) {
-
-               coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
-               return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
-
+       if (pdu && pdu->hdr) {
+               if (COAP_UDP == transport &&
+                       (pdu->transport_hdr->udp.token + pdu->transport_hdr->udp.token_length < (unsigned char *)pdu->hdr + pdu->length)) {
+                       coap_opt_t *opt = pdu->transport_hdr->udp.token + pdu->transport_hdr->udp.token_length;
+                       return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+               }
+#ifdef WITH_TCP
+               else if (COAP_TCP == transport &&
+                               (pdu->transport_hdr->tcp.token + ((pdu->transport_hdr->tcp.header_data[0]) & 0x0f)
+                                                                                  < (unsigned char *)pdu->hdr + pdu->length)) {
+                       coap_opt_t *opt = pdu->transport_hdr->tcp.token + ((pdu->transport_hdr->tcp.header_data[0]) & 0x0f);
+                       return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+               }
+#endif
+               return NULL;
        } else {
                return NULL;
        }
@@ -116,22 +125,65 @@ size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *resul
 
 coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
 {
+       return coap_option_iterator_init2(pdu, oi, filter, COAP_UDP);
+}
+
+coap_opt_iterator_t *coap_option_iterator_init2(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter, coap_transport_t transport)
+{
        assert(pdu);
        assert(pdu->hdr);
        assert(oi);
 
        memset(oi, 0, sizeof(coap_opt_iterator_t));
 
-       oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t)
-                                         + pdu->hdr->token_length;
-       if ((unsigned char *)pdu->hdr + pdu->length <= oi->next_option) {
-               oi->bad = 1;
-               return NULL;
+       unsigned int token_length;
+       unsigned int headerSize;
+
+       switch (transport) {
+#ifdef WITH_TCP
+       case COAP_TCP:
+               token_length = (pdu->transport_hdr->tcp.header_data[0]) & 0x0f;
+               headerSize = COAP_TCP_HEADER_NO_FIELD;
+               break;
+       case COAP_TCP_8BIT:
+               token_length = (pdu->transport_hdr->tcp_8bit.header_data[0]) & 0x0f;
+               headerSize = COAP_TCP_HEADER_8_BIT;
+               break;
+       case COAP_TCP_16BIT:
+               token_length = (pdu->transport_hdr->tcp_16bit.header_data[0]) & 0x0f;
+               headerSize = COAP_TCP_HEADER_16_BIT;
+               break;
+       case COAP_TCP_32BIT:
+               token_length = pdu->transport_hdr->tcp_32bit.header_data[0] & 0x0f;
+               headerSize = COAP_TCP_HEADER_32_BIT;
+               break;
+#endif
+       default:
+               token_length = pdu->transport_hdr->udp.token_length;
+               headerSize = sizeof(pdu->transport_hdr->udp);
+               break;
        }
 
-       assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
+       oi->next_option = (unsigned char *)pdu->hdr + headerSize + token_length;
+
+       if (COAP_UDP == transport) {
+               if ((unsigned char *)&(pdu->transport_hdr->udp) + pdu->length <= oi->next_option) {
+                       oi->bad = 1;
+                       return NULL;
+               }
+       }
+#ifdef WITH_TCP
+       else {
+               if ((unsigned char *)&(pdu->transport_hdr->tcp) + pdu->length <= oi->next_option) {
+                       oi->bad = 1;
+                       return NULL;
+               }
+       }
+#endif
+
+       assert((headerSize + token_length) <= pdu->length);
 
-       oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
+       oi->length = pdu->length - (headerSize + token_length);
 
        if (filter) {
                memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
@@ -326,7 +378,7 @@ size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta,
 
        assert(opt);
 
-       if (maxlen == 0) {              /* need at least one byte */
+       if (maxlen == 0) {                      /* need at least one byte */
                return 0;
        }
 
@@ -395,7 +447,7 @@ size_t coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, con
                return 0;
        }
 
-       if (val) {                              /* better be safe here */
+       if (val) {                                      /* better be safe here */
                memcpy(opt, val, length);
        }
 
index 8241dfc..2b14ef2 100644 (file)
 #ifdef WITH_CONTIKI
 #include "memb.h"
 
+#ifndef WITH_TCP
 typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
 
 MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
+#endif
 
 void coap_pdu_resources_init()
 {
@@ -41,15 +43,30 @@ void coap_pdu_resources_init()
 
 void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
 {
+       coap_pdu_clear2(pdu, size, COAP_UDP, 0);
+}
+
+void coap_pdu_clear2(coap_pdu_t *pdu, size_t size, coap_transport_t transport, unsigned int length)
+{
        assert(pdu);
 
        memset(pdu, 0, sizeof(coap_pdu_t) + size);
        pdu->max_size = size;
        pdu->hdr = (coap_hdr_t *)((unsigned char *)pdu + sizeof(coap_pdu_t));
-       pdu->hdr->version = COAP_DEFAULT_VERSION;
 
-       /* data is NULL unless explicitly set by coap_add_data() */
-       pdu->length = sizeof(coap_hdr_t);
+       if (COAP_UDP == transport) {
+               pdu->transport_hdr->udp.version = COAP_DEFAULT_VERSION;
+               /* data is NULL unless explicitly set by coap_add_data() */
+               pdu->length = sizeof(pdu->transport_hdr->udp);
+       }
+#ifdef WITH_TCP
+       else {
+               /* data is NULL unless explicitly set by coap_add_data() */
+               pdu->length = length;
+       }
+#else
+       (void)length;
+#endif
 }
 
 #ifdef WITH_LWIP
@@ -79,21 +96,50 @@ coap_pdu_t *coap_pdu_from_pbuf(struct pbuf *pbuf)
 
 coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
 {
+       return coap_pdu_init2(type, code, id, size, COAP_UDP);
+}
+
+coap_pdu_t *coap_pdu_init2(unsigned char type, unsigned char code, unsigned short id, size_t size, coap_transport_t transport)
+{
        coap_pdu_t *pdu;
 #ifdef WITH_LWIP
        struct pbuf *p;
 #endif
 
-       pdu = NULL;                                     /* to prevent stooped compilng due to warning */
+       unsigned int length = 0;
+       switch (transport) {
+       case COAP_UDP:
+               length = sizeof(pdu->transport_hdr->udp);
+               break;
+#ifdef WITH_TCP
+       case COAP_TCP:
+               length = COAP_TCP_HEADER_NO_FIELD;
+               break;
+       case COAP_TCP_8BIT:
+               length = COAP_TCP_HEADER_8_BIT;
+               break;
+       case COAP_TCP_16BIT:
+               length = COAP_TCP_HEADER_16_BIT;
+               break;
+       case COAP_TCP_32BIT:
+               length = COAP_TCP_HEADER_32_BIT;
+               break;
+#endif
+       default:
+               debug("it has wrong type\n");
+       }
+
+#ifndef WITH_TCP
        assert(size <= COAP_MAX_PDU_SIZE);
        /* Size must be large enough to fit the header. */
-       if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE) {
+       if (size < length || size > COAP_MAX_PDU_SIZE) {
                return NULL;
        }
+#endif
 
        /* size must be large enough for hdr */
 #ifdef WITH_POSIX
-       pdu = coap_malloc(sizeof(coap_pdu_t) + size);
+       pdu = (coap_pdu_t *) coap_malloc(sizeof(coap_pdu_t) + size);
 #endif
 #ifdef WITH_CONTIKI
        pdu = (coap_pdu_t *) memb_alloc(&pdu_storage);
@@ -111,10 +157,36 @@ coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short
        }
 #endif
        if (pdu) {
-               coap_pdu_clear(pdu, size);
-               pdu->hdr->id = id;
-               pdu->hdr->type = type;
-               pdu->hdr->code = code;
+               coap_pdu_clear2(pdu, size, transport, length);
+
+               switch (transport) {
+               case COAP_UDP:
+                       pdu->transport_hdr->udp.id = id;
+                       pdu->transport_hdr->udp.type = type;
+                       pdu->transport_hdr->udp.code = code;
+                       break;
+#ifdef WITH_TCP
+               case COAP_TCP:
+                       pdu->transport_hdr->tcp.header_data[0] = 0;
+                       pdu->transport_hdr->tcp.header_data[1] = code;
+                       break;
+               case COAP_TCP_8BIT:
+                       pdu->transport_hdr->tcp_8bit.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_8_BIT << 4;
+                       pdu->transport_hdr->tcp_8bit.header_data[2] = code;
+                       break;
+               case COAP_TCP_16BIT:
+                       pdu->transport_hdr->tcp_16bit.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_16_BIT << 4;
+                       pdu->transport_hdr->tcp_16bit.header_data[3] = code;
+                       break;
+               case COAP_TCP_32BIT:
+                       pdu->transport_hdr->tcp_32bit.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_32_BIT << 4;
+                       pdu->transport_hdr->tcp_32bit.header_data[5] = code;
+                       break;
+#endif
+               default:
+                       debug("it has wrong type\n");
+               }
+
 #ifdef WITH_LWIP
                pdu->pbuf = p;
 #endif
@@ -122,14 +194,46 @@ coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short
        return pdu;
 }
 
-coap_pdu_t *coap_new_pdu(void)
+coap_pdu_t *coap_new_pdu()
 {
        coap_pdu_t *pdu;
 
 #ifndef WITH_CONTIKI
        pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
-#else                                                  /* WITH_CONTIKI */
+#else /* WITH_CONTIKI */
        pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+#endif /* WITH_CONTIKI */
+
+#ifndef NDEBUG
+       if (!pdu)
+               coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
+#endif
+       return pdu;
+}
+
+coap_pdu_t *coap_new_pdu2(coap_transport_t transport, unsigned int size)
+{
+#ifndef WITH_TCP
+       (void)size;
+#endif
+       coap_pdu_t *pdu;
+
+#ifndef WITH_CONTIKI
+       pdu = coap_pdu_init2(0, 0, ntohs(COAP_INVALID_TID),
+#ifndef WITH_TCP
+                                                COAP_MAX_PDU_SIZE,
+#else
+                                                size,
+#endif
+                                                transport);
+#else                                                  /* WITH_CONTIKI */
+       pdu = coap_pdu_init2(0, 0, uip_ntohs(COAP_INVALID_TID),
+#ifndef WITH_TCP
+                                                COAP_MAX_PDU_SIZE,
+#else
+                                                size,
+#endif
+                                                transport);
 #endif                                                 /* WITH_CONTIKI */
 
 #ifndef NDEBUG
@@ -155,28 +259,370 @@ void coap_delete_pdu(coap_pdu_t *pdu)
 #endif
 }
 
+#ifdef WITH_TCP
+size_t coap_get_total_message_length(const unsigned char *data, size_t size)
+{
+       if (!data || !size) {
+               debug("received data length is null\n");
+               return 0;
+       }
+
+       coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)data)[0] >> 4);
+       size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)data,
+                                                  transport);
+       size_t headerLen = coap_get_tcp_header_length((unsigned char *)data);
+
+       return headerLen + optPaylaodLen;
+}
+
+coap_transport_t coap_get_tcp_header_type_from_size(unsigned int size)
+{
+       if (size < COAP_TCP_LENGTH_FIELD_8_BIT) {
+               return COAP_TCP;
+       } else if (size < COAP_TCP_LENGTH_FIELD_16_BIT) {
+               return COAP_TCP_8BIT;
+       } else if (size < COAP_TCP_LENGTH_FIELD_32_BIT) {
+               return COAP_TCP_16BIT;
+       } else {
+               return COAP_TCP_32BIT;
+       }
+}
+
+coap_transport_t coap_get_tcp_header_type_from_initbyte(unsigned int length)
+{
+       coap_transport_t type;
+       switch (length) {
+       case COAP_TCP_LENGTH_FIELD_NUM_8_BIT:
+               type = COAP_TCP_8BIT;
+               break;
+       case COAP_TCP_LENGTH_FIELD_NUM_16_BIT:
+               type = COAP_TCP_16BIT;
+               break;
+       case COAP_TCP_LENGTH_FIELD_NUM_32_BIT:
+               type = COAP_TCP_32BIT;
+               break;
+       default:
+               type = COAP_TCP;
+       }
+       return type;
+}
+
+void coap_add_length(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int length)
+{
+       assert(pdu);
+
+       switch (transport) {
+       case COAP_TCP:
+               pdu->transport_hdr->tcp.header_data[0] = length << 4;
+               break;
+       case COAP_TCP_8BIT:
+               if (length > COAP_TCP_LENGTH_FIELD_8_BIT) {
+                       pdu->transport_hdr->tcp_8bit.header_data[1] = length - COAP_TCP_LENGTH_FIELD_8_BIT;
+               }
+               break;
+       case COAP_TCP_16BIT:
+               if (length > COAP_TCP_LENGTH_FIELD_16_BIT) {
+                       unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_16_BIT;
+                       pdu->transport_hdr->tcp_16bit.header_data[1] = (total_length >> 8) & 0x0000ff;
+                       pdu->transport_hdr->tcp_16bit.header_data[2] = total_length & 0x000000ff;
+               }
+               break;
+       case COAP_TCP_32BIT:
+               if (length > COAP_TCP_LENGTH_FIELD_32_BIT) {
+                       unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_32_BIT;
+                       pdu->transport_hdr->tcp_32bit.header_data[1] = total_length >> 24;
+                       pdu->transport_hdr->tcp_32bit.header_data[2] = (total_length >> 16) & 0x00ff;
+                       pdu->transport_hdr->tcp_32bit.header_data[3] = (total_length >> 8) & 0x0000ff;
+                       pdu->transport_hdr->tcp_32bit.header_data[4] = total_length & 0x000000ff;
+               }
+               break;
+       default:
+               debug("it has wrong type\n");
+       }
+}
+
+unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_t transport)
+{
+       assert(header);
+
+       unsigned int length = 0;
+       unsigned int length_field_data = 0;
+       switch (transport) {
+       case COAP_TCP:
+               length = header[0] >> 4;
+               break;
+       case COAP_TCP_8BIT:
+               length = header[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
+               break;
+       case COAP_TCP_16BIT:
+               length_field_data = (header[1] << 8 | header[2]);
+               length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+               break;
+       case COAP_TCP_32BIT:
+               length_field_data = header[1] << 24 | header[2] << 16 | header[3] << 8 | header[4];
+               length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+               break;
+       default:
+               debug("it has wrong type\n");
+       }
+
+       return length;
+}
+
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_t transport)
+{
+       assert(pdu);
+
+       unsigned int length = 0;
+       unsigned int length_field_data = 0;
+       switch (transport) {
+       case COAP_TCP:
+               length = pdu->transport_hdr->tcp.header_data[0] >> 4;
+               break;
+       case COAP_TCP_8BIT:
+               length = pdu->transport_hdr->tcp_8bit.header_data[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
+               break;
+       case COAP_TCP_16BIT:
+               length_field_data = pdu->transport_hdr->tcp_16bit.header_data[1] << 8 | pdu->transport_hdr->tcp_16bit.header_data[2];
+               length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+               break;
+       case COAP_TCP_32BIT:
+               length_field_data = pdu->transport_hdr->tcp_32bit.header_data[1] << 24 | pdu->transport_hdr->tcp_32bit.header_data[2] << 16 | pdu->transport_hdr->tcp_32bit.header_data[3] << 8 | pdu->transport_hdr->tcp_32bit.header_data[4];
+               length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+               break;
+       default:
+               debug("it has wrong type\n");
+       }
+
+       return length;
+}
+
+unsigned int coap_get_tcp_header_length(unsigned char *data)
+{
+       assert(data);
+
+       unsigned int tokenLength = data[0] & 0x0f;
+       coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(data[0] >> 4);
+       unsigned int length = 0;
+
+       length = coap_get_tcp_header_length_for_transport(transport) + tokenLength;
+       return length;
+}
+
+unsigned int coap_get_tcp_header_length_for_transport(coap_transport_t transport)
+{
+       unsigned int length = 0;
+       switch (transport) {
+       case COAP_TCP:
+               length = COAP_TCP_HEADER_NO_FIELD;
+               break;
+       case COAP_TCP_8BIT:             /* len(4bit) + TKL(4bit) + Len+bytes(1byte) + Code(1byte) */
+               length = COAP_TCP_HEADER_8_BIT;
+               break;
+       case COAP_TCP_16BIT:            /* len(4bit) + TKL(4bit) + Len+bytes(2byte) + Code(1byte) */
+               length = COAP_TCP_HEADER_16_BIT;
+               break;
+       case COAP_TCP_32BIT:            /* len(4bit) + TKL(4bit) + Len+bytes(4byte) + Code(1byte) */
+               length = COAP_TCP_HEADER_32_BIT;
+               break;
+       default:
+               debug("it has wrong type\n");
+       }
+
+       return length;
+}
+
+size_t coap_get_opt_header_length(unsigned short key, size_t length)
+{
+       size_t headerLength = 0;
+
+       unsigned short optDeltaLength = 0;
+       if (COAP_OPTION_FIELD_8_BIT >= key) {
+               optDeltaLength = 0;
+       } else if (COAP_OPTION_FIELD_8_BIT < key && COAP_OPTION_FIELD_16_BIT >= key) {
+               optDeltaLength = 1;
+       } else {
+               optDeltaLength = 2;
+       }
+
+       size_t optLength = 0;
+       if (COAP_OPTION_FIELD_8_BIT >= length) {
+               optLength = 0;
+       } else if (COAP_OPTION_FIELD_8_BIT < length && COAP_OPTION_FIELD_16_BIT >= length) {
+               optLength = 1;
+       } else if (COAP_OPTION_FIELD_16_BIT < length && COAP_OPTION_FIELD_32_BIT >= length) {
+               optLength = 2;
+       } else {
+               printf("Error : Reserved for the Payload marker for length");
+               return 0;
+       }
+
+       headerLength = length + optDeltaLength + optLength + 1;
+
+       return headerLength;
+}
+
+#endif
+
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int code)
+{
+       assert(pdu);
+
+       switch (transport) {
+       case COAP_UDP:
+               pdu->transport_hdr->udp.code = COAP_RESPONSE_CODE(code);
+               break;
+#ifdef WITH_TCP
+       case COAP_TCP:
+               pdu->transport_hdr->tcp.header_data[1] = COAP_RESPONSE_CODE(code);
+               break;
+       case COAP_TCP_8BIT:
+               pdu->transport_hdr->tcp_8bit.header_data[2] = COAP_RESPONSE_CODE(code);
+               break;
+       case COAP_TCP_16BIT:
+               pdu->transport_hdr->tcp_16bit.header_data[3] = COAP_RESPONSE_CODE(code);
+               break;
+       case COAP_TCP_32BIT:
+               pdu->transport_hdr->tcp_32bit.header_data[5] = COAP_RESPONSE_CODE(code);
+               break;
+#endif
+       default:
+               debug("it has wrong type\n");
+       }
+}
+
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_t transport)
+{
+       assert(pdu);
+
+       unsigned int code = 0;
+       switch (transport) {
+       case COAP_UDP:
+               code = pdu->transport_hdr->udp.code;
+               break;
+#ifdef WITH_TCP
+       case COAP_TCP:
+               code = pdu->transport_hdr->tcp.header_data[1];
+               break;
+       case COAP_TCP_8BIT:
+               code = pdu->transport_hdr->tcp_8bit.header_data[2];
+               break;
+       case COAP_TCP_16BIT:
+               code = pdu->transport_hdr->tcp_16bit.header_data[3];
+               break;
+       case COAP_TCP_32BIT:
+               code = pdu->transport_hdr->tcp_32bit.header_data[5];
+               break;
+#endif
+       default:
+               debug("it has wrong type\n");
+       }
+       return code;
+}
+
 int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
 {
+       return coap_add_token2(pdu, len, data, COAP_UDP);
+}
+
+int coap_add_token2(coap_pdu_t *pdu, size_t len, const unsigned char *data, coap_transport_t transport)
+{
        const size_t HEADERLENGTH = len + 4;
        /* must allow for pdu == NULL as callers may rely on this */
        if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH) {
                return 0;
        }
 
-       pdu->hdr->token_length = len;
+       unsigned char *token = NULL;
+       switch (transport) {
+       case COAP_UDP:
+               pdu->transport_hdr->udp.token_length = len;
+               token = pdu->transport_hdr->udp.token;
+               pdu->length = HEADERLENGTH;
+               break;
+#ifdef WITH_TCP
+       case COAP_TCP:
+               pdu->transport_hdr->tcp.header_data[0] = pdu->transport_hdr->tcp.header_data[0] | len;
+               token = pdu->transport_hdr->tcp.token;
+               pdu->length = len + COAP_TCP_HEADER_NO_FIELD;
+               break;
+       case COAP_TCP_8BIT:
+               pdu->transport_hdr->tcp_8bit.header_data[0] = pdu->transport_hdr->tcp_8bit.header_data[0] | len;
+               token = pdu->transport_hdr->tcp_8bit.token;
+               pdu->length = len + COAP_TCP_HEADER_8_BIT;
+               break;
+       case COAP_TCP_16BIT:
+               pdu->transport_hdr->tcp_16bit.header_data[0] = pdu->transport_hdr->tcp_16bit.header_data[0] | len;
+               token = pdu->transport_hdr->tcp_16bit.token;
+               pdu->length = len + COAP_TCP_HEADER_16_BIT;
+               break;
+       case COAP_TCP_32BIT:
+               pdu->transport_hdr->tcp_32bit.header_data[0] = pdu->transport_hdr->tcp_32bit.header_data[0] | len;
+               token = pdu->transport_hdr->tcp_32bit.token;
+               pdu->length = len + COAP_TCP_HEADER_32_BIT;
+               break;
+#endif
+       default:
+               debug("it has wrong type\n");
+       }
+
        if (len) {
-               memcpy(pdu->hdr->token, data, len);
+               memcpy(token, data, len);
        }
+
        pdu->max_delta = 0;
-       pdu->length = HEADERLENGTH;
        pdu->data = NULL;
 
        return 1;
 }
 
-/** @FIXME de-duplicate code with coap_add_option_later */
+void coap_get_token(const coap_hdr_t *pdu_hdr, unsigned char **token, unsigned int *token_length)
+{
+       coap_get_token2((const coap_hdr_transport_t *)pdu_hdr, COAP_UDP, token, token_length);
+}
+
+void coap_get_token2(const coap_hdr_transport_t *pdu_hdr, coap_transport_t transport, unsigned char **token, unsigned int *token_length)
+{
+       assert(pdu_hdr);
+       assert(token);
+       assert(token_length);
+
+       switch (transport) {
+       case COAP_UDP:
+               *token_length = pdu_hdr->udp.token_length;
+               *token = (unsigned char *)pdu_hdr->udp.token;
+               break;
+#ifdef WITH_TCP
+       case COAP_TCP:
+               *token_length = (pdu_hdr->tcp.header_data[0]) & 0x0f;
+               *token = (unsigned char *)pdu_hdr->tcp.token;
+               break;
+       case COAP_TCP_8BIT:
+               *token_length = (pdu_hdr->tcp_8bit.header_data[0]) & 0x0f;
+               *token = (unsigned char *)pdu_hdr->tcp_8bit.token;
+               break;
+       case COAP_TCP_16BIT:
+               *token_length = (pdu_hdr->tcp_16bit.header_data[0]) & 0x0f;
+               *token = (unsigned char *)pdu_hdr->tcp_16bit.token;
+               break;
+       case COAP_TCP_32BIT:
+               *token_length = (pdu_hdr->tcp_32bit.header_data[0]) & 0x0f;
+               *token = (unsigned char *)pdu_hdr->tcp_32bit.token;
+               break;
+#endif
+       default:
+               debug("it has wrong type\n");
+       }
+}
+
 size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data)
 {
+       return coap_add_option2(pdu, type, len, data, COAP_UDP);
+}
+
+/** @FIXME de-duplicate code with coap_add_option_later */
+size_t coap_add_option2(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data, coap_transport_t transport)
+{
        size_t optsize;
        coap_opt_t *opt;
 
@@ -184,17 +630,35 @@ size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, c
        pdu->data = NULL;
 
        if (type < pdu->max_delta) {
-               warn("coap_add_option: options are not in correct order\n");
+               warn("coap_add_option2: options are not in correct order\n");
                return 0;
        }
 
-       opt = (unsigned char *)pdu->hdr + pdu->length;
+       switch (transport) {
+#ifdef WITH_TCP
+       case COAP_TCP:
+               opt = (unsigned char *)&(pdu->transport_hdr->tcp) + pdu->length;
+               break;
+       case COAP_TCP_8BIT:
+               opt = (unsigned char *)&(pdu->transport_hdr->tcp_8bit) + pdu->length;
+               break;
+       case COAP_TCP_16BIT:
+               opt = (unsigned char *)&(pdu->transport_hdr->tcp_16bit) + pdu->length;
+               break;
+       case COAP_TCP_32BIT:
+               opt = (unsigned char *)&(pdu->transport_hdr->tcp_32bit) + pdu->length;
+               break;
+#endif
+       default:
+               opt = (unsigned char *)&(pdu->transport_hdr->udp) + pdu->length;
+               break;
+       }
 
        /* encode option and check length */
        optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
 
        if (!optsize) {
-               warn("coap_add_option: cannot add option\n");
+               warn("coap_add_option2: cannot add option\n");
                /* error */
                return 0;
        } else {
@@ -205,7 +669,7 @@ size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, c
        return optsize;
 }
 
-/** @FIXME de-duplicate code with coap_add_option */
+/** @FIXME de-duplicate code with coap_add_option2 */
 unsigned char *coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
 {
        size_t optsize;
@@ -326,16 +790,15 @@ char *coap_response_phrase(unsigned char code)
  * returns the number of bytes opt has been advanced or @c 0
  * on error.
  */
-static size_t next_option_safe(coap_opt_t **optp, size_t *length)
+static size_t next_option_safe(coap_opt_t **optp, size_t *length, coap_option_t *option)
 {
-       coap_option_t option;
+       //coap_option_t option;
        size_t optsize;
 
        assert(optp);
        assert(*optp);
        assert(length);
-
-       optsize = coap_opt_parse(*optp, *length, &option);
+       optsize = coap_opt_parse(*optp, *length, option);
        if (optsize) {
                assert(optsize <= *length);
 
@@ -348,58 +811,140 @@ static size_t next_option_safe(coap_opt_t **optp, size_t *length)
 
 int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
 {
-       coap_opt_t *opt;
+       return coap_pdu_parse2(data, length, pdu, COAP_UDP);
+}
 
+int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu, coap_transport_t transport)
+{
        assert(data);
        assert(pdu);
 
        if (pdu->max_size < length) {
                debug("insufficient space to store parsed PDU\n");
-               return 0;
+               printf("[COAP] insufficient space to store parsed PDU\n");
+               return -1;
+       }
+
+       unsigned int headerSize = 0;
+
+       if (COAP_UDP == transport) {
+               headerSize = sizeof(pdu->transport_hdr->udp);
+       }
+#ifdef WITH_TCP
+       else {
+               headerSize = coap_get_tcp_header_length_for_transport(transport);
        }
+#endif
 
-       if (length < sizeof(coap_hdr_t)) {
+       if (length < headerSize) {
                debug("discarded invalid PDU\n");
        }
 
-       pdu->hdr->version = data[0] >> 6;
-       pdu->hdr->type = (data[0] >> 4) & 0x03;
-       pdu->hdr->token_length = data[0] & 0x0f;
-       pdu->hdr->code = data[1];
-       pdu->data = NULL;
+       coap_opt_t *opt = NULL;
+       unsigned int tokenLength = 0;
+#ifdef WITH_TCP
+       size_t i;
+
+       switch (transport) {
+       case COAP_UDP:
+               break;
+       case COAP_TCP:
+               for (i = 0; i < headerSize; i++) {
+                       pdu->transport_hdr->tcp.header_data[i] = data[i];
+               }
 
-       /* sanity checks */
-       if (pdu->hdr->code == 0) {
-               if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length) {
-                       debug("coap_pdu_parse: empty message is not empty\n");
-                       goto discard;
+               tokenLength = data[0] & 0x0f;
+               opt = (unsigned char *)(&(pdu->transport_hdr->tcp) + 1) + tokenLength;
+               break;
+       case COAP_TCP_8BIT:
+               for (i = 0; i < headerSize; i++) {
+                       pdu->transport_hdr->tcp_8bit.header_data[i] = data[i];
                }
-       }
 
-       if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8) {
-               debug("coap_pdu_parse: invalid Token\n");
-               goto discard;
-       }
+               tokenLength = data[0] & 0x0f;
+               opt = (unsigned char *)(&(pdu->transport_hdr->tcp_8bit))
+                         + tokenLength + COAP_TCP_HEADER_8_BIT;
+               break;
+       case COAP_TCP_16BIT:
+               for (i = 0; i < headerSize; i++) {
+                       pdu->transport_hdr->tcp_16bit.header_data[i] = data[i];
+               }
 
-       /* Copy message id in network byte order, so we can easily write the
-        * response back to the network. */
-       memcpy(&pdu->hdr->id, data + 2, 2);
+               tokenLength = data[0] & 0x0f;
+               opt = (unsigned char *)(&(pdu->transport_hdr->tcp_16bit) + 1) + tokenLength;
+               break;
+       case COAP_TCP_32BIT:
+               for (i = 0; i < headerSize; i++) {
+                       pdu->transport_hdr->tcp_32bit.header_data[i] = data[i];
+               }
 
-       /* append data (including the Token) to pdu structure */
-       memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
+               tokenLength = data[0] & 0x0f;
+               opt = ((unsigned char *)&(pdu->transport_hdr->tcp_32bit)) + headerSize + tokenLength;
+               break;
+       default:
+               printf("it has wrong type\n");
+       }
+#endif
        pdu->length = length;
 
-       /* Finally calculate beginning of data block and thereby check integrity
-        * of the PDU structure. */
+       if (COAP_UDP == transport) {
+               pdu->transport_hdr->udp.version = data[0] >> 6;
+               pdu->transport_hdr->udp.type = (data[0] >> 4) & 0x03;
+               pdu->transport_hdr->udp.token_length = data[0] & 0x0f;
+               pdu->transport_hdr->udp.code = data[1];
+               pdu->data = NULL;
+
+               tokenLength = pdu->transport_hdr->udp.token_length;
+
+               /* sanity checks */
+               if (pdu->transport_hdr->udp.code == 0) {
+                       if (length != headerSize || tokenLength) {
+                               debug("coap_pdu_parse2: empty message is not empty\n");
+                               goto discard;
+                       }
+               }
 
-       /* skip header + token */
-       length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
-       opt = (unsigned char *)(pdu->hdr + 1) + pdu->hdr->token_length;
+               if (length < headerSize + tokenLength || tokenLength > 8) {
+                       debug("coap_pdu_parse2: invalid Token\n");
+                       goto discard;
+               }
 
-       while (length && *opt != COAP_PAYLOAD_START) {
+               memcpy(&pdu->transport_hdr->udp.id, data + 2, 2);
+
+               /* Finally calculate beginning of data block and thereby check integrity
+                * of the PDU structure. */
+
+               /* append data (including the Token) to pdu structure */
+               memcpy(&(pdu->transport_hdr->udp) + 1, data + headerSize, length - headerSize);
 
-               if (!next_option_safe(&opt, (size_t *)&length)) {
-                       debug("coap_pdu_parse: drop\n");
+               /* skip header + token */
+               length -= (tokenLength + headerSize);
+               opt = (unsigned char *)(&(pdu->transport_hdr->udp) + 1) + tokenLength;
+       }
+#ifdef WITH_TCP
+       else {                                  // common for tcp header setting
+               pdu->data = NULL;
+
+               if (length < headerSize + tokenLength || tokenLength > 8) {
+                       debug("coap_pdu_parse2: invalid Token\n");
+                       goto discard;
+               }
+               /* Finally calculate beginning of data block and thereby check integrity
+                * of the PDU structure. */
+
+               /* append data (including the Token) to pdu structure */
+               memcpy(((unsigned char *)pdu->hdr) + headerSize, data + headerSize, length - headerSize);
+
+               /* skip header + token */
+               length -= (tokenLength + headerSize);
+       }
+#endif
+
+       while (length && *opt != COAP_PAYLOAD_START) {
+               coap_option_t option;
+               memset(&option, 0, sizeof(coap_option_t));
+               if (!next_option_safe(&opt, (size_t *)&length, &option)) {
+                       debug("coap_pdu_parse2: drop\n");
                        goto discard;
                }
        }
@@ -411,12 +956,13 @@ int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
                length--;
 
                if (!length) {
-                       debug("coap_pdu_parse: message ending in payload start marker\n");
+                       debug("coap_pdu_parse2: message ending in payload start marker\n");
                        goto discard;
                }
 
                debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length);
                pdu->data = (unsigned char *)opt;
+               //printf("[COAP] pdu - data : %s\n", pdu->data);
        }
 
        return 1;
index 71e90f1..8a890fb 100644 (file)
@@ -726,17 +726,17 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
 
                        token.length = obs->token_length;
                        token.s = obs->token;
-
-                       response->hdr->id = coap_new_message_id(context);
+                       /* TODO : Considering TCP Case */
+                       response->transport_hdr->udp.id = coap_new_message_id(context);
                        if (obs->non && obs->non_cnt < COAP_OBS_MAX_NON) {
-                               response->hdr->type = COAP_MESSAGE_NON;
+                               response->transport_hdr->udp.type = COAP_MESSAGE_NON;
                        } else {
-                               response->hdr->type = COAP_MESSAGE_CON;
+                               response->transport_hdr->udp.type = COAP_MESSAGE_CON;
                        }
                        /* fill with observer-specific data */
                        h(context, r, &obs->subscriber, NULL, &token, response);
 
-                       if (response->hdr->type == COAP_MESSAGE_CON) {
+                       if (response->transport_hdr->udp.type == COAP_MESSAGE_CON) {
                                tid = coap_send_confirmed(context, &obs->subscriber, response);
                                obs->non_cnt = 0;
                        } else {
@@ -744,7 +744,7 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
                                obs->non_cnt++;
                        }
 
-                       if (COAP_INVALID_TID == tid || response->hdr->type != COAP_MESSAGE_CON) {
+                       if (COAP_INVALID_TID == tid || response->transport_hdr->udp.type != COAP_MESSAGE_CON) {
                                coap_delete_pdu(response);
                        }
                        if (COAP_INVALID_TID == tid) {
index 0a5b97a..e1c07db 100644 (file)
@@ -81,6 +81,16 @@ int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri)
                --len;
        }
 
+#ifdef WITH_TCP
+       /* Add to support tcp prefix */
+       q = (unsigned char *)"+tcp";
+       while (len && *q && tolower(*p) == *q) {
+               ++p;
+               ++q;
+               --len;
+       }
+#endif
+
        q = (unsigned char *)"://";
        while (len && *q && tolower(*p) == *q) {
                ++p;