oic; add parsing/encoding TCP like CoAP. Use this with BLE.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/3b8b6928 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/3b8b6928 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/3b8b6928 Branch: refs/heads/develop Commit: 3b8b69283744cdec31c6537bccd21dbaa56cf455 Parents: 524a6ea Author: Marko Kiiskila <ma...@runtime.io> Authored: Fri Dec 2 17:49:22 2016 -0800 Committer: Marko Kiiskila <ma...@runtime.io> Committed: Tue Dec 6 20:45:59 2016 -0800 ---------------------------------------------------------------------- net/oic/src/api/oc_client_api.c | 54 +++++----- net/oic/src/api/oc_ri.c | 23 ++-- net/oic/src/api/oc_server_api.c | 2 +- net/oic/src/messaging/coap/coap.c | 162 +++++++++++++++++++--------- net/oic/src/messaging/coap/coap.h | 4 +- net/oic/src/messaging/coap/constants.h | 72 ++++++++++++- net/oic/src/messaging/coap/engine.c | 14 ++- net/oic/src/messaging/coap/observe.c | 3 +- net/oic/src/messaging/coap/separate.c | 3 +- net/oic/src/port/oc_connectivity.h | 10 ++ 10 files changed, 247 insertions(+), 100 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/api/oc_client_api.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_client_api.c b/net/oic/src/api/oc_client_api.c index 8122f17..0dce249 100644 --- a/net/oic/src/api/oc_client_api.c +++ b/net/oic/src/api/oc_client_api.c @@ -28,33 +28,35 @@ coap_packet_t request[1]; static bool dispatch_coap_request(void) { - int response_length = oc_rep_finalize(); - if (!transaction) { - if (message) { - if (response_length) { - coap_set_payload(request, message->data + COAP_MAX_HEADER_SIZE, - response_length); - coap_set_header_content_format(request, APPLICATION_CBOR); - } - message->length = coap_serialize_message(request, message->data); - coap_send_message(message); - message = 0; - return true; + int response_length = oc_rep_finalize(); + if (!transaction) { + if (message) { + if (response_length) { + coap_set_payload(request, message->data + COAP_MAX_HEADER_SIZE, + response_length); + coap_set_header_content_format(request, APPLICATION_CBOR); + } + message->length = coap_serialize_message(request, message->data, + oc_endpoint_use_tcp(&message->endpoint)); + coap_send_message(message); + message = 0; + return true; + } + } else { + if (response_length) { + coap_set_payload(request, + transaction->message->data + COAP_MAX_HEADER_SIZE, + response_length); + coap_set_header_content_format(request, APPLICATION_CBOR); + } + transaction->message->length = + coap_serialize_message(request, transaction->message->data, + oc_endpoint_use_tcp(&transaction->message->endpoint)); + coap_send_transaction(transaction); + transaction = 0; + return true; } - } else { - if (response_length) { - coap_set_payload(request, - transaction->message->data + COAP_MAX_HEADER_SIZE, - response_length); - coap_set_header_content_format(request, APPLICATION_CBOR); - } - transaction->message->length = - coap_serialize_message(request, transaction->message->data); - coap_send_transaction(transaction); - transaction = 0; - return true; - } - return false; + return false; } static bool http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/api/oc_ri.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_ri.c b/net/oic/src/api/oc_ri.c index da89d11..fae737c 100644 --- a/net/oic/src/api/oc_ri.c +++ b/net/oic/src/api/oc_ri.c @@ -696,17 +696,18 @@ bool oc_ri_send_rst(oc_endpoint_t *endpoint, uint8_t *token, uint8_t token_len, uint16_t mid) { - coap_packet_t rst[1]; - coap_init_message(rst, COAP_TYPE_RST, 0, mid); - coap_set_header_observe(rst, 1); - coap_set_token(rst, token, token_len); - oc_message_t *message = oc_allocate_message(); - if (message) { - message->length = coap_serialize_message(rst, message->data); - coap_send_message(message); - return true; - } - return false; + coap_packet_t rst[1]; + coap_init_message(rst, COAP_TYPE_RST, 0, mid); + coap_set_header_observe(rst, 1); + coap_set_token(rst, token, token_len); + oc_message_t *message = oc_allocate_message(); + if (message) { + message->length = coap_serialize_message(rst, message->data, + oc_endpoint_use_tcp(endpoint)); + coap_send_message(message); + return true; + } + return false; } bool http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/api/oc_server_api.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_server_api.c b/net/oic/src/api/oc_server_api.c index a45cc6f..9cdb4e1 100644 --- a/net/oic/src/api/oc_server_api.c +++ b/net/oic/src/api/oc_server_api.c @@ -260,7 +260,7 @@ oc_send_separate_response(oc_separate_response_t *handle, } t->type = response->type; t->message->length = coap_serialize_message(response, - t->message->data); + t->message->data, oc_endpoint_use_tcp(&cur->endpoint)); coap_send_transaction(t); } coap_separate_clear(handle, cur); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/messaging/coap/coap.c ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/coap.c b/net/oic/src/messaging/coap/coap.c index 5e490bd..470af9c 100644 --- a/net/oic/src/messaging/coap/coap.c +++ b/net/oic/src/messaging/coap/coap.c @@ -289,46 +289,27 @@ coap_init_message(coap_packet_t *pkt, coap_message_type_t type, /*---------------------------------------------------------------------------*/ size_t -coap_serialize_message(coap_packet_t *pkt, uint8_t *buffer) +coap_serialize_message(coap_packet_t *pkt, uint8_t *buffer, int tcp_hdr) { struct coap_udp_hdr *cuh; + struct coap_tcp_hdr0 *cth0; + struct coap_tcp_hdr8 *cth8; + struct coap_tcp_hdr16 *cth16; + struct coap_tcp_hdr32 *cth32; uint8_t *option; unsigned int current_number = 0; + int len, data_len; /* Initialize */ pkt->buffer = buffer; pkt->version = 1; - LOG("-Serializing MID %u to %p, ", pkt->mid, pkt->buffer); - - /* set header fields */ - cuh = (struct coap_udp_hdr *)pkt->buffer; - cuh->version = pkt->version; - cuh->type = pkt->type; - cuh->token_len = pkt->token_len; - cuh->code = pkt->code; - cuh->id = htons(pkt->mid); - - /* empty packet, dont need to do more stuff */ - if (!pkt->code) { - LOG("-Done serializing empty message at %p-\n", pkt->buffer); - return 4; - } - - /* set Token */ - LOG("Token (len %u)", pkt->token_len); - option = pkt->buffer + COAP_HEADER_LEN; - for (current_number = 0; current_number < pkt->token_len; - ++current_number) { - LOG(" %02X", pkt->token[current_number]); - *option = pkt->token[current_number]; - ++option; - } - LOG("-\n"); + LOG("-Serializing MID %u to %p, ", pkt->mid, buffer); /* Serialize options */ current_number = 0; + option = buffer; LOG("-Serializing options at %p-\n", option); #if 0 /* The options must be serialized in the order of their number */ @@ -374,21 +355,68 @@ coap_serialize_message(coap_packet_t *pkt, uint8_t *buffer) LOG("-Done serializing at %p----\n", option); - /* Pack payload */ - if ((option - pkt->buffer) <= COAP_MAX_HEADER_SIZE) { - /* Payload marker */ - if (pkt->payload_len) { - *option = 0xFF; - ++option; + /* Payload marker */ + if (pkt->payload_len) { + *option = 0xFF; + ++option; + } + len = option - buffer; + data_len = len + pkt->payload_len; + + /* set header fields */ + if (!tcp_hdr) { + if (len + sizeof(*cuh) + pkt->token_len > COAP_MAX_HEADER_SIZE) { + pkt->buffer = NULL; + coap_error_message = "Serialized header exceeds MAX_HEADER_SIZE"; + return 0; } - memmove(option, pkt->payload, pkt->payload_len); + memmove(buffer + sizeof(*cuh) + pkt->token_len, buffer, len); + cuh = (struct coap_udp_hdr *)buffer; + cuh->version = pkt->version; + cuh->type = pkt->type; + cuh->token_len = pkt->token_len; + cuh->code = pkt->code; + cuh->id = htons(pkt->mid); + option = (uint8_t *)(cuh + 1); } else { - /* an error occurred: caller must check for !=0 */ - pkt->buffer = NULL; - coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE"; - return 0; + if (data_len < 13) { + memmove(buffer + sizeof(*cth0) + pkt->token_len, buffer, len); + cth0 = (struct coap_tcp_hdr0 *)buffer; + cth0->data_len = data_len; + cth0->token_len = pkt->token_len; + cth0->code = pkt->code; + option = (uint8_t *)(cth0 + 1); + } else if (data_len < 269) { + memmove(buffer + sizeof(*cth8) + pkt->token_len, buffer, len); + cth8 = (struct coap_tcp_hdr8 *)buffer; + cth8->type = COAP_TCP_TYPE8; + cth8->token_len = pkt->token_len; + cth8->data_len = data_len - 13; + cth8->code = pkt->code; + option = (uint8_t *)(cth8 + 1); + } else if (data_len < 65805) { + memmove(buffer + sizeof(*cth16) + pkt->token_len, buffer, len); + cth16 = (struct coap_tcp_hdr16 *)buffer; + cth16->type = COAP_TCP_TYPE16; + cth16->token_len = pkt->token_len; + cth16->data_len = htons(data_len - 269); + cth16->code = pkt->code; + option = (uint8_t *)(cth16 + 1); + } else { + memmove(buffer + sizeof(*cth32) + pkt->token_len, buffer, len); + cth32 = (struct coap_tcp_hdr32 *)buffer; + cth32->type = COAP_TCP_TYPE32; + cth32->token_len = pkt->token_len; + cth32->data_len = htonl(data_len - 65805); + cth32->code = pkt->code; + option = (uint8_t *)(cth32 + 1); + } } + memcpy(option, pkt->token, pkt->token_len); + option += (len + pkt->token_len); + memmove(option, pkt->payload, pkt->payload_len); + LOG("-Done %u B (header len %u, payload len %u)-\n", (unsigned int)(pkt->payload_len + option - buffer), (unsigned int)(option - buffer), (unsigned int)pkt->payload_len); @@ -409,9 +437,14 @@ coap_send_message(oc_message_t *message) /*---------------------------------------------------------------------------*/ coap_status_t -coap_parse_message(coap_packet_t *pkt, uint8_t *data, uint16_t data_len) +coap_parse_message(coap_packet_t *pkt, uint8_t *data, uint16_t data_len, + int tcp_hdr) { struct coap_udp_hdr *udp; + struct coap_tcp_hdr0 *cth0; + struct coap_tcp_hdr8 *cth8; + struct coap_tcp_hdr16 *cth16; + struct coap_tcp_hdr32 *cth32; uint8_t *cur_opt; unsigned int opt_num = 0; unsigned int opt_delta = 0; @@ -423,24 +456,51 @@ coap_parse_message(coap_packet_t *pkt, uint8_t *data, uint16_t data_len) pkt->buffer = data; /* parse header fields */ - udp = (struct coap_udp_hdr *)data; - pkt->version = udp->version; - pkt->type = udp->type; - pkt->token_len = udp->token_len; - pkt->code = udp->code; - pkt->mid = ntohs(udp->id); - - if (pkt->version != 1) { - coap_error_message = "CoAP version must be 1"; - return BAD_REQUEST_4_00; + if (!tcp_hdr) { + udp = (struct coap_udp_hdr *)data; + pkt->version = udp->version; + pkt->type = udp->type; + pkt->token_len = udp->token_len; + pkt->code = udp->code; + pkt->mid = ntohs(udp->id); + if (pkt->version != 1) { + coap_error_message = "CoAP version must be 1"; + return BAD_REQUEST_4_00; + } + cur_opt = (uint8_t *)(udp + 1); + } else { + /* + * We cannot just look at the data length, as token might or might + * not be present. Need to figure out which header is present + * programmatically. + */ + cth0 = (struct coap_tcp_hdr0 *)data; + if (cth0->data_len < 13) { + pkt->token_len = cth0->token_len; + pkt->code = cth0->code; + cur_opt = (uint8_t *)(cth0 + 1); + } else if (cth0->data_len == 13) { + cth8 = (struct coap_tcp_hdr8 *)data; + pkt->token_len = cth8->token_len; + pkt->code = cth8->code; + cur_opt = (uint8_t *)(cth8 + 1); + } else if (cth0->data_len == 14) { + cth16 = (struct coap_tcp_hdr16 *)data; + pkt->token_len = cth16->token_len; + pkt->code = cth16->code; + cur_opt = (uint8_t *)(cth16 + 1); + } else { + cth32 = (struct coap_tcp_hdr32 *)data; + pkt->token_len = cth32->token_len; + pkt->code = cth32->code; + cur_opt = (uint8_t *)(cth32 + 1); + } } if (pkt->token_len > COAP_TOKEN_LEN) { coap_error_message = "Token Length must not be more than 8"; return BAD_REQUEST_4_00; } - cur_opt = data + sizeof(*udp); - memcpy(pkt->token, cur_opt, pkt->token_len); LOG("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/messaging/coap/coap.h ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/coap.h b/net/oic/src/messaging/coap/coap.h index 11377eb..987f34a 100644 --- a/net/oic/src/messaging/coap/coap.h +++ b/net/oic/src/messaging/coap/coap.h @@ -212,10 +212,10 @@ uint16_t coap_get_mid(void); void coap_init_message(coap_packet_t *, coap_message_type_t type, uint8_t code, uint16_t mid); -size_t coap_serialize_message(coap_packet_t *, uint8_t *buffer); +size_t coap_serialize_message(coap_packet_t *, uint8_t *buffer, int tcp_hdr); void coap_send_message(oc_message_t *message); coap_status_t coap_parse_message(coap_packet_t *request, uint8_t *data, - uint16_t data_len); + uint16_t data_len, int tcp_hdr); int coap_get_query_variable(coap_packet_t *, const char *name, const char **output); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/messaging/coap/constants.h ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/constants.h b/net/oic/src/messaging/coap/constants.h index e0c0f66..385df69 100644 --- a/net/oic/src/messaging/coap/constants.h +++ b/net/oic/src/messaging/coap/constants.h @@ -50,6 +50,9 @@ extern "C" { #define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */ #define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */ +/* + * Standard COAP header + */ struct coap_udp_hdr { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ uint8_t version:2; /* protocol version */ @@ -60,10 +63,75 @@ struct coap_udp_hdr { uint8_t type:2; /* type flag */ uint8_t version:2; /* protocol version */ #endif - uint8_t code; /* request (1-10) or response (value 40-255) */ - uint16_t id; /* transaction id */ + uint8_t code; /* request (1-10) or response (value 40-255) */ + uint16_t id; /* transaction id */ +}; + +/* + * Header used by Iotivity for TCP-like transports. + * 4 different kinds of headers. + */ +#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_TYPE0 0 +#define COAP_TCP_TYPE8 13 +#define COAP_TCP_TYPE16 14 +#define COAP_TCP_TYPE32 15 + +struct coap_tcp_hdr0 { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t data_len:4; /* packet length */ + uint8_t token_len:4; /* length of token */ +#else + uint8_t token_len:4; /* length of token */ + uint8_t data_len:4; /* packet length */ +#endif + uint8_t code; +}; + +struct coap_tcp_hdr8 { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t type:4; /* header type == 13 */ + uint8_t token_len:4; /* length of token */ +#else + uint8_t token_len:4; /* length of token */ + uint8_t type:4; /* header type == 13*/ +#endif + uint8_t data_len; /* packet size - 13 */ + uint8_t code; }; +struct coap_tcp_hdr16 { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t type:4; /* header type == 14 */ + uint8_t token_len:4; /* length of token */ +#else + uint8_t token_len:4; /* length of token */ + uint8_t type:4; /* header type == 14 */ +#endif + uint16_t data_len; /* packet size - 269 */ + uint8_t code; +} __attribute__((packed)); + +struct coap_tcp_hdr32 { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t type:4; /* header type == 15 */ + uint8_t token_len:4; /* length of token */ +#else + uint8_t token_len:4; /* length of token */ + uint8_t type:4; /* header type == 15*/ +#endif + uint32_t data_len; /* packet size - 65805 */ + uint8_t code; +} __attribute__((packed)); + +#define COAP_TCP_TYPE8 13 +#define COAP_TCP_TYPE16 14 +#define COAP_TCP_TYPE32 15 + + #define COAP_HEADER_OPTION_DELTA_MASK 0xF0 #define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/messaging/coap/engine.c ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/engine.c b/net/oic/src/messaging/coap/engine.c index 511b71c..009a2e3 100644 --- a/net/oic/src/messaging/coap/engine.c +++ b/net/oic/src/messaging/coap/engine.c @@ -66,7 +66,8 @@ coap_receive(oc_message_t *msg) static coap_packet_t response[1]; static coap_transaction_t *transaction = NULL; - erbium_status_code = coap_parse_message(message, msg->data, msg->length); + erbium_status_code = coap_parse_message(message, msg->data, msg->length, + oc_endpoint_use_tcp(&msg->endpoint)); if (erbium_status_code == NO_ERROR) { @@ -220,7 +221,8 @@ coap_receive(oc_message_t *msg) } if (erbium_status_code == NO_ERROR) { if ((transaction->message->length = coap_serialize_message( - response, transaction->message->data)) == 0) { + response, transaction->message->data, + oc_endpoint_use_tcp(&msg->endpoint))) == 0) { erbium_status_code = PACKET_SERIALIZATION_ERROR; } transaction->type = response->type; @@ -264,7 +266,7 @@ coap_receive(oc_message_t *msg) coap_send_transaction(transaction); } } else if (erbium_status_code == CLEAR_TRANSACTION) { - LOG("Clearing transaction for manual response"); + LOG("Clearing transaction for manual response\n"); coap_clear_transaction(transaction); // used in server for separate response } #ifdef OC_CLIENT @@ -273,7 +275,8 @@ coap_receive(oc_message_t *msg) oc_message_t *response = oc_allocate_message(); if (response) { memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); - response->length = coap_serialize_message(message, response->data); + response->length = coap_serialize_message(message, response->data, + oc_endpoint_use_tcp(&msg->endpoint)); coap_send_message(response); } } @@ -290,7 +293,8 @@ coap_receive(oc_message_t *msg) oc_message_t *response = oc_allocate_message(); if (response) { memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); - response->length = coap_serialize_message(message, response->data); + response->length = coap_serialize_message(message, response->data, + oc_endpoint_use_tcp(&response->endpoint)); coap_send_message(response); } } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/messaging/coap/observe.c ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/observe.c b/net/oic/src/messaging/coap/observe.c index 0202bb6..d6c5cba 100644 --- a/net/oic/src/messaging/coap/observe.c +++ b/net/oic/src/messaging/coap/observe.c @@ -297,7 +297,8 @@ coap_notify_observers(oc_resource_t *resource, transaction->message->length = coap_serialize_message(notification, - transaction->message->data); + transaction->message->data, + oc_endpoint_use_tcp(&obs->endpoint)); transaction->type = notification->type; coap_send_transaction(transaction); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/messaging/coap/separate.c ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/separate.c b/net/oic/src/messaging/coap/separate.c index 015aa2d..757860e 100644 --- a/net/oic/src/messaging/coap/separate.c +++ b/net/oic/src/messaging/coap/separate.c @@ -105,7 +105,8 @@ coap_separate_accept(coap_packet_t *coap_req, if (message != NULL) { message->endpoint.flags = IP; memcpy(&message->endpoint, endpoint, sizeof(oc_endpoint_t)); - message->length = coap_serialize_message(ack, message->data); + message->length = coap_serialize_message(ack, message->data, + oc_endpoint_use_tcp(&message->endpoint)); coap_send_message(message); } else { coap_separate_clear(separate_response, separate_store); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3b8b6928/net/oic/src/port/oc_connectivity.h ---------------------------------------------------------------------- diff --git a/net/oic/src/port/oc_connectivity.h b/net/oic/src/port/oc_connectivity.h index 123db7c..f5a075e 100644 --- a/net/oic/src/port/oc_connectivity.h +++ b/net/oic/src/port/oc_connectivity.h @@ -73,6 +73,16 @@ uint16_t oc_connectivity_get_dtls_port(void); int oc_connectivity_init(void); void oc_connectivity_shutdown(void); +static inline int +oc_endpoint_use_tcp(struct oc_endpoint *oe) +{ + if (oe->flags & GATT) { + return 1; + } + return 0; +} + + void oc_send_buffer(struct os_mbuf *); void oc_send_multicast_message(struct os_mbuf *);