From 5802a4b23868f8f7730ee880fa73ee26ab893473 Mon Sep 17 00:00:00 2001 From: Jin-Seong Kim Date: Mon, 31 Jul 2017 16:30:32 +0900 Subject: [PATCH] netutils/libcoap : TCP patch for CoAP observe mode This commit is TCP patch for CoAP observe mode Change-Id: Ie6617414b3674bee73997d071ccba034ea1d4bf2 Signed-off-by: Jin-Seong Kim --- apps/examples/libcoap_client/libcoap-client.c | 2 +- apps/examples/libcoap_server/libcoap-server.c | 87 +++++++++++++++++++++++---- apps/netutils/libcoap/async.c | 47 +++++++++++---- apps/netutils/libcoap/net.c | 3 +- apps/netutils/libcoap/resource.c | 45 ++++++++++---- 5 files changed, 149 insertions(+), 35 deletions(-) diff --git a/apps/examples/libcoap_client/libcoap-client.c b/apps/examples/libcoap_client/libcoap-client.c index f8c041c..c7791a4 100644 --- a/apps/examples/libcoap_client/libcoap-client.c +++ b/apps/examples/libcoap_client/libcoap-client.c @@ -502,7 +502,7 @@ void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, c /* check if an error was signaled and output payload if so */ if (COAP_RESPONSE_CLASS(code) >= 4) { - fprintf(stderr, "%d.%02d", (received->hdr->code >> 5), received->hdr->code & 0x1F); + fprintf(stderr, "%d.%02d", (code >> 5), code & 0x1F); if (coap_get_data(received, &len, &databuf)) { fprintf(stderr, " "); while (len--) { diff --git a/apps/examples/libcoap_server/libcoap-server.c b/apps/examples/libcoap_server/libcoap-server.c index 7a76e3e..478be55 100644 --- a/apps/examples/libcoap_server/libcoap-server.c +++ b/apps/examples/libcoap_server/libcoap-server.c @@ -114,16 +114,43 @@ void hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_ad coap_tick_t t; coap_subscription_t *subscription; + coap_transport_t transport = COAP_UDP; + unsigned short req_code; + /* FIXME: return time, e.g. in human-readable by default and ticks * when query ?ticks is given. */ /* if my_clock_base was deleted, we pretend to have no such resource */ + + switch(ctx->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + transport = COAP_UDP; + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + transport = coap_get_tcp_header_type_from_size(request->length); + break; + default: + /* Should not enter here */ + break; + } + + req_code = (unsigned short)coap_get_code(response, transport); + 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)) { + if (request != NULL && coap_check_option2(request, COAP_OPTION_OBSERVE, &opt_iter, transport)) { subscription = coap_add_observer(resource, peer, token); if (subscription) { - subscription->non = request->transport_hdr->udp.type == COAP_MESSAGE_NON; + if (ctx->protocol == COAP_PROTO_UDP || ctx->protocol == COAP_PROTO_DTLS) { + subscription->non = request->transport_hdr->udp.type == COAP_MESSAGE_NON; + } else if (ctx->protocol == COAP_PROTO_TCP || ctx->protocol == COAP_PROTO_TLS) { + /* TCP / TLS doesn't have type field on header */ + subscription->non = 1; + } else { + /* Should not enter here */ + } coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL); } } @@ -143,7 +170,7 @@ void hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_ad coap_ticks(&t); now = my_clock_base + (t / COAP_TICKS_PER_SECOND); - if (request != NULL && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter)) + if (request != NULL && (option = coap_check_option2(request, COAP_OPTION_URI_QUERY, &opt_iter, transport)) && memcmp(COAP_OPT_VALUE(option), "ticks", min(5, COAP_OPT_LENGTH(option))) == 0) { /* output ticks */ len = snprintf((char *)buf, min(sizeof(buf), response->max_size - response->length), "%u", (unsigned int)now); @@ -205,16 +232,38 @@ void hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource, coap_a unsigned long delay = 5; size_t size; + coap_opt_filter_t f; + coap_transport_t transport = COAP_UDP; + + switch(ctx->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + transport = COAP_UDP; + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + transport = coap_get_tcp_header_type_from_size(request->length); + break; + default: + break; + } + if (async) { - if (async->id != request->transport_hdr->udp.id) { - coap_opt_filter_t f; - coap_option_filter_clear(f); + + coap_option_filter_clear(f); + if (ctx->protocol == COAP_PROTO_UDP || ctx->protocol == COAP_PROTO_DTLS) { + if (async->id != request->transport_hdr->udp.id) { + response->transport_hdr->udp.code = COAP_RESPONSE_CODE(503); + } + } else if (ctx->protocol == COAP_PROTO_TCP || ctx->protocol == COAP_PROTO_TLS) { response->transport_hdr->udp.code = COAP_RESPONSE_CODE(503); + } else { + /* Should not enter here */ } return; } - option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter); + option = coap_check_option2(request, COAP_OPTION_URI_QUERY, &opt_iter, transport); if (option) { unsigned char *p = COAP_OPT_VALUE(option); @@ -240,7 +289,7 @@ void check_async(coap_context_t *ctx, coap_tick_t now) response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM ? COAP_MESSAGE_CON : COAP_MESSAGE_NON, COAP_RESPONSE_CODE(205), 0, size); if (!response) { - debug("check_async: insufficient memory, we'll try later\n"); + debug("check_async : insufficient memory, we'll try later\n"); async->appdata = (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND); return; } @@ -253,10 +302,26 @@ 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->transport_hdr->udp.id); + if (ctx->protocol == COAP_PROTO_UDP || ctx->protocol == COAP_PROTO_DTLS) { + if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) { + debug("check_async : cannot send response for message %d\n", response->transport_hdr->udp.id); + } + coap_delete_pdu(response); + } else if (ctx->protocol == COAP_PROTO_TCP || ctx->protocol == COAP_PROTO_TLS) { + coap_pdu_t *tcp_resp = NULL; + tcp_resp = coap_convert_to_tcp_pdu(response); + if (tcp_resp != NULL) { + warn("check_async : failed to create tcp response\n"); + } else { + if (coap_send(ctx, &async->peer, tcp_resp) == COAP_INVALID_TID) { + debug("check_async : cannot send TCP response for message %d\n", response->transport_hdr->udp.id); + } + coap_delete_pdu(tcp_resp); + } + } else { + /* Should not enter here */ } - coap_delete_pdu(response); + coap_remove_async(ctx, async->id, &tmp); coap_free_async(async); async = NULL; diff --git a/apps/netutils/libcoap/async.c b/apps/netutils/libcoap/async.c index fc82412..623d277 100644 --- a/apps/netutils/libcoap/async.c +++ b/apps/netutils/libcoap/async.c @@ -21,45 +21,70 @@ #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; coap_tid_t id; + coap_transport_t transport = COAP_UDP; + + unsigned char *token; + unsigned int token_len = 0; + + switch(context->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + transport = COAP_UDP; + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + transport = coap_get_tcp_header_type_from_size(request->length); + break; + default: + break; + } + coap_transaction_id2(peer, request, &id, context->protocol); LL_SEARCH_SCALAR(context->async_state, s, id, id); + coap_get_token2(request->transport_hdr, transport, &token, &token_len); + + if (token_len > 8) { + debug("coap_register_async : invalied length of token\n"); + return NULL; + } + if (s != NULL) { /* We must return NULL here as the caller must know that he is * responsible for releasing @p data. */ - debug("asynchronous state for transaction %d already registered\n", id); + debug("coap_register_async : asynchronous state for transaction %d already registered\n", id); return NULL; } /* store information for handling the asynchronous task */ - s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) + - request->transport_hdr->udp.token_length); + s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + token_len); if (!s) { - coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n"); + coap_log(LOG_CRIT, "coap_register_async : insufficient memory\n"); return NULL; } - memset(s, 0, sizeof(coap_async_state_t) + request->transport_hdr->udp.token_length); + memset(s, 0, sizeof(coap_async_state_t) + token_len); /* set COAP_ASYNC_CONFIRM according to request's type */ s->flags = flags & ~COAP_ASYNC_CONFIRM; - if (request->transport_hdr->udp.type == COAP_MESSAGE_CON) { - s->flags |= COAP_ASYNC_CONFIRM; + if (context->protocol == COAP_PROTO_UDP || context->protocol == COAP_PROTO_TCP) { + if (request->transport_hdr->udp.type == COAP_MESSAGE_CON) { + s->flags |= COAP_ASYNC_CONFIRM; + } } s->appdata = data; memcpy(&s->peer, peer, sizeof(coap_address_t)); - 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); + if (token_len) { + s->tokenlen = token_len; + memcpy(s->token, token, token_len); } memcpy(&s->id, &id, sizeof(coap_tid_t)); diff --git a/apps/netutils/libcoap/net.c b/apps/netutils/libcoap/net.c index 18c4f95..0740bea 100644 --- a/apps/netutils/libcoap/net.c +++ b/apps/netutils/libcoap/net.c @@ -1022,7 +1022,8 @@ int coap_read(coap_context_t *ctx) transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)buf)[0] >> 4); debug("coap_read : received header type, transport %d, len %u, bytes_read %d\n", transport, ((buf[0] >> 4) & 0x0f), bytes_read); if (!coap_pdu_parse2((unsigned char*)buf, bytes_read, node->pdu, transport)) { - warn("coap_read : discard malformed TCP PDU\n"); + /* FIXME : prevent printing log when continuously received wrong PDU */ + //warn("coap_read : discard malformed TCP PDU\n"); goto error; } node->transport = transport; diff --git a/apps/netutils/libcoap/resource.c b/apps/netutils/libcoap/resource.c index 332fcdb..70cfd28 100644 --- a/apps/netutils/libcoap/resource.c +++ b/apps/netutils/libcoap/resource.c @@ -693,7 +693,8 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r) coap_method_handler_t h; coap_subscription_t *obs; str token; - coap_pdu_t *response; + coap_pdu_t *response = NULL; + coap_pdu_t *tcp_resp = NULL; if (r->observable && (r->dirty || r->partiallydirty)) { r->partiallydirty = 0; @@ -731,7 +732,7 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r) token.length = obs->token_length; token.s = obs->token; - /* 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->transport_hdr->udp.type = COAP_MESSAGE_NON; @@ -741,17 +742,39 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r) /* fill with observer-specific data */ h(context, r, &obs->subscriber, NULL, &token, response); - if (response->transport_hdr->udp.type == COAP_MESSAGE_CON) { - tid = coap_send_confirmed(context, &obs->subscriber, response); - obs->non_cnt = 0; - } else { - tid = coap_send(context, &obs->subscriber, response); - obs->non_cnt++; - } + switch (context->protocol) { + case COAP_PROTO_UDP: + case COAP_PROTO_DTLS: + if (response->transport_hdr->udp.type == COAP_MESSAGE_CON) { + tid = coap_send_confirmed(context, &obs->subscriber, response); + obs->non_cnt = 0; + } else { + tid = coap_send(context, &obs->subscriber, response); + obs->non_cnt++; + } - if (COAP_INVALID_TID == tid || response->transport_hdr->udp.type != COAP_MESSAGE_CON) { - coap_delete_pdu(response); + if (COAP_INVALID_TID == tid || + response->transport_hdr->udp.type != COAP_MESSAGE_CON) { + coap_delete_pdu(response); + } + break; + case COAP_PROTO_TCP: + case COAP_PROTO_TLS: + tcp_resp = coap_convert_to_tcp_pdu(response); + if (tcp_resp == NULL) { + warn("coap_check_notify : failed to create TCP response\n"); + } else { + tid = coap_send(context, &obs->subscriber, tcp_resp); + if (COAP_INVALID_TID == tid) { + coap_delete_pdu(tcp_resp); + } + } + break; + default: + /* Should not enter here */ + break; } + if (COAP_INVALID_TID == tid) { debug("coap_check_notify: sending failed, resource stays partially dirty\n"); obs->dirty = 1; -- 2.7.4