From: Jin-Seong Kim Date: Wed, 5 Jul 2017 07:51:20 +0000 (+0900) Subject: netutils/libcoap : introduce patch to support TCP X-Git-Tag: 1.1_Public_Release~318^2~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=88bb6ddda7edd478191214280c543a031858eca1;p=rtos%2Ftinyara.git netutils/libcoap : introduce patch to support TCP 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 --- diff --git a/apps/examples/libcoap_client/Makefile b/apps/examples/libcoap_client/Makefile index 3c4bbaf..945d845 100644 --- a/apps/examples/libcoap_client/Makefile +++ b/apps/examples/libcoap_client/Makefile @@ -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) diff --git a/apps/examples/libcoap_client/libcoap-client.c b/apps/examples/libcoap_client/libcoap-client.c index 4e74a68..a305f79 100644 --- a/apps/examples/libcoap_client/libcoap-client.c +++ b/apps/examples/libcoap_client/libcoap-client.c @@ -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); } diff --git a/apps/examples/libcoap_server/Makefile b/apps/examples/libcoap_server/Makefile index c140e17..f50064a 100644 --- a/apps/examples/libcoap_server/Makefile +++ b/apps/examples/libcoap_server/Makefile @@ -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) diff --git a/apps/examples/libcoap_server/libcoap-server.c b/apps/examples/libcoap_server/libcoap-server.c index 64e31e0..7a76e3e 100644 --- a/apps/examples/libcoap_server/libcoap-server.c +++ b/apps/examples/libcoap_server/libcoap-server.c @@ -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); diff --git a/apps/include/netutils/libcoap/option.h b/apps/include/netutils/libcoap/option.h index 84a2f90..d29800a 100644 --- a/apps/include/netutils/libcoap/option.h +++ b/apps/include/netutils/libcoap/option.h @@ -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 diff --git a/apps/include/netutils/libcoap/pdu.h b/apps/include/netutils/libcoap/pdu.h index 5a94536..f17fde0 100644 --- a/apps/include/netutils/libcoap/pdu.h +++ b/apps/include/netutils/libcoap/pdu.h @@ -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 diff --git a/apps/netutils/libcoap/Makefile b/apps/netutils/libcoap/Makefile index b7d68ca..780a34e 100644 --- a/apps/netutils/libcoap/Makefile +++ b/apps/netutils/libcoap/Makefile @@ -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) diff --git a/apps/netutils/libcoap/async.c b/apps/netutils/libcoap/async.c index 719d564..ab733f7 100644 --- a/apps/netutils/libcoap/async.c +++ b/apps/netutils/libcoap/async.c @@ -21,6 +21,7 @@ #include #include +/* 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)); diff --git a/apps/netutils/libcoap/debug.c b/apps/netutils/libcoap/debug.c index fbe7192..bdfd6bc 100644 --- a/apps/netutils/libcoap/debug.c +++ b/apps/netutils/libcoap/debug.c @@ -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) { diff --git a/apps/netutils/libcoap/net.c b/apps/netutils/libcoap/net.c index 1bfc400..68d5081 100644 --- a/apps/netutils/libcoap/net.c +++ b/apps/netutils/libcoap/net.c @@ -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); } } diff --git a/apps/netutils/libcoap/option.c b/apps/netutils/libcoap/option.c index 6c36de7..88d97b9 100644 --- a/apps/netutils/libcoap/option.c +++ b/apps/netutils/libcoap/option.c @@ -19,14 +19,23 @@ #include #include -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); } diff --git a/apps/netutils/libcoap/pdu.c b/apps/netutils/libcoap/pdu.c index 8241dfc..2b14ef2 100644 --- a/apps/netutils/libcoap/pdu.c +++ b/apps/netutils/libcoap/pdu.c @@ -27,9 +27,11 @@ #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; diff --git a/apps/netutils/libcoap/resource.c b/apps/netutils/libcoap/resource.c index 71e90f1..8a890fb 100644 --- a/apps/netutils/libcoap/resource.c +++ b/apps/netutils/libcoap/resource.c @@ -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) { diff --git a/apps/netutils/libcoap/uri.c b/apps/netutils/libcoap/uri.c index 0a5b97a..e1c07db 100644 --- a/apps/netutils/libcoap/uri.c +++ b/apps/netutils/libcoap/uri.c @@ -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;