netutils/libcoap : TCP patch for CoAP observe mode
authorJin-Seong Kim <jseong82.kim@samsung.com>
Mon, 31 Jul 2017 07:30:32 +0000 (16:30 +0900)
committerEunBong Song <eunb.song@samsung.com>
Wed, 30 Aug 2017 04:15:47 +0000 (21:15 -0700)
This commit is TCP patch for CoAP observe mode

Change-Id: Ie6617414b3674bee73997d071ccba034ea1d4bf2
Signed-off-by: Jin-Seong Kim <jseong82.kim@samsung.com>
apps/examples/libcoap_client/libcoap-client.c
apps/examples/libcoap_server/libcoap-server.c
apps/netutils/libcoap/async.c
apps/netutils/libcoap/net.c
apps/netutils/libcoap/resource.c

index f8c041c..c7791a4 100644 (file)
@@ -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--) {
index 7a76e3e..478be55 100644 (file)
@@ -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;
index fc82412..623d277 100644 (file)
 #include <apps/netutils/libcoap/debug.h>
 #include <apps/netutils/libcoap/async.h>
 
-/* TODO : Considering TCP Case */
 coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data)
 {
        coap_async_state_t *s;
        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));
index 18c4f95..0740bea 100644 (file)
@@ -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;
index 332fcdb..70cfd28 100644 (file)
@@ -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;