From 30af410dea8e22d7226db14e82d6e59a15d4a70b Mon Sep 17 00:00:00 2001 From: clairiky Date: Tue, 19 Aug 2014 18:39:46 -0700 Subject: [PATCH] A commit with Confirmable support: Patch set 1 which supports: 1) Sending a delayed response when the request is received as multicast, tested only on linux. 2) Sending confirmable requests. 3) Sending confirmable observer notifications. 4) Sending nonconfirmable observer notification with support of detecting client leaving. 5) Added support for client to send RESET instead of regular GET. 6) Error handling in cases of failed retransmissions. 7) Code reorganizations and refactoring. Patch set 2: 1) Response to code reviews Patch set 3: 1) Rebased on master Patch set 4: Removed tabs. Change-Id: I502168bf71c7253f3d4b64b9c2edfe40b1cd8d7a --- csdk/libcoap-4.1.1/net.c | 214 +++++--- csdk/libcoap-4.1.1/net.h | 41 +- csdk/libcoap-4.1.1/pdu.h | 6 +- csdk/libcoap-4.1.1/resource.c | 176 +++---- csdk/occoap/include/occoap.h | 21 +- csdk/occoap/include/occoaphelper.h | 50 +- csdk/occoap/src/occoap.c | 419 ++++++++-------- csdk/occoap/src/occoaphelper.c | 544 +++++++++++++++------ csdk/occoap/test/occoaptests.cpp | 13 - csdk/stack/include/internal/ocobserve.h | 42 +- csdk/stack/include/internal/ocstackinternal.h | 2 +- csdk/stack/include/ocstack.h | 3 + .../samples/linux/SimpleClientServer/occlient.cpp | 112 +++-- .../samples/linux/SimpleClientServer/ocserver.cpp | 2 +- csdk/stack/src/ocobserve.c | 258 +++++++--- csdk/stack/src/ocresource.c | 3 + csdk/stack/src/ocstack.c | 96 ++-- csdk/stack/test/arduino/ArduinoStackTest.cpp | 4 +- 18 files changed, 1273 insertions(+), 733 deletions(-) diff --git a/csdk/libcoap-4.1.1/net.c b/csdk/libcoap-4.1.1/net.c index c8307f9..db4462a 100644 --- a/csdk/libcoap-4.1.1/net.c +++ b/csdk/libcoap-4.1.1/net.c @@ -571,7 +571,7 @@ coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst, response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, sizeof(coap_pdu_t)); if (response) { - result = coap_send(context, dst, response); + result = coap_send(context, dst, response, SEND_NOW); coap_delete_pdu(response); } } @@ -580,31 +580,21 @@ coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst, #if defined(WITH_POSIX) || defined(WITH_ARDUINO) /* releases space allocated by PDU if free_pdu is set */ -coap_tid_t +int coap_send_impl(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu) { -#ifdef WITH_POSIX - ssize_t bytes_written; -#else /* if it is Arduino */ - int bytes_written; -#endif - coap_tid_t id = COAP_INVALID_TID; + + int bytes_written = -1; if ( !context || !dst || !pdu ) - return id; + return bytes_written; bytes_written = OCSendTo( context->sockfd, (uint8_t*)(pdu->hdr), pdu->length, 0, (OCDevAddr*)dst); debug("bytes_written %d\n", (int)bytes_written); - if (bytes_written >= 0) { - coap_transaction_id(dst, pdu, &id); - } else { - coap_log(LOG_CRIT, "coap_send: sendto\n"); - } - - return id; + return bytes_written; } #endif /* WITH_POSIX || WITH_ARDUINO */ #ifdef WITH_CONTIKI @@ -684,11 +674,6 @@ coap_send_impl(coap_context_t *context, } #endif /* WITH_LWIP */ -coap_tid_t coap_send(coap_context_t *context, const coap_address_t *dst, - coap_pdu_t *pdu) { - return coap_send_impl(context, dst, pdu); -} - coap_tid_t coap_send_error(coap_context_t *context, coap_pdu_t *request, const coap_address_t *dst, unsigned char code, coap_opt_filter_t opts) { coap_pdu_t *response; @@ -699,7 +684,7 @@ coap_tid_t coap_send_error(coap_context_t *context, coap_pdu_t *request, response = coap_new_error_response(request, code, opts); if (response) { - result = coap_send(context, dst, response); + result = coap_send(context, dst, response, SEND_NOW); coap_delete_pdu(response); } @@ -714,41 +699,55 @@ coap_tid_t coap_send_message_type(coap_context_t *context, if (request) { response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); if (response) { - result = coap_send(context, dst, response); + result = coap_send(context, dst, response, SEND_NOW); coap_delete_pdu(response); } } return result; } -coap_tid_t coap_send_confirmed(coap_context_t *context, - const coap_address_t *dst, coap_pdu_t *pdu) { - coap_queue_t *node; +coap_tid_t coap_send(coap_context_t *context, + const coap_address_t *dst, coap_pdu_t *pdu, const uint8_t flag) +{ + coap_queue_t *node = NULL; coap_tick_t now; + coap_tid_t tid; + int bytesWritten; int r; - node = coap_new_node(); - if (!node) { - debug("coap_send_confirmed: insufficient memory\n"); + if (!context) return COAP_INVALID_TID; + if(flag != SEND_RETX){ + coap_transaction_id(dst, pdu, &tid); + } + if(flag == SEND_NOW || flag == SEND_RETX) + { + goto sending; } - node->id = coap_send_impl(context, dst, pdu); - if (COAP_INVALID_TID == node->id) { - debug("coap_send_confirmed: error sending pdu\n"); - coap_free_node(node); + node = coap_new_node(); + if (!node) { + debug("coap_send: insufficient memory\n"); return COAP_INVALID_TID; } prng((unsigned char * )&r, sizeof(r)); - /* add randomized RESPONSE_TIMEOUT to determine retransmission timeout */ - node->timeout = COAP_DEFAULT_RESPONSE_TIMEOUT * COAP_TICKS_PER_SECOND - + (COAP_DEFAULT_RESPONSE_TIMEOUT >> 1) - * ((COAP_TICKS_PER_SECOND * (r & 0xFF)) >> 8); + if(flag == SEND_NOW_CON) + { + node->timeout = COAP_DEFAULT_RESPONSE_TIMEOUT * COAP_TICKS_PER_SECOND + + (COAP_DEFAULT_RESPONSE_TIMEOUT >> 1) + * ((COAP_TICKS_PER_SECOND * (r & 0xFF)) >> 8); + } + else + { + node->timeout = MAX_MULTICAST_DELAY_SEC * ((COAP_TICKS_PER_SECOND * (r & 0xFF)) >> 8); + node->delayedResponse = 1; + } memcpy(&node->remote, dst, sizeof(coap_address_t)); node->pdu = pdu; + node->id = tid; /* Set timer for pdu retransmission. If this is the first element in * the retransmission queue, the base time is set to the current @@ -757,23 +756,28 @@ coap_tid_t coap_send_confirmed(coap_context_t *context, * to be retransmitted earlier. Therefore, node->timeout is first * normalized to the base time and then inserted into the queue with * an adjusted relative time. - */coap_ticks(&now); - if (context->sendqueue == NULL) { + */ + + coap_ticks(&now); + if (context->sendqueue == NULL) + { node->t = node->timeout; context->sendqueue_basetime = now; - } else { + } + else + { /* make node->t relative to context->sendqueue_basetime */ node->t = (now - context->sendqueue_basetime) + node->timeout; } - coap_insert_node(&context->sendqueue, node); -#ifdef WITH_LWIP - if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */ - coap_retransmittimer_restart(context); -#endif + #ifdef WITH_LWIP + if (node == context->sendqueue) + /* don't bother with timer stuff if there are earlier retransmits */ + coap_retransmittimer_restart(context); + #endif -#ifdef WITH_CONTIKI + #ifdef WITH_CONTIKI { /* (re-)initialize retransmission timer */ coap_queue_t *nextpdu; @@ -785,12 +789,28 @@ coap_tid_t coap_send_confirmed(coap_context_t *context, etimer_set(&context->retransmit_timer, nextpdu->t); PROCESS_CONTEXT_END(&coap_retransmit_process); } -#endif /* WITH_CONTIKI */ + #endif /* WITH_CONTIKI */ - return node->id; + if(flag == SEND_NOW_CON) + { + goto sending; + } + return tid; + + sending: + bytesWritten = coap_send_impl(context, dst, pdu); + if(bytesWritten > 0) + { + return tid; + } + debug("coap_send_impl: error sending pdu\n"); + coap_free_node(node); + return COAP_INVALID_TID; } coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node) { + coap_tid_t tid = COAP_INVALID_TID; + if (!context || !node) return COAP_INVALID_TID; @@ -806,9 +826,8 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node) { debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->hdr->id)); - - node->id = coap_send_impl(context, &node->remote, node->pdu); - return node->id; + tid = coap_send(context, (coap_address_t *)&(node->remote),node->pdu, SEND_RETX); + return (tid == COAP_INVALID_TID)? COAP_INVALID_TID : node->id; } /* no more retransmissions, remove node from system */ @@ -830,8 +849,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node) { } #endif /* WITHOUT_OBSERVE */ - /* And finally delete the node */ - coap_delete_node(node); + // deletion of node will happen in ocoap since we still need the info node has return COAP_INVALID_TID; } @@ -856,13 +874,11 @@ int coap_read(coap_context_t *ctx, int sockfd) { char *buf; #endif coap_hdr_t *pdu; -#ifndef WITH_ARDUINO - ssize_t bytes_read = -1; -#else /* if it is Arduino */ int bytes_read = -1; -#endif + coap_address_t src, dst; coap_queue_t *node; + unsigned char delayRes = 0; #ifdef WITH_CONTIKI buf = uip_appdata; @@ -882,6 +898,11 @@ int coap_read(coap_context_t *ctx, int sockfd) { bytes_read = OCRecvFrom( sockfd, (uint8_t*)buf, sizeof(buf), 0, (OCDevAddr*)&src); + // Set the delayed response flag for responding to multicast requests + if (sockfd == ctx->sockfd_wellknown && bytes_read > 0) { + delayRes = 1; + } + #endif /* WITH_POSIX || WITH_ARDUINO */ #ifdef WITH_CONTIKI if(uip_newdata()) { @@ -941,6 +962,9 @@ int coap_read(coap_context_t *ctx, int sockfd) { goto error; } + //set the delayed response flag + node->delayedResponse = delayRes; + /* and add new node to receive queue */ coap_transaction_id(&node->remote, node->pdu, &node->id); coap_insert_node(&ctx->recvqueue, node); @@ -1413,7 +1437,6 @@ handle_request(coap_context_t *context, coap_queue_t *node) { } #endif static void handle_request(coap_context_t *context, coap_queue_t *rcvd) { - /* Call application-specific reponse handler when available. If * not, we must acknowledge confirmable messages. */ if (context->request_handler) { @@ -1424,8 +1447,7 @@ static void handle_request(coap_context_t *context, coap_queue_t *rcvd) { } } -static inline void handle_response(coap_context_t *context, coap_queue_t *rcvd) { - +static void handle_response(coap_context_t *context, coap_queue_t *rcvd) { /* Call application-specific reponse handler when available. If * not, we must acknowledge confirmable messages. */ if (context->response_handler) { @@ -1436,6 +1458,14 @@ static inline void handle_response(coap_context_t *context, coap_queue_t *rcvd) } } +static void handle_ack_rst(coap_context_t *context, uint8_t msgType, coap_queue_t *sent) { + /* Call application-specific reponse handler when available. If + * not, we must acknowledge confirmable messages. */ + if (context->ack_rst_handler) { + context->ack_rst_handler(context, msgType, sent); + } +} + static inline int #ifdef __GNUC__ handle_locally(coap_context_t *context __attribute__ ((unused)), @@ -1514,28 +1544,51 @@ handle_locally(coap_context_t *context __attribute__ ((unused)), } switch (rcvd->pdu->hdr->type) { + case COAP_MESSAGE_ACK: + /* find transaction in sendqueue to stop retransmission */ + if(coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent)){ + handle_ack_rst(context, COAP_MESSAGE_ACK, sent); + } + + //delete empty messages, this is ACK only message no piggybacked response + if (rcvd->pdu->hdr->code == 0) + goto cleanup; + break; + case COAP_MESSAGE_NON: /* check for unknown critical options */ if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) goto cleanup; break; - case COAP_MESSAGE_RST: - /* We have sent something the receiver disliked, so we remove - * 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)); - // Handing this up, hoping there's enough info to remove an observe if at all possible. - handle_response(context, rcvd); + case COAP_MESSAGE_CON: /* check for unknown critical options */ + if (coap_option_check_critical(context, rcvd->pdu, opt_filter) + == 0) { + /* FIXME: send response only if we have received a request. Otherwise, + * send RST. */ + response = coap_new_error_response(rcvd->pdu, + COAP_RESPONSE_CODE(402), opt_filter); + if (!response) + warn("coap_dispatch: cannot create error reponse\n"); + else { + if (coap_send(context, &rcvd->remote, + response, SEND_NOW) == COAP_INVALID_TID) { + warn("coap_dispatch: error sending reponse\n"); + } + coap_delete_pdu(response); + } + goto cleanup; + } + break; - /* find transaction in sendqueue to stop retransmission */ - coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); + case COAP_MESSAGE_RST: + /* find transaction in sendqueue to stop retransmission */ + if(coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent)){ + handle_ack_rst(context, COAP_MESSAGE_RST, sent); + } + goto cleanup; + break; - if (sent) - coap_handle_rst(context, sent); - goto cleanup; default: debug( "TODO: Need to handle other message types in coap_dispatch"); @@ -1612,10 +1665,12 @@ handle_locally(coap_context_t *context __attribute__ ((unused)), /* 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->hdr)){ handle_request(context, rcvd); - else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) + } + else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)){ handle_response(context, rcvd); + } else { debug("dropped message with invalid code\n"); coap_send_message_type(context, &rcvd->remote, rcvd->pdu, @@ -1623,9 +1678,10 @@ handle_locally(coap_context_t *context __attribute__ ((unused)), } } - // we should not retrying responses..... - cleanup: coap_delete_node(sent); - coap_delete_node(rcvd); + // we should not retry responses..... + cleanup: + coap_delete_node(sent); + coap_delete_node(rcvd); } } diff --git a/csdk/libcoap-4.1.1/net.h b/csdk/libcoap-4.1.1/net.h index 09528c3..116a66b 100644 --- a/csdk/libcoap-4.1.1/net.h +++ b/csdk/libcoap-4.1.1/net.h @@ -51,6 +51,11 @@ extern "C" { #include "pdu.h" #include "coap_time.h" +#define SEND_NOW (1) /*Flag used when sending non-confirmable, ACK and RESET coap pdus*/ +#define SEND_NOW_CON (2) /*Flag used when sending confirmable coap pdu*/ +#define SEND_DELAYED (3) /*Flag used to delay the transmission of coap pdu*/ +#define SEND_RETX (4) /*Flag used to retransmit a confirmable pdu*/ + struct coap_queue_t; typedef struct coap_queue_t { @@ -65,6 +70,8 @@ typedef struct coap_queue_t { coap_tid_t id; /**< unique transaction id */ coap_pdu_t *pdu; /**< the CoAP PDU to send */ + + unsigned char delayedResponse; /**< delayed response flag */ } coap_queue_t; /** Adds node to given queue, ordered by node->t. */ @@ -93,6 +100,10 @@ typedef void (*coap_request_handler_t)(struct coap_context_t *, typedef void (*coap_response_handler_t)(struct coap_context_t *, const coap_queue_t * rcvd); +/** Message handler for ack and rst that is used as call-back in coap_context_t */ +typedef void (*coap_ack_rst_handler_t)(struct coap_context_t *, uint8_t msgType, + const coap_queue_t * sent); + #define COAP_MID_CACHE_SIZE 3 typedef struct { unsigned char flags[COAP_MID_CACHE_SIZE]; @@ -149,6 +160,7 @@ typedef struct coap_context_t { coap_request_handler_t request_handler; coap_response_handler_t response_handler; + coap_ack_rst_handler_t ack_rst_handler; } coap_context_t; /** @@ -177,6 +189,19 @@ coap_register_response_handler(coap_context_t *context, context->response_handler = handler; } +/** + * Registers a new message handler that is called whenever ack or rst + * was received that matches an ongoing transaction. + * + * @param context The context to register the handler for. + * @param handler The handler to register. + */ +static inline void +coap_register_ack_rst_handler(coap_context_t *context, + coap_ack_rst_handler_t handler) { + context->ack_rst_handler = handler; +} + /** * Registers the option type @p type with the given context object @p * ctx. @@ -230,7 +255,6 @@ coap_new_message_id(coap_context_t *context) { /* CoAP stack context must be released with coap_free_context() */ void coap_free_context( coap_context_t *context ); - /** * Sends a confirmed CoAP message to given destination. The memory * that is allocated by pdu will not be released by @@ -241,7 +265,7 @@ void coap_free_context( coap_context_t *context ); * @param pdu The CoAP PDU to send. * @return The message id of the sent message or @c COAP_INVALID_TID on error. */ -coap_tid_t coap_send_confirmed(coap_context_t *context, +coap_tid_t coap_send_confirmed(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu); @@ -266,18 +290,17 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter_t opts); /** - * Sends a non-confirmed CoAP message to given destination. The memory - * that is allocated by pdu will not be released by coap_send(). - * The caller must release the memory. + * Sends a CoAP message to given destination. The memory + * that is allocated by pdu will be released by coap_send(). * * @param context The CoAP context to use. * @param dst The address to send to. * @param pdu The CoAP PDU to send. + * @param flag The flag indicating if the message will be sent with delay * @return The message id of the sent message or @c COAP_INVALID_TID on error. */ -coap_tid_t coap_send(coap_context_t *context, - const coap_address_t *dst, - coap_pdu_t *pdu); + +coap_tid_t coap_send(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu, const uint8_t flag); /** * Sends an error response with code @p code for request @p request to @@ -354,7 +377,7 @@ coap_send_rst(coap_context_t *context, } /** Handles retransmissions of confirmable messages */ -coap_tid_t coap_retransmit( coap_context_t *context, coap_queue_t *node ); +coap_tid_t coap_retransmit( coap_context_t *context, coap_queue_t *node); /** * Reads data from the network and tries to parse as CoAP PDU. On success, 0 is returned diff --git a/csdk/libcoap-4.1.1/pdu.h b/csdk/libcoap-4.1.1/pdu.h index 815e877..7bccb2f 100644 --- a/csdk/libcoap-4.1.1/pdu.h +++ b/csdk/libcoap-4.1.1/pdu.h @@ -22,9 +22,11 @@ extern "C" { #endif /* pre-defined constants that reflect defaults for CoAP */ +// This value is based on the DEFAULT_LEISURE (5 seconds) defined in RFC 7252 +#define MAX_MULTICAST_DELAY_SEC (5) -#define COAP_DEFAULT_RESPONSE_TIMEOUT 2 /* response timeout in seconds */ -#define COAP_DEFAULT_MAX_RETRANSMIT 4 /* max number of retransmissions */ +#define COAP_DEFAULT_RESPONSE_TIMEOUT 3 /* response timeout in seconds */ +#define COAP_DEFAULT_MAX_RETRANSMIT 3 /* max number of retransmissions */ #define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ #define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */ #ifndef COAP_MAX_PDU_SIZE diff --git a/csdk/libcoap-4.1.1/resource.c b/csdk/libcoap-4.1.1/resource.c index 6caf6ec..f723274 100644 --- a/csdk/libcoap-4.1.1/resource.c +++ b/csdk/libcoap-4.1.1/resource.c @@ -71,21 +71,21 @@ coap_free_subscription(coap_subscription_t *subscription) { * Adds Char to Buf if Offset is zero. Otherwise, Char is not written * and Offset is decremented. */ -#define PRINT_WITH_OFFSET(Buf,Offset,Char) \ - if ((Offset) == 0) { \ - (*(Buf)++) = (Char); \ - } else { \ - (Offset)--; \ - } \ +#define PRINT_WITH_OFFSET(Buf,Offset,Char) \ + if ((Offset) == 0) { \ + (*(Buf)++) = (Char); \ + } else { \ + (Offset)--; \ + } \ /** * Adds Char to Buf if Offset is zero and Buf is less than Bufend. */ -#define PRINT_COND_WITH_OFFSET(Buf,Bufend,Offset,Char,Result) { \ - if ((Buf) < (Bufend)) { \ - PRINT_WITH_OFFSET(Buf,Offset,Char); \ - } \ - (Result)++; \ +#define PRINT_COND_WITH_OFFSET(Buf,Bufend,Offset,Char,Result) { \ + if ((Buf) < (Bufend)) { \ + PRINT_WITH_OFFSET(Buf,Offset,Char); \ + } \ + (Result)++; \ } /** @@ -93,11 +93,11 @@ coap_free_subscription(coap_subscription_t *subscription) { * characters are skipped. Output may be truncated to Bufend - Buf * characters. */ -#define COPY_COND_WITH_OFFSET(Buf,Bufend,Offset,Str,Length,Result) { \ - size_t i; \ - for (i = 0; i < (Length); i++) { \ +#define COPY_COND_WITH_OFFSET(Buf,Bufend,Offset,Str,Length,Result) { \ + size_t i; \ + for (i = 0; i < (Length); i++) { \ PRINT_COND_WITH_OFFSET((Buf), (Bufend), (Offset), (Str)[i], (Result)); \ - } \ + } \ } int @@ -159,12 +159,12 @@ match(const str *text, const str *pattern, int match_prefix, int match_substring #if defined(__GNUC__) && defined(WITHOUT_QUERY_FILTER) coap_print_status_t print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, - size_t offset, - coap_opt_t *query_filter __attribute__ ((unused))) { + size_t offset, + coap_opt_t *query_filter __attribute__ ((unused))) { #else /* not a GCC */ coap_print_status_t print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, - size_t offset, coap_opt_t *query_filter) { + size_t offset, coap_opt_t *query_filter) { #endif /* GCC */ coap_resource_t *r; unsigned char *p = buf; @@ -198,14 +198,14 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, if (query_filter) { resource_param.s = COAP_OPT_VALUE(query_filter); while (resource_param.length < COAP_OPT_LENGTH(query_filter) - && resource_param.s[resource_param.length] != '=') + && resource_param.s[resource_param.length] != '=') resource_param.length++; if (resource_param.length < COAP_OPT_LENGTH(query_filter)) { const str *rt_attributes; if (resource_param.length == 4 && - memcmp(resource_param.s, "href", 4) == 0) - flags |= MATCH_URI; + memcmp(resource_param.s, "href", 4) == 0) + flags |= MATCH_URI; for (rt_attributes = _rt_attributes; rt_attributes->s; rt_attributes++) { if (resource_param.length == rt_attributes->length && @@ -217,11 +217,11 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, /* rest is query-pattern */ query_pattern.s = - COAP_OPT_VALUE(query_filter) + resource_param.length + 1; + COAP_OPT_VALUE(query_filter) + resource_param.length + 1; assert((resource_param.length + 1) <= COAP_OPT_LENGTH(query_filter)); query_pattern.length = - COAP_OPT_LENGTH(query_filter) - (resource_param.length + 1); + COAP_OPT_LENGTH(query_filter) - (resource_param.length + 1); if ((query_pattern.s[0] == '/') && ((flags & MATCH_URI) == MATCH_URI)) { query_pattern.s++; @@ -229,9 +229,9 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, } if (query_pattern.length && - query_pattern.s[query_pattern.length-1] == '*') { - query_pattern.length--; - flags |= MATCH_PREFIX; + query_pattern.s[query_pattern.length-1] == '*') { + query_pattern.length--; + flags |= MATCH_PREFIX; } } } @@ -254,13 +254,13 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, #ifndef WITHOUT_QUERY_FILTER if (resource_param.length) { /* there is a query filter */ - if (flags & MATCH_URI) { /* match resource URI */ - if (!match(&r->uri, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0)) - continue; - } else { /* match attribute */ - coap_attr_t *attr; + if (flags & MATCH_URI) { /* match resource URI */ + if (!match(&r->uri, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0)) + continue; + } else { /* match attribute */ + coap_attr_t *attr; str unquoted_val; - attr = coap_find_attr(r, resource_param.s, resource_param.length); + attr = coap_find_attr(r, resource_param.s, resource_param.length); if (!attr) continue; if (attr->value.s[0] == '"') { /* if attribute has a quoted value, remove double quotes */ unquoted_val.length = attr->value.length - 2; @@ -268,15 +268,15 @@ print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, } else { unquoted_val = attr->value; } - if (!(match(&unquoted_val, &query_pattern, + if (!(match(&unquoted_val, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0))) - continue; + continue; } } #endif /* WITHOUT_QUERY_FILTER */ - if (!subsequent_resource) { /* this is the first resource */ + if (!subsequent_resource) { /* this is the first resource */ subsequent_resource = 1; } else { PRINT_COND_WITH_OFFSET(p, bufend, offset, ',', written); @@ -339,8 +339,8 @@ coap_resource_init(const unsigned char *uri, size_t len, int flags) { coap_attr_t * coap_add_attr(coap_resource_t *resource, - const unsigned char *name, size_t nlen, - const unsigned char *val, size_t vlen, + const unsigned char *name, size_t nlen, + const unsigned char *val, size_t vlen, int flags) { coap_attr_t *attr; @@ -381,7 +381,7 @@ coap_add_attr(coap_resource_t *resource, coap_attr_t * coap_find_attr(coap_resource_t *resource, - const unsigned char *name, size_t nlen) { + const unsigned char *name, size_t nlen) { coap_attr_t *attr; if (!resource || !name) @@ -394,7 +394,7 @@ coap_find_attr(coap_resource_t *resource, attr = list_item_next(attr)) { #endif /* WITH_CONTIKI */ if (attr->name.length == nlen && - memcmp(attr->name.s, name, nlen) == 0) + memcmp(attr->name.s, name, nlen) == 0) return attr; } @@ -509,7 +509,7 @@ coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { /* if you think you can outspart the compiler and speed things up by (eg by * casting to uint32* and comparing alues), increment this counter: 1 */ if (memcmp(key, resource->key, sizeof(coap_key_t)) == 0) - return resource; + return resource; } return NULL; #else @@ -525,7 +525,7 @@ coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { ptr2 = (coap_resource_t *)resource_storage.mem; for (i = 0; i < resource_storage.num; ++i) { if (resource_storage.count[i] && - (memcmp(ptr2->key, key, sizeof(coap_key_t)) == 0)) + (memcmp(ptr2->key, key, sizeof(coap_key_t)) == 0)) return (coap_resource_t *)ptr2; ++ptr2; } @@ -536,7 +536,7 @@ coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { coap_print_status_t coap_print_link(const coap_resource_t *resource, - unsigned char *buf, size_t *len, size_t *offset) { + unsigned char *buf, size_t *len, size_t *offset) { unsigned char *p = buf; const unsigned char *bufend = buf + *len; coap_attr_t *attr; @@ -548,7 +548,7 @@ coap_print_link(const coap_resource_t *resource, PRINT_COND_WITH_OFFSET(p, bufend, *offset, '/', *len); COPY_COND_WITH_OFFSET(p, bufend, *offset, - resource->uri.s, resource->uri.length, *len); + resource->uri.s, resource->uri.length, *len); PRINT_COND_WITH_OFFSET(p, bufend, *offset, '>', *len); @@ -562,13 +562,13 @@ coap_print_link(const coap_resource_t *resource, PRINT_COND_WITH_OFFSET(p, bufend, *offset, ';', *len); COPY_COND_WITH_OFFSET(p, bufend, *offset, - attr->name.s, attr->name.length, *len); + attr->name.s, attr->name.length, *len); if (attr->value.s) { PRINT_COND_WITH_OFFSET(p, bufend, *offset, '=', *len); COPY_COND_WITH_OFFSET(p, bufend, *offset, - attr->value.s, attr->value.length, *len); + attr->value.s, attr->value.length, *len); } } @@ -587,7 +587,7 @@ coap_print_link(const coap_resource_t *resource, #ifndef WITHOUT_OBSERVE coap_subscription_t * coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, - const str *token) { + const str *token) { coap_subscription_t *s; assert(resource); @@ -596,8 +596,8 @@ coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, for (s = (coap_subscription_t*)list_head(resource->subscribers); s; s = (coap_subscription_t*)list_item_next(s)) { if (coap_address_equals(&s->subscriber, peer) - && (!token || (token->length == s->token_length - && memcmp(token->s, s->token, token->length) == 0))) + && (!token || (token->length == s->token_length + && memcmp(token->s, s->token, token->length) == 0))) return s; } @@ -606,8 +606,8 @@ coap_find_observer(coap_resource_t *resource, const coap_address_t *peer, coap_subscription_t * coap_add_observer(coap_resource_t *resource, - const coap_address_t *observer, - const str *token) { + const coap_address_t *observer, + const str *token) { coap_subscription_t *s; assert(observer); @@ -642,7 +642,7 @@ coap_add_observer(coap_resource_t *resource, void coap_touch_observer(coap_context_t *context, const coap_address_t *observer, - const str *token) { + const str *token) { coap_resource_t *r; coap_subscription_t *s; @@ -664,7 +664,7 @@ coap_touch_observer(coap_context_t *context, const coap_address_t *observer, if (resource_storage.count[i]) { s = coap_find_observer(r, observer, token); if (s) { - s->fail_cnt = 0; + s->fail_cnt = 0; } } } @@ -673,7 +673,7 @@ coap_touch_observer(coap_context_t *context, const coap_address_t *observer, void coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer, - const str *token) { + const str *token) { coap_subscription_t *s; s = coap_find_observer(resource, observer, token); @@ -697,8 +697,8 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { /* retrieve GET handler, prepare response */ h = r->handler[COAP_REQUEST_GET - 1]; - assert(h); /* we do not allow subscriptions if no - * GET handler is defined */ + assert(h); /* we do not allow subscriptions if no + * GET handler is defined */ for (obs = (coap_subscription_t*)list_head(r->subscribers); obs; obs = (coap_subscription_t*)list_item_next(obs)) { @@ -713,16 +713,16 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { if (!response) { obs->dirty = 1; r->partiallydirty = 1; - debug("coap_check_notify: pdu init failed, resource stays partially dirty\n"); - continue; + debug("coap_check_notify: pdu init failed, resource stays partially dirty\n"); + continue; } if (!coap_add_token(response, obs->token_length, obs->token)) { obs->dirty = 1; r->partiallydirty = 1; - debug("coap_check_notify: cannot add token, resource stays partially dirty\n"); - coap_delete_pdu(response); - continue; + debug("coap_check_notify: cannot add token, resource stays partially dirty\n"); + coap_delete_pdu(response); + continue; } token.length = obs->token_length; @@ -730,26 +730,26 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { response->hdr->id = coap_new_message_id(context); if (obs->non && obs->non_cnt < COAP_OBS_MAX_NON) { - response->hdr->type = COAP_MESSAGE_NON; + response->hdr->type = COAP_MESSAGE_NON; } else { - response->hdr->type = COAP_MESSAGE_CON; + response->hdr->type = COAP_MESSAGE_CON; } /* fill with observer-specific data */ h(context, r, &obs->subscriber, NULL, &token, response); if (response->hdr->type == COAP_MESSAGE_CON) { - tid = coap_send_confirmed(context, &obs->subscriber, response); - obs->non_cnt = 0; + tid = coap_send(context, &obs->subscriber, response, SEND_NOW_CON); + obs->non_cnt = 0; } else { - tid = coap_send(context, &obs->subscriber, response); - obs->non_cnt++; + tid = coap_send(context, &obs->subscriber, response, SEND_NOW); + obs->non_cnt++; } if (COAP_INVALID_TID == tid || response->hdr->type != COAP_MESSAGE_CON) - coap_delete_pdu(response); + coap_delete_pdu(response); if (COAP_INVALID_TID == tid) { - debug("coap_check_notify: sending failed, resource stays partially dirty\n"); + debug("coap_check_notify: sending failed, resource stays partially dirty\n"); obs->dirty = 1; r->partiallydirty = 1; } @@ -799,50 +799,50 @@ coap_check_notify(coap_context_t *context) { */ static void coap_remove_failed_observers(coap_context_t *context, - coap_resource_t *resource, - const coap_address_t *peer, - const str *token) { + coap_resource_t *resource, + const coap_address_t *peer, + const str *token) { coap_subscription_t *obs; for (obs = (coap_subscription_t*)list_head(resource->subscribers); obs; obs = (coap_subscription_t*)list_item_next(obs)) { if (coap_address_equals(peer, &obs->subscriber) && - token->length == obs->token_length && - memcmp(token->s, obs->token, token->length) == 0) { + token->length == obs->token_length && + memcmp(token->s, obs->token, token->length) == 0) { /* count failed notifies and remove when * COAP_MAX_FAILED_NOTIFY is reached */ if (obs->fail_cnt < COAP_OBS_MAX_FAIL) - obs->fail_cnt++; + obs->fail_cnt++; else { - list_remove(resource->subscribers, obs); - obs->fail_cnt = 0; + list_remove(resource->subscribers, obs); + obs->fail_cnt = 0; #ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { + if (LOG_DEBUG <= coap_get_log_level()) { #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 40 #endif - unsigned char addr[INET6_ADDRSTRLEN+8]; + unsigned char addr[INET6_ADDRSTRLEN+8]; - if (coap_print_addr(&obs->subscriber, addr, INET6_ADDRSTRLEN+8)) - debug("** removed observer %s\n", addr); - } + if (coap_print_addr(&obs->subscriber, addr, INET6_ADDRSTRLEN+8)) + debug("** removed observer %s\n", addr); + } #endif - coap_cancel_all_messages(context, &obs->subscriber, - obs->token, obs->token_length); + coap_cancel_all_messages(context, &obs->subscriber, + obs->token, obs->token_length); - COAP_FREE_TYPE(subscription, obs); + COAP_FREE_TYPE(subscription, obs); } } - break; /* break loop if observer was found */ + break; /* break loop if observer was found */ } } void coap_handle_failed_notify(coap_context_t *context, - const coap_address_t *peer, - const str *token) { + const coap_address_t *peer, + const str *token) { coap_resource_t *r; #ifndef WITH_CONTIKI @@ -853,7 +853,7 @@ coap_handle_failed_notify(coap_context_t *context, coap_resource_t *tmp; HASH_ITER(hh, context->resources, r, tmp) { #endif - coap_remove_failed_observers(context, r, peer, token); + coap_remove_failed_observers(context, r, peer, token); } #else /* WITH_CONTIKI */ int i; diff --git a/csdk/occoap/include/occoap.h b/csdk/occoap/include/occoap.h index 517475d..af5ebe7 100644 --- a/csdk/occoap/include/occoap.h +++ b/csdk/occoap/include/occoap.h @@ -34,11 +34,6 @@ // Typedefs //----------------------------------------------------------------------------- -typedef enum { - OC_COAP_OK = 0, - OC_COAP_ERR -} OCCoAPResult; - //----------------------------------------------------------------------------- // Function Prototypes //----------------------------------------------------------------------------- @@ -57,7 +52,7 @@ typedef enum { * 0 - success * TBD - TBD error */ -int OCInitCoAP(const char *address, uint16_t port, OCMode mode); +OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode); /** * Discover OC resources @@ -72,7 +67,7 @@ int OCInitCoAP(const char *address, uint16_t port, OCMode mode); * 0 - success * TBD - TBD error */ -int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token, +OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token, const char *Uri, const char *payload); @@ -81,7 +76,7 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke * * @return 0 - success, else - TBD error */ -int OCStopCoAP(); +OCStackResult OCStopCoAP(); /** * Called in main loop of CoAP client or server. Allows low-level CoAP processing of @@ -89,17 +84,17 @@ int OCStopCoAP(); * * @return 0 - success, else - TBD error */ -int OCProcessCoAP(); +OCStackResult OCProcessCoAP(); OCCoAPToken * OCGenerateCoAPToken(); /** * Initiate sending of CoAP messages. Example: server uses it to send observe messages * - * @return OC_COAP_OK - success, OC_COAP_ERR + * @return 0 - success, else - TBD error */ -int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode, - OCQualityOfService qos, OCCoAPToken * token, - const char *payload, uint32_t seqNum); +OCStackResult OCSendCoAPNotification (OCDevAddr *dstAddr, OCStackResult result, + OCQualityOfService qos, OCCoAPToken * token, + unsigned char *payload, uint32_t seqNum); #endif /* OCCOAP_H_ */ diff --git a/csdk/occoap/include/occoaphelper.h b/csdk/occoap/include/occoaphelper.h index 4641b0d..115fb17 100644 --- a/csdk/occoap/include/occoaphelper.h +++ b/csdk/occoap/include/occoaphelper.h @@ -44,9 +44,14 @@ OCStackResult CoAPToOCResponseCode(uint8_t coapCode); // Internal function to generate a coap pdu based on passed parameters coap_pdu_t * GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id, - size_t tokenLength, uint8_t * token, unsigned char * payloadJSON, + OCCoAPToken * token, unsigned char * payloadJSON, coap_list_t *options); +// Internal function to send a coap pdu, it also handles NON and CON +OCStackResult +SendCoAPPdu(coap_context_t * gCoAPCtx, coap_address_t* dst, coap_pdu_t * pdu, + uint8_t delayFlag); + // Call back function used by libcoap to order option in coap pdu int OrderOptions(void *a, void *b); @@ -56,25 +61,46 @@ CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data); // Internal function to create OCRequest struct at the server from a received coap pdu -OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest, - OCRequest * * requestLoc, unsigned char * uriBuf, - unsigned char * queryBuf); +OCStackResult FormOCRequest(OCRequest * * requestLoc, OCQualityOfService qos, + unsigned char * uriBuf, OCObserveReq * observeReq, + OCEntityHandlerRequest * entityHandlerRequest); // Internal function to create OCEntityHandlerRequest at the server from a received coap pdu -OCStackResult FormOCEntityHandlerRequest(const coap_queue_t * rcvdRequest, - OCEntityHandlerRequest * * entityHandlerRequestLoc, - unsigned char * bufRes, unsigned char * query); +OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * * entityHandlerRequestLoc, + OCMethod method, unsigned char * resBuf, unsigned char * reqBuf, + unsigned char * queryBuf); + +// Internal function to retrieve Uri and Query from received coap pdu +OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf, + unsigned char * queryBuf, uint8_t * * obsOptionLoc, unsigned char * * payloadLoc); // Internal function to retrieve a Token from received coap pdu -OCStackResult RetrieveOCCoAPToken(const coap_queue_t * rcvdRequest, +OCStackResult RetrieveOCCoAPToken(const coap_pdu_t * pdu, OCCoAPToken * * rcvdTokenLoc); +// Internal function to create OCObserveReq at the server +OCStackResult FormOCObserveReq(OCObserveReq ** observeReqLoc, uint8_t obsOption, + OCDevAddr * remote, OCCoAPToken * rcvdToken); + // Internal function to create OCResponse struct at the client from a received coap pdu -OCStackResult FormOCResponse(const coap_queue_t * rcvdResponse, - OCResponse * * responseLoc); +OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode, + OCClientResponse * clientResponse); // Internal function to create OCClientResponse struct at the client from a received coap pdu -OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse, - OCClientResponse * * clientResponseLoc); +OCStackResult FormOCClientResponse(OCClientResponse * * clientResponseLoc, + OCStackResult result, OCDevAddr * remote, uint32_t seqNum, + const unsigned char * resJSONPayload); + +// Internal function to handle the queued pdus in the send queue +void HandleSendQueue(coap_context_t * gCoAPCtx); + +// Internal function to form the standard response option list +OCStackResult FormResponseOptList(coap_list_t * * optList, uint8_t * addMediaType, + uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr); + +// Internal function to retransmit a queue +OCStackResult ReTXCoAPQueue(coap_context_t * ctx, coap_queue_t * queue); +// Internal function called when sending/retransmission fails +OCStackResult HandleFailedCommunication(coap_context_t * ctx, coap_queue_t * queue); #endif /* OCCOAPHELPER_H_ */ diff --git a/csdk/occoap/src/occoap.c b/csdk/occoap/src/occoap.c index c982608..307432b 100644 --- a/csdk/occoap/src/occoap.c +++ b/csdk/occoap/src/occoap.c @@ -43,8 +43,6 @@ #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg); goto exit;} } #define BUF_SIZE (64) -#define BUF_SIZE_ENCODE_OPTION (3) -#define BUF_SIZE_PORT (2) //============================================================================= // Private Variables @@ -72,6 +70,47 @@ OCCoAPToken * OCGenerateCoAPToken() return token; } +//This function is called back by libcoap when ack or rst are received +static void HandleCoAPAckRst(struct coap_context_t * ctx, uint8_t msgType, + const coap_queue_t * sentQueue){ + + // silence warnings + (void) ctx; + + OCStackResult result = OC_STACK_ERROR; + OCCoAPToken * sentToken = NULL; + uint8_t * observeOption = NULL; + coap_pdu_t * sentPdu = sentQueue->pdu; + + // fill the buffers of Uri and Query + result = ParseCoAPPdu(sentPdu, NULL, NULL, &observeOption, NULL); + VERIFY_SUCCESS(result, OC_STACK_OK); + + // fill OCCoAPToken structure + result = RetrieveOCCoAPToken(sentPdu, &sentToken); + VERIFY_SUCCESS(result, OC_STACK_OK); + + if(msgType == COAP_MESSAGE_RST){ + // now the observer should be deleted + result = OCObserverStatus(sentToken, OC_OBSERVER_NOT_INTERESTED); + if(result == OC_STACK_OBSERVER_REMOVED){ + OC_LOG_V(DEBUG, TAG, "Received RST, removing all queues associated with Token %d bytes",sentToken->tokenLength); + OC_LOG_BUFFER(INFO, TAG, sentToken->token, sentToken->tokenLength); + coap_cancel_all_messages(ctx, &sentQueue->remote, sentToken->token, + sentToken->tokenLength); + } + }else if(observeOption && msgType == COAP_MESSAGE_ACK){ + OC_LOG_V(DEBUG, TAG, "Received ACK, for Token %d bytes",sentToken->tokenLength); + OC_LOG_BUFFER(INFO, TAG, sentToken->token, sentToken->tokenLength); + // now the observer is still interested + OCObserverStatus(sentToken, OC_OBSERVER_STILL_INTERESTED); + } + + exit: + OCFree(sentToken); + OCFree(observeOption); +} + //This function is called back by libcoap when a request is received static void HandleCoAPRequests(struct coap_context_t *ctx, const coap_queue_t * rcvdRequest) @@ -79,35 +118,52 @@ static void HandleCoAPRequests(struct coap_context_t *ctx, // silence warnings (void) ctx; - OCStackResult result; + OCStackResult result = OC_STACK_ERROR; + OCStackResult responseResult = OC_STACK_ERROR; OCRequest * request = NULL; OCEntityHandlerRequest * entityHandlerRequest = NULL; OCCoAPToken * rcvdToken = NULL; + OCObserveReq * rcvdObsReq = NULL; + coap_pdu_t * sendPdu = NULL; + coap_list_t *optList = NULL; + uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON; + uint32_t maxAge = 0x2ffff; unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 }; unsigned char rcvdQuery[MAX_QUERY_LENGTH] = { 0 }; - unsigned char bufRes[MAX_RESPONSE_LENGTH] = { 0 }; + uint8_t * rcvObserveOption = NULL; + unsigned char * bufReqPayload = NULL; + uint8_t observeOption = OC_RESOURCE_NO_OBSERVE; - coap_list_t *optList = NULL; - unsigned char tempBuf[BUF_SIZE_ENCODE_OPTION]; - coap_pdu_t *pdu; - coap_tid_t tid = COAP_INVALID_TID; + coap_pdu_t * recvPdu = rcvdRequest->pdu; - // fill OCRequest structure - result = FormOCRequest(rcvdRequest, &request, rcvdUri, rcvdQuery); + // fill the buffers of Uri and Query + result = ParseCoAPPdu(recvPdu, rcvdUri, rcvdQuery, &rcvObserveOption, &bufReqPayload); VERIFY_SUCCESS(result, OC_STACK_OK); + if(rcvObserveOption){ + observeOption = (uint8_t)(*rcvObserveOption); + } - // fill OCEntityHandlerRequest structure - result = FormOCEntityHandlerRequest(rcvdRequest, &entityHandlerRequest, - bufRes, rcvdQuery); + // fill OCCoAPToken structure + result = RetrieveOCCoAPToken(recvPdu, &rcvdToken); VERIFY_SUCCESS(result, OC_STACK_OK); - // fill OCCoAPToken structure - result = RetrieveOCCoAPToken(rcvdRequest, &rcvdToken); + // fill OCEntityHandlerRequest structure + result = FormOCEntityHandlerRequest(&entityHandlerRequest, + (recvPdu->hdr->code == COAP_REQUEST_GET) ? + OC_REST_GET : OC_REST_PUT, bufRes, bufReqPayload, rcvdQuery); VERIFY_SUCCESS(result, OC_STACK_OK); - request->entityHandlerRequest = entityHandlerRequest; + // fill OCObserveReq + result = FormOCObserveReq(&rcvdObsReq, observeOption, + (OCDevAddr *)&(rcvdRequest->remote), rcvdToken); + VERIFY_SUCCESS(result, OC_STACK_OK); + + // fill OCRequest structure + result = FormOCRequest(&request, (recvPdu->hdr->type == COAP_MESSAGE_CON) ? + OC_CONFIRMABLE : OC_NON_CONFIRMABLE, rcvdUri, rcvdObsReq, entityHandlerRequest); + VERIFY_SUCCESS(result, OC_STACK_OK); OC_LOG_V(INFO, TAG, " Receveid uri: %s", request->resourceUrl); OC_LOG_V(INFO, TAG, " Receveid query: %s", entityHandlerRequest->query); @@ -118,49 +174,49 @@ static void HandleCoAPRequests(struct coap_context_t *ctx, OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength); // process the request - result = HandleStackRequests(request); + responseResult = HandleStackRequests(request); - if (result == OC_STACK_OK) - { - OC_LOG_V(INFO, TAG, "Response from ocstack: %s", request->entityHandlerRequest->resJSONPayload); - // need to build the response PDU - coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(tempBuf, COAP_MEDIATYPE_APPLICATION_JSON), - tempBuf), OrderOptions); - coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_MAXAGE, - coap_encode_var_bytes(tempBuf, 0x2ffff), tempBuf), - OrderOptions); - } - - // generate the pdu, if the request was CON, then the response is ACK, otherwire NON - pdu = GenerateCoAPPdu( - rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON ? - COAP_MESSAGE_ACK : COAP_MESSAGE_NON, - OCToCoAPResponseCode(result), rcvdRequest->pdu->hdr->id, - rcvdToken->tokenLength, rcvdToken->token, - request->entityHandlerRequest->resJSONPayload, optList); - VERIFY_NON_NULL(pdu); - coap_show_pdu(pdu); + TODO("we should return the same registration option; however, this will confuse the receiver \ + whether it is a sequence number or registration option!------------"); + OC_LOG_V(INFO, TAG, "Response from ocstack: %s", request->entityHandlerRequest->resJSONPayload); - if (pdu->hdr->type != COAP_MESSAGE_NON - || (pdu->hdr->code >= 64 && !coap_is_mcast(&rcvdRequest->local))) + switch(responseResult) { - tid = coap_send(gCoAPCtx, &rcvdRequest->remote, pdu); + case OC_STACK_OBSERVER_ADDED: + observeOption = OC_RESOURCE_OBSERVE_REGISTER; + result = FormResponseOptList(&optList, &mediaType, &maxAge, 0, NULL); + break; + case OC_STACK_OBSERVER_REMOVED: + observeOption = OC_RESOURCE_OBSERVE_DEREGISTER; + result = FormResponseOptList(&optList, &mediaType, &maxAge, 0, NULL); + break; + case OC_STACK_OK: + default: + result = FormResponseOptList(&optList, &mediaType, &maxAge, 0, NULL); + break; } + VERIFY_SUCCESS(result, OC_STACK_OK); - OC_LOG_V(INFO, TAG, "TID %d", tid); - // unlike stock libcoap (deletion in handle_request in net.c), we are deleting the response here - // in the future, the response might be queued for SLOW resources - if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) - { - OC_LOG(INFO, TAG, PCF("Deleting PDU")); - coap_delete_pdu(pdu); + // generate the pdu, if the request was CON, then the response is ACK, otherwire NON + sendPdu = GenerateCoAPPdu( + (rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON) ? + COAP_MESSAGE_ACK : COAP_MESSAGE_NON, + OCToCoAPResponseCode(responseResult), rcvdRequest->pdu->hdr->id, + rcvdToken, + request->entityHandlerRequest->resJSONPayload, optList); + VERIFY_NON_NULL(sendPdu); + coap_show_pdu(sendPdu); + + if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu, rcvdRequest->delayedResponse) + != OC_STACK_OK){ + OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu")); } exit: - coap_delete_list(optList); + OCFree(rcvObserveOption); OCFree(rcvdToken); OCFree(entityHandlerRequest); + OCFree(rcvdObsReq); OCFree(request); } @@ -168,99 +224,89 @@ exit: static void HandleCoAPResponses(struct coap_context_t *ctx, const coap_queue_t * rcvdResponse) { OCResponse * response = NULL; - OCCoAPToken * token = NULL; + OCCoAPToken * rcvdToken = NULL; OCClientResponse * clientResponse = NULL; ClientCB * cbNode = NULL; - OCStackResult result; + unsigned char * bufRes = NULL; + uint8_t * rcvObserveOption; + uint32_t sequenceNumber = 0; + OCStackResult result = OC_STACK_ERROR; + coap_pdu_t *sendPdu = NULL; + //coap_list_t *optList = NULL; + //uint8_t deregisterObserveOption = OC_RESOURCE_OBSERVE_DEREGISTER; VERIFY_NON_NULL(ctx); VERIFY_NON_NULL(rcvdResponse); + coap_pdu_t * recvPdu = rcvdResponse->pdu; - // TODO: we should check if we are interested in the token - // Now, just accept NON packets + result = ParseCoAPPdu(recvPdu, NULL, NULL, &rcvObserveOption, &bufRes); + VERIFY_SUCCESS(result, OC_STACK_OK); - if (rcvdResponse->pdu->hdr->type == COAP_MESSAGE_NON) - { - // fill OCResponse structure - result = FormOCResponse(rcvdResponse, &response); - VERIFY_SUCCESS(result, OC_STACK_OK); + if(rcvObserveOption){ + sequenceNumber = *((uint32_t *) rcvObserveOption); + } - // fill OCCoAPToken structure - result = RetrieveOCCoAPToken(rcvdResponse, &token); - VERIFY_SUCCESS(result, OC_STACK_OK); + OC_LOG_V(DEBUG, TAG, "The sequence number of this response %d", sequenceNumber); + OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes); - // fill OCClientResponse structure - result = FormOCClientResponse(rcvdResponse, &clientResponse); - VERIFY_SUCCESS(result, OC_STACK_OK); + // fill OCCoAPToken structure + result = RetrieveOCCoAPToken(recvPdu, &rcvdToken); + VERIFY_SUCCESS(result, OC_STACK_OK); + OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken->tokenLength); + OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength); - // put everything together - response->clientResponse = clientResponse; + // fill OCClientResponse structure + result = FormOCClientResponse(&clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code), + (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes); + VERIFY_SUCCESS(result, OC_STACK_OK); - cbNode = GetClientCB(token, NULL); + cbNode = GetClientCB(rcvdToken, NULL); - OC_LOG_V(INFO, TAG, " Received a response HandleCoAPResponses in occoap: %s", - response->clientResponse->resJSONPayload); - OC_LOG_V(INFO, TAG,"Token received %d bytes", token->tokenLength); - OC_LOG_BUFFER(INFO, TAG, token->token, - token->tokenLength); + // fill OCResponse structure + result = FormOCResponse(&response, cbNode, clientResponse); + VERIFY_SUCCESS(result, OC_STACK_OK); - if(cbNode && (cbNode->method == OC_REST_OBSERVE || cbNode->method == OC_REST_OBSERVE_ALL)) - { - if(clientResponse->sequenceNumber != 0) - { - if(cbNode->method == OC_REST_OBSERVE && (clientResponse->sequenceNumber <= cbNode->sequenceNumber)) - { - OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \ - Ignoring Incoming:%d Against Current:%d.", - clientResponse->sequenceNumber, cbNode->sequenceNumber); - return; - } - else - { - cbNode->sequenceNumber = clientResponse->sequenceNumber; - } + if(cbNode) + { + if(clientResponse->sequenceNumber != 0 && + (cbNode->method == OC_REST_OBSERVE || + cbNode->method == OC_REST_OBSERVE_ALL)){ + OC_LOG(INFO, TAG, PCF("Received an observe notification")); + if(recvPdu->hdr->type == COAP_MESSAGE_CON){ + sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, + recvPdu->hdr->id, NULL, NULL, NULL); + VERIFY_NON_NULL(sendPdu); + result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, + sendPdu, 0); } - } - else if(!cbNode && clientResponse && clientResponse->sequenceNumber != 0) // Ensure that this is an observe notification. - { - - coap_pdu_t *pdu; - coap_list_t *optList = NULL; - coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE, - strlen(OC_RESOURCE_OBSERVE_DEREGISTER), (unsigned char *)OC_RESOURCE_OBSERVE_DEREGISTER), OrderOptions); - - pdu = GenerateCoAPPdu(COAP_MESSAGE_NON, COAP_REQUEST_GET, - coap_new_message_id(gCoAPCtx), token->tokenLength, token->token, - (unsigned char*)"", optList); - VERIFY_NON_NULL(pdu); - coap_tid_t tid; - tid = coap_send(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, pdu); - - OC_LOG_V(INFO, TAG, "TID %d", tid); - if (tid != COAP_INVALID_TID) - { - OC_LOG(INFO, TAG, PCF("Deleting PDU")); - coap_delete_pdu(pdu); + if(cbNode->method == OC_REST_OBSERVE && + clientResponse->sequenceNumber <= cbNode->sequenceNumber){ + OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \ + Ignoring Incoming:%d Against Current:%d.", + clientResponse->sequenceNumber, cbNode->sequenceNumber); + goto exit; } - else - { - OC_LOG(INFO, TAG, PCF("Keeping PDU, we should handle the retry of this pdu")); + if(clientResponse->sequenceNumber > cbNode->sequenceNumber){ + cbNode->sequenceNumber = clientResponse->sequenceNumber; } - goto exit; } - response->cbNode = cbNode; - response->clientResponse->result = CoAPToOCResponseCode(rcvdResponse->pdu->hdr->code); HandleStackResponses(response); + }else if(!cbNode && clientResponse->sequenceNumber != 0){ + OC_LOG(INFO, TAG, PCF("Received an observe notification, but I do not have callback \ + ------------ sending RESET")); + sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0, + recvPdu->hdr->id, NULL, NULL, NULL); + VERIFY_NON_NULL(sendPdu); + result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu, 0); + VERIFY_SUCCESS(result, OC_STACK_OK); + }else{ + // TODO: we should send a RST here and.. } - else - { - OC_LOG(DEBUG, TAG, PCF("Do not accept other than NON in HandleCoAPResponses")); - } - -exit: - OCFree(response); - OCFree(token); - OCFree(clientResponse); + exit: + OCFree(rcvObserveOption); + OCFree(rcvdToken); + OCFree(clientResponse); + OCFree(response); } //============================================================================= @@ -281,9 +327,9 @@ exit: * 0 - success * TBD - TBD error */ -int OCInitCoAP(const char *address, uint16_t port, OCMode mode) { +OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) { - int ret = OC_COAP_ERR; + int ret = OC_STACK_ERROR; TODO ("Below should go away and be replaced by OC_LOG"); coap_log_t log_level = (coap_log_t)(LOG_DEBUG + 1); @@ -299,9 +345,13 @@ int OCInitCoAP(const char *address, uint16_t port, OCMode mode) { { if (!ParseIPv4Address((unsigned char *) address, ipAddr)) { - return OC_COAP_ERR; + ret = OC_STACK_ERROR; + goto exit; } OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]); + + OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port, + &devAddr); } OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port, @@ -316,13 +366,15 @@ int OCInitCoAP(const char *address, uint16_t port, OCMode mode) { coap_join_wellknown_group(gCoAPCtx, (coap_address_t* )&mcastAddr), 0); } + coap_register_request_handler(gCoAPCtx, HandleCoAPRequests); coap_register_response_handler(gCoAPCtx, HandleCoAPResponses); + coap_register_ack_rst_handler(gCoAPCtx, HandleCoAPAckRst); - ret = OC_COAP_OK; + ret = OC_STACK_OK; exit: - if (ret != OC_COAP_OK) + if (ret != OC_STACK_OK) { OCStopCoAP(); } @@ -342,23 +394,23 @@ exit: * 0 - success * TBD - TBD error */ -int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token, +OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token, const char *Uri, const char *payload) { - int ret = OC_COAP_ERR; + int ret = OC_STACK_ERROR; coap_pdu_t *pdu = NULL; coap_uri_t uri; OCDevAddr dst; uint8_t ipAddr[4] = { 0 }; coap_list_t *optList = NULL; - unsigned char portBuf[BUF_SIZE_PORT]; size_t buflen; unsigned char _buf[BUF_SIZE]; unsigned char *buf = _buf; int res; uint8_t coapMsgType; uint8_t coapMethod; + uint8_t observeOption; OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource")); @@ -376,10 +428,8 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke //create appropriate coap options if (uri.port != COAP_DEFAULT_PORT) { - coap_insert(&optList, - CreateNewOptionNode(COAP_OPTION_URI_PORT, - coap_encode_var_bytes(portBuf, uri.port), portBuf), - OrderOptions); + coap_insert(&optList, CreateNewOptionNode( COAP_OPTION_URI_PORT, + sizeof(uri.port), (uint8_t *)&(uri.port)), OrderOptions); } if (uri.path.length) { @@ -416,13 +466,13 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port); OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s); } - coapMsgType = COAP_MESSAGE_NON; + coapMsgType = COAP_MESSAGE_NON; // Decide message type if (qos == OC_CONFIRMABLE) { coapMsgType = COAP_MESSAGE_CON; - OC_LOG(FATAL, TAG, PCF("qos == OC_CONFIRMABLE is not supported in OCDoCoAPResource")); } + // Decide method type switch (method) { case OC_REST_GET: @@ -434,84 +484,67 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke case OC_REST_OBSERVE_ALL: case OC_REST_OBSERVE: coapMethod = COAP_REQUEST_GET; + observeOption = OC_RESOURCE_OBSERVE_REGISTER; coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE, - strlen(OC_RESOURCE_OBSERVE_REGISTER), (unsigned char *)OC_RESOURCE_OBSERVE_REGISTER), OrderOptions); + sizeof(observeOption), &observeOption), OrderOptions); break; default: - coapMethod = 0; + coapMethod = OC_REST_NOMETHOD; OC_LOG(FATAL, TAG, PCF("OCDoCoAPResource only supports GET, PUT, & OBSERVE methods")); break; } VERIFY_NON_NULL(gCoAPCtx); pdu = GenerateCoAPPdu(coapMsgType, coapMethod, - coap_new_message_id(gCoAPCtx), token->tokenLength, token->token, + coap_new_message_id(gCoAPCtx), token, (unsigned char*) payload, optList); VERIFY_NON_NULL(pdu); - coap_send(gCoAPCtx, (coap_address_t*) &dst, pdu); - - //OC_LOG_V(INFO, TAG, "TID %d", tid); - TODO ("Once CON implementation is available, pdu should be saved until ACK is received"); - //if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) - { - OC_LOG(INFO, TAG, PCF("Deleting PDU")); - coap_delete_pdu(pdu); - pdu = NULL; - } - - ret = OC_COAP_OK; + ret = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &dst, pdu, 0); exit: - coap_delete_list(optList); - if (ret != OC_COAP_OK) + if (ret!= OC_STACK_OK) { - coap_delete_pdu(pdu); + OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu")); } return ret; } -int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode, +OCStackResult OCSendCoAPNotification (OCDevAddr *dstAddr, OCStackResult result, OCQualityOfService qos, OCCoAPToken * token, - const char *payload, uint32_t seqNum) + unsigned char *payload, uint32_t seqNum) { coap_list_t *optList = NULL; - coap_pdu_t *pdu; - unsigned char tempBuf[BUF_SIZE_ENCODE_OPTION]; uint8_t coapMsgType = COAP_MESSAGE_NON; - coap_tid_t tid = COAP_INVALID_TID; - - OC_LOG(INFO, TAG, PCF("Entering OCCoAPSendMessage")); - - OC_LOG_V(INFO, TAG, "OCStack payload: %s", payload); - coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE, - coap_encode_var_bytes(tempBuf, COAP_MEDIATYPE_APPLICATION_JSON), - tempBuf), OrderOptions); - coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_MAXAGE, - coap_encode_var_bytes(tempBuf, 0x2ffff), tempBuf), OrderOptions); - coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE, - coap_encode_var_bytes(tempBuf, seqNum), tempBuf), OrderOptions); - - pdu = GenerateCoAPPdu (coapMsgType, OCToCoAPResponseCode(msgCode), - coap_new_message_id(gCoAPCtx), token->tokenLength, token->token, - (unsigned char*) payload, optList); - VERIFY_NON_NULL(pdu); - coap_show_pdu(pdu); + uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON; + uint32_t maxAge = 0x2ffff; + coap_pdu_t *sendPdu; - tid = coap_send(gCoAPCtx, (coap_address_t*)dstAddr, pdu); - OC_LOG_V(INFO, TAG, "TID %d", tid); - if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) - { - OC_LOG(INFO, TAG, PCF("Deleting PDU")); - coap_delete_pdu(pdu); - pdu = NULL; + OC_LOG(INFO, TAG, PCF("Entering OCSendCoAPNotification")); + + coapMsgType = COAP_MESSAGE_NON; + // Decide message type + if (qos == OC_CONFIRMABLE) { + coapMsgType = COAP_MESSAGE_CON; } - return OC_COAP_OK; + result = FormResponseOptList(&optList, &mediaType, &maxAge, 4, (uint8_t *)(&seqNum)); + VERIFY_SUCCESS(result, OC_STACK_OK); + sendPdu = GenerateCoAPPdu( + coapMsgType == COAP_MESSAGE_CON ? COAP_MESSAGE_CON : COAP_MESSAGE_NON, + OCToCoAPResponseCode(result), coap_new_message_id(gCoAPCtx), + token, payload, optList); + VERIFY_NON_NULL(sendPdu); + coap_show_pdu(sendPdu); + + if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) dstAddr, sendPdu, 0) + != OC_STACK_OK){ + OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu")); + } + return OC_STACK_OK; exit: - coap_delete_list(optList); - return OC_COAP_ERR; + return OC_STACK_ERROR; } /** @@ -519,11 +552,11 @@ exit: * * @return 0 - success, else - TBD error */ -int OCStopCoAP() { +OCStackResult OCStopCoAP() { OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP")); coap_free_context(gCoAPCtx); gCoAPCtx = NULL; - return 0; + return OC_STACK_OK; } /** @@ -532,7 +565,8 @@ int OCStopCoAP() { * * @return 0 - success, else - TBD error */ -int OCProcessCoAP() { +OCStackResult OCProcessCoAP() { + OC_LOG(INFO, TAG, PCF("Entering OCProcessCoAP")); int read = 0; read = coap_read(gCoAPCtx, gCoAPCtx->sockfd); @@ -548,6 +582,9 @@ int OCProcessCoAP() { } } coap_dispatch(gCoAPCtx); - return 0; + + HandleSendQueue(gCoAPCtx); + + return OC_STACK_OK; } diff --git a/csdk/occoap/src/occoaphelper.c b/csdk/occoap/src/occoaphelper.c index 9e42081..39eb28f 100644 --- a/csdk/occoap/src/occoaphelper.c +++ b/csdk/occoap/src/occoaphelper.c @@ -23,6 +23,8 @@ //----------------------------------------------------------------------------- #include "occoaphelper.h" #include "logger.h" +#include "ocobserve.h" +#include "coap_time.h" //----------------------------------------------------------------------------- // Macros @@ -40,6 +42,8 @@ uint8_t OCToCoAPResponseCode(OCStackResult result) uint8_t ret; switch(result) { + case OC_STACK_OBSERVER_ADDED : + case OC_STACK_OBSERVER_REMOVED : case OC_STACK_OK : ret = COAP_RESPONSE_200; break; @@ -100,130 +104,172 @@ OCStackResult CoAPToOCResponseCode(uint8_t coapCode) return ret; } - -// Form the OCRequest struct -OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest, - OCRequest * * requestLoc, unsigned char * uriBuf, - unsigned char * queryBuf) { - - OCRequest * request = NULL; - OCObserveReq *obsReq = NULL; - size_t bufLen; - size_t optLen; +// Retrieve Uri and Query from received coap pdu +OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf, + unsigned char * queryBuf, uint8_t * * observeOptionLoc, unsigned char * * payloadLoc) +{ coap_opt_filter_t filter; coap_opt_iterator_t opt_iter; - coap_opt_t *option; - - // allocate it - request = (OCRequest *) OCMalloc(sizeof(OCRequest)); - if (!request) { - return OC_STACK_NO_MEMORY; - } - - // fill in qos - request->qos = OC_NON_CONFIRMABLE; - if (rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON) { - request->qos = OC_CONFIRMABLE; - } - - // fill in uri - request->resourceUrl = NULL; - bufLen = 0; - coap_option_filter_clear(filter); - coap_option_setb(filter, COAP_OPTION_URI_PATH); - coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter); - while ((option = coap_option_next(&opt_iter))) { - optLen = COAP_OPT_LENGTH(option); - if (bufLen + 1 + optLen < MAX_URI_LENGTH) { - //we still have room in the buffer - uriBuf[bufLen++] = '/'; - memcpy(uriBuf + bufLen, COAP_OPT_VALUE(option), optLen); - bufLen += optLen; - } else { - // TODO: should it be OC_STACK_NO_MEMORY - // TODO: we should check that resources do not have long uri at the registration - return OC_STACK_INVALID_URI; - } - } - uriBuf[bufLen] = '\0'; - request->resourceUrl = uriBuf; + coap_opt_t *option = NULL; + size_t bufLen = 0; + size_t optLen = 0; + uint8_t * observeOption = NULL; + uint8_t observeOptionFound = 0; - // fill in query - bufLen = 0; - coap_option_filter_clear(filter); - coap_option_setb(filter, COAP_OPTION_URI_QUERY); - coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter); - while ((option = coap_option_next(&opt_iter))) { - optLen = COAP_OPT_LENGTH(option); - if (bufLen + 1 + optLen < MAX_QUERY_LENGTH) { - //we still have room in the buffer - memcpy(queryBuf + bufLen, COAP_OPT_VALUE(option), optLen); - bufLen += optLen; - queryBuf[bufLen++] = '&'; - } else { - // TODO: should it be OC_STACK_NO_MEMORY - return OC_STACK_INVALID_QUERY; - } - } - // delete last '&' - queryBuf[bufLen ? (bufLen - 1) : (bufLen)] = '\0'; - - // fill in observe, if present - request->observe = NULL; - coap_option_filter_clear(filter); - coap_option_setb(filter, COAP_OPTION_OBSERVE); - coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter); - while ((option = coap_option_next(&opt_iter))) { - request->observe = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq)); - if (request->observe) + if(uriBuf) + { + // parse the Uri + coap_option_filter_clear(filter); + coap_option_setb(filter, COAP_OPTION_URI_PATH); + coap_option_iterator_init(pdu, &opt_iter, filter); + while ((option = coap_option_next(&opt_iter))) { - obsReq = request->observe; - obsReq->option = NULL; - obsReq->option = (unsigned char *)OCMalloc(COAP_OPT_LENGTH(option)+1); - if (obsReq->option) + optLen = COAP_OPT_LENGTH(option); + if (bufLen + 1 + optLen < MAX_URI_LENGTH) { - memcpy(obsReq->option, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option)); - (obsReq->option)[COAP_OPT_LENGTH(option)] = '\0'; + //we still have room in the buffer + uriBuf[bufLen++] = '/'; + memcpy(uriBuf + bufLen, COAP_OPT_VALUE(option), optLen); + bufLen += optLen; } else { - OCFree (request->observe); - OCFree (request); + // TODO: we should check that resources do not have long uri at the resource creation return OC_STACK_NO_MEMORY; } - obsReq->token = (OCCoAPToken *)OCMalloc(sizeof(MAX_TOKEN_LENGTH)); - if(obsReq->token) + } + uriBuf[bufLen] = '\0'; + } + + if(queryBuf) + { + // parse the Query + bufLen = 0; + coap_option_filter_clear(filter); + coap_option_setb(filter, COAP_OPTION_URI_QUERY); + coap_option_iterator_init(pdu, &opt_iter, filter); + while ((option = coap_option_next(&opt_iter))) + { + optLen = COAP_OPT_LENGTH(option); + if (bufLen + 1 + optLen < MAX_QUERY_LENGTH) { - memcpy (&obsReq->token->token, rcvdRequest->pdu->hdr->token, - rcvdRequest->pdu->hdr->token_length); - obsReq->token->tokenLength = rcvdRequest->pdu->hdr->token_length; + //we still have room in the buffer + memcpy(queryBuf + bufLen, COAP_OPT_VALUE(option), optLen); + bufLen += optLen; + queryBuf[bufLen++] = '&'; } else { - OCFree (request->observe); - OCFree (request); + // TODO: should it be OC_STACK_NO_MEMORY + return OC_STACK_NO_MEMORY; + } + } + // delete last '&' + queryBuf[bufLen ? (bufLen - 1) : (bufLen)] = '\0'; + } + + if(observeOptionLoc) + { + // parse the observe option + coap_option_filter_clear(filter); + coap_option_setb(filter, COAP_OPTION_OBSERVE); + coap_option_iterator_init(pdu, &opt_iter, filter); + while ((option = coap_option_next(&opt_iter))) + { + observeOption = (uint8_t *) OCMalloc(COAP_OPT_LENGTH(option)); + if(!observeOption) + { return OC_STACK_NO_MEMORY; } - obsReq->subAddr = (OCDevAddr *)&(rcvdRequest->remote); - } else { - OCFree (request); - return OC_STACK_NO_MEMORY; + memcpy(observeOption, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option)); + observeOptionFound = 1; + break; } + if(observeOptionFound) + { + *observeOptionLoc = observeOption; + } + else + { + OCFree(observeOption); + *observeOptionLoc = NULL; + } + } + + // get the payload + if(payloadLoc) + { + coap_get_data(pdu, &bufLen, payloadLoc); } - OC_LOG_V(INFO, TAG, "Observe option %d", request->observe); + + return OC_STACK_OK; +} + +// Form the OCRequest struct +OCStackResult FormOCRequest(OCRequest * * requestLoc, OCQualityOfService qos, + unsigned char * uriBuf, OCObserveReq * observeReq, + OCEntityHandlerRequest * entityHandlerRequest) +{ + OCRequest * request = NULL; + + // allocate it + request = (OCRequest *) OCMalloc(sizeof(OCRequest)); + if (!request) + { + return OC_STACK_NO_MEMORY; + } + + // fill in qos + request->qos = qos; + + // fill in uri + request->resourceUrl = uriBuf; + + // fill in observe + request->observe = observeReq; + + // add entityHandlerRequest + request->entityHandlerRequest = entityHandlerRequest; + + //TODO: this needs to be filled in the future + request->sequenceNum = 0; *requestLoc = request; return OC_STACK_OK; } +// Form the OCObserveReq struct +OCStackResult FormOCObserveReq(OCObserveReq ** observeReqLoc, uint8_t observeOption, + OCDevAddr * remote, OCCoAPToken * rcvdToken) +{ + OCObserveReq * observeReq; + + if(observeOption == OC_RESOURCE_NO_OBSERVE) + { + return OC_STACK_OK; + } + + observeReq = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq)); + if(!observeReq) + { + *observeReqLoc = NULL; + return OC_STACK_NO_MEMORY; + } + + observeReq->option = observeOption; + observeReq->subAddr = remote; + observeReq->token = rcvdToken; + + *observeReqLoc = observeReq; + return OC_STACK_OK; +} + // Form the OCEntityHandlerRequest struct -OCStackResult FormOCEntityHandlerRequest(const coap_queue_t * rcvdRequest, - OCEntityHandlerRequest * * entityHandlerRequestLoc, - unsigned char * resBuf, unsigned char * query) +OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * * entityHandlerRequestLoc, + OCMethod method, unsigned char * resBuf, unsigned char * bufReqPayload, + unsigned char * queryBuf) { OCEntityHandlerRequest * entityHandlerRequest = NULL; - unsigned char * pReq = NULL; - size_t bufLen = 0; entityHandlerRequest = (OCEntityHandlerRequest *) OCMalloc( sizeof(OCEntityHandlerRequest)); @@ -231,13 +277,16 @@ OCStackResult FormOCEntityHandlerRequest(const coap_queue_t * rcvdRequest, { return OC_STACK_NO_MEMORY; } + //set it to NULL for now, it will be modified in ocstack + entityHandlerRequest->resource = NULL; + + entityHandlerRequest->method = method; - entityHandlerRequest->method = (rcvdRequest->pdu->hdr->code == COAP_REQUEST_GET) ? - OC_REST_GET : OC_REST_PUT; + // fill in query + entityHandlerRequest->query = queryBuf; - entityHandlerRequest->query = query; - coap_get_data(rcvdRequest->pdu, &bufLen, &pReq); - entityHandlerRequest->reqJSONPayload = pReq; + // fill payload + entityHandlerRequest->reqJSONPayload = bufReqPayload; entityHandlerRequest->resJSONPayload = resBuf; entityHandlerRequest->resJSONPayloadLen = MAX_RESPONSE_LENGTH; @@ -247,94 +296,173 @@ OCStackResult FormOCEntityHandlerRequest(const coap_queue_t * rcvdRequest, } // Retrieve the token from the PDU -OCStackResult RetrieveOCCoAPToken(const coap_queue_t * rcvdRequest, - OCCoAPToken * * rcvdTokenLoc) { +OCStackResult RetrieveOCCoAPToken(const coap_pdu_t * pdu, + OCCoAPToken * * rcvdTokenLoc) +{ OCCoAPToken * rcvdToken = NULL; rcvdToken = (OCCoAPToken *) OCMalloc(sizeof(OCCoAPToken)); - if (!rcvdToken) { + if (!rcvdToken) + { return OC_STACK_NO_MEMORY; } - rcvdToken->tokenLength = rcvdRequest->pdu->hdr->token_length; - memcpy(rcvdToken->token, rcvdRequest->pdu->hdr->token, + rcvdToken->tokenLength = pdu->hdr->token_length; + memcpy(rcvdToken->token, pdu->hdr->token, rcvdToken->tokenLength); *rcvdTokenLoc = rcvdToken; return OC_STACK_OK; } -OCStackResult FormOCResponse(const coap_queue_t * rcvdResponse, - OCResponse * * responseLoc) { +OCStackResult FormOCResponse(OCResponse * * responseLoc, ClientCB * cbNode, + OCClientResponse * clientResponse) +{ OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse)); - if (!response) { + if (!response) + { return OC_STACK_NO_MEMORY; } + response->cbNode = cbNode; + response->clientResponse = clientResponse; + *responseLoc = response; return OC_STACK_OK; } -OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse, - OCClientResponse * * clientResponseLoc) { - - coap_opt_filter_t filter; - coap_opt_iterator_t opt_iter; - coap_opt_t *option; - unsigned char * pRes = NULL; - size_t bufLen = 0; +OCStackResult FormOCClientResponse(OCClientResponse * * clientResponseLoc, + OCStackResult result, OCDevAddr * remote, uint32_t seqNum, + const unsigned char * resJSONPayload) +{ OCClientResponse * clientResponse = (OCClientResponse *) OCMalloc( sizeof(OCClientResponse)); - if (!clientResponse) { + if (!clientResponse) + { return OC_STACK_NO_MEMORY; } - clientResponse->sequenceNumber = 0; - clientResponse->result = OC_STACK_ERROR; - clientResponse->addr = (OCDevAddr *) &(rcvdResponse->remote); - // fill in observe, if present - coap_option_filter_clear(filter); - coap_option_setb(filter, COAP_OPTION_OBSERVE); - coap_option_iterator_init(rcvdResponse->pdu, &opt_iter, filter); - while ((option = coap_option_next(&opt_iter))) { - if (option) + clientResponse->sequenceNumber = seqNum; + clientResponse->result = result; + clientResponse->addr = remote; + clientResponse->resJSONPayload = resJSONPayload; + + *clientResponseLoc = clientResponse; + return OC_STACK_OK; +} + +OCStackResult FormResponseOptList(coap_list_t * * optListLoc, uint8_t * addMediaType, + uint32_t * addMaxAge, uint8_t observeOptionLength, uint8_t * observeOptionPtr) +{ + coap_list_t * optNode = NULL; + + if(addMediaType) + { + optNode = CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE, + sizeof(*addMediaType), addMediaType); + VERIFY_NON_NULL(optNode); + coap_insert(optListLoc, optNode, OrderOptions); + } + if(addMaxAge) + { + optNode = CreateNewOptionNode(COAP_OPTION_MAXAGE, + sizeof(*addMaxAge), (uint8_t *)addMaxAge); + VERIFY_NON_NULL(optNode); + coap_insert(optListLoc, optNode, OrderOptions); + } + if(observeOptionPtr) + { + optNode = CreateNewOptionNode(COAP_OPTION_OBSERVE, + observeOptionLength, (uint8_t *)observeOptionPtr); + VERIFY_NON_NULL(optNode); + coap_insert(optListLoc, optNode, OrderOptions); + } + + return OC_STACK_OK; + exit: + coap_delete_list(*optListLoc); + return OC_STACK_NO_MEMORY; +} + +//Send a coap pdu +OCStackResult +SendCoAPPdu(coap_context_t * gCoAPCtx, coap_address_t* dst, coap_pdu_t * pdu, + uint8_t delayFlag) +{ + coap_tid_t tid = COAP_INVALID_TID; + OCStackResult res = OC_STACK_COMM_ERROR; + uint8_t sendFlag = SEND_NOW; + + if(delayFlag) + { + sendFlag = SEND_DELAYED; + } + else + { + if(pdu->hdr->type != COAP_MESSAGE_CON) { - memcpy(&clientResponse->sequenceNumber, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option)); + sendFlag = SEND_NOW; } else { - return OC_STACK_NO_MEMORY; + sendFlag = SEND_NOW_CON; } } - coap_get_data(rcvdResponse->pdu, &bufLen, &pRes); - clientResponse->resJSONPayload = pRes; + tid = coap_send(gCoAPCtx, dst, pdu, sendFlag); + OC_LOG_V(INFO, TAG, "TID %d", tid); + if ((pdu->hdr->type != COAP_MESSAGE_CON && !delayFlag) || tid == COAP_INVALID_TID) + { + OC_LOG(INFO, TAG, PCF("Deleting PDU")); + coap_delete_pdu(pdu); + } + else + { + OC_LOG(INFO, TAG, PCF("Keeping PDU, we will handle the retry/delay of this pdu")); + } - *clientResponseLoc = clientResponse; - return OC_STACK_OK; + if(tid != COAP_INVALID_TID) + { + OC_LOG(INFO, TAG, PCF("Sending a pdu with Token:")); + OC_LOG_BUFFER(INFO,TAG, pdu->hdr->token, pdu->hdr->token_length); + res = OC_STACK_OK; + } + + return res; } //generate a coap message coap_pdu_t * GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id, - size_t tokenLength, uint8_t * token, unsigned char * payloadJSON, - coap_list_t *options) { + OCCoAPToken * token, unsigned char * payloadJSON, + coap_list_t *options) +{ coap_pdu_t *pdu; coap_list_t *opt; - pdu = coap_pdu_init(msgType, code, id, COAP_MAX_PDU_SIZE); - VERIFY_NON_NULL(pdu); - - pdu->hdr->token_length = tokenLength; - if (!coap_add_token(pdu, tokenLength, token)) { - OC_LOG(FATAL, TAG, PCF("coap_add_token failed")); + if(token) + { + pdu = coap_pdu_init(msgType, code, id, COAP_MAX_PDU_SIZE); + VERIFY_NON_NULL(pdu); + pdu->hdr->token_length = token->tokenLength; + if (!coap_add_token(pdu, token->tokenLength, token->token)) + { + OC_LOG(FATAL, TAG, PCF("coap_add_token failed")); + } + } + else + { + pdu = coap_pdu_init(msgType, code, id, sizeof(coap_pdu_t)); + VERIFY_NON_NULL(pdu); } - for (opt = options; opt; opt = opt->next) { + for (opt = options; opt; opt = opt->next) + { coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data), COAP_OPTION_LENGTH(*(coap_option *) opt->data), COAP_OPTION_DATA(*(coap_option *) opt->data)); } - if (payloadJSON) { + if (payloadJSON) + { coap_add_data(pdu, strlen((const char *) payloadJSON) + 1, (unsigned char*) payloadJSON); } @@ -342,19 +470,26 @@ GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id, // display the pdu for debugging purposes coap_show_pdu(pdu); + // clean up + coap_delete_list(options); return pdu; - exit: return NULL; + exit: + coap_delete_list(options); + return NULL; } //a function to help in ordering coap options -int OrderOptions(void *a, void *b) { - if (!a || !b) { +int OrderOptions(void *a, void *b) +{ + if (!a || !b) + { return a < b ? -1 : 1; } if (COAP_OPTION_KEY(*(coap_option *)a) - < COAP_OPTION_KEY(*(coap_option *)b) ) { + < COAP_OPTION_KEY(*(coap_option *)b) ) + { return -1; } @@ -390,3 +525,114 @@ exit: coap_free(option); return NULL; } + +OCStackResult ReTXCoAPQueue(coap_context_t * ctx, coap_queue_t * queue) +{ + coap_tid_t tid = COAP_INVALID_TID; + OCStackResult result = OC_STACK_ERROR; + tid = coap_retransmit( ctx, queue); + if(tid == COAP_INVALID_TID) + { + OC_LOG_V(DEBUG, TAG, "Retransmission Failed TID %d", + queue->id); + result = OC_STACK_COMM_ERROR; + } + else + { + OC_LOG_V(DEBUG, TAG, "Retransmission TID %d, this is attempt %d", + queue->id, queue->retransmit_cnt); + result = OC_STACK_OK; + } + return result; +} + +OCStackResult HandleFailedCommunication(coap_context_t * ctx, coap_queue_t * queue) +{ + OCResponse * response = NULL; + ClientCB * cbNode = NULL; + ResourceObserver * observer = NULL; + OCClientResponse * clientResponse = NULL; + OCCoAPToken * token = NULL; + OCStackResult result = OC_STACK_OK; + + result = RetrieveOCCoAPToken(queue->pdu, &token); + if(result != OC_STACK_OK) + { + goto exit; + } + + cbNode = GetClientCB(token, NULL); + if(!cbNode) + { + goto observation; + } + result = FormOCClientResponse(&clientResponse, OC_STACK_COMM_ERROR, + (OCDevAddr *) &(queue->remote), 0, NULL); + if(result != OC_STACK_OK) + { + goto observation; + } + result = FormOCResponse(&response, cbNode, clientResponse); + if(result != OC_STACK_OK) + { + goto observation; + } + HandleStackResponses(response); + +observation: + observer = GetObserver(token); + if(!observer) + { + goto exit; + } + + result = OCObserverStatus(token, OC_OBSERVER_FAILED_COMM); + if(result == OC_STACK_OBSERVER_REMOVED) + { + coap_cancel_all_messages(ctx, &queue->remote, token->token, token->tokenLength); + } + + exit: + OCFree(token); + OCFree(clientResponse); + OCFree(response); + return result; +} + +// a function to handle the send queue in the passed context +void HandleSendQueue(coap_context_t * ctx) +{ + coap_tick_t now; + coap_queue_t *nextQueue = NULL; + + coap_ticks(&now); + nextQueue = coap_peek_next( ctx ); + while (nextQueue && nextQueue->t <= now - ctx->sendqueue_basetime) + { + nextQueue = coap_pop_next( ctx ); + if((uint8_t)nextQueue->delayedResponse) + { + OC_LOG_V(DEBUG, TAG, "Sending Delayed response TID %d", + nextQueue->id); + if(SendCoAPPdu(ctx, &nextQueue->remote, nextQueue->pdu, 0) + == OC_STACK_COMM_ERROR) + { + OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu")); + HandleFailedCommunication(ctx, nextQueue); + } + nextQueue->pdu = NULL; + coap_delete_node(nextQueue); + } + else + { + OC_LOG_V(DEBUG, TAG, "Retrying a CON pdu TID %d",nextQueue->id); + if(ReTXCoAPQueue(ctx, nextQueue) == OC_STACK_COMM_ERROR) + { + OC_LOG(DEBUG, TAG, PCF("A problem occurred in retransmitting a pdu")); + HandleFailedCommunication(ctx, nextQueue); + coap_delete_node(nextQueue); + } + } + nextQueue = coap_peek_next( ctx ); + } +} diff --git a/csdk/occoap/test/occoaptests.cpp b/csdk/occoap/test/occoaptests.cpp index da4afa9..43b145b 100644 --- a/csdk/occoap/test/occoaptests.cpp +++ b/csdk/occoap/test/occoaptests.cpp @@ -59,16 +59,3 @@ static const char TAG[] = "TestHarness"; TEST(OCCoapTest, General) { EXPECT_EQ(0, 0); } - -/*TEST(OCCoapTest, ServiceDiscovery) { - OC_LOG(INFO, TAG, "Running ServiceDiscovery"); - - EXPECT_EQ(0, OCInitCoAP("127.0.0.1", 0, OC_CLIENT)); - - OCCoAPClientCallbackFunction asyncReturnFunc = discoverServicesAsync; - EXPECT_EQ(0, OCDoCoAPResource(OC_REST_GET, "oc/core/d", asyncReturnFunc)); - - EXPECT_EQ(0, OCProcessCoAP()); - - EXPECT_EQ(0, OCStopCoAP()); -}*/ diff --git a/csdk/stack/include/internal/ocobserve.h b/csdk/stack/include/internal/ocobserve.h index da622ce..71a14ce 100644 --- a/csdk/stack/include/internal/ocobserve.h +++ b/csdk/stack/include/internal/ocobserve.h @@ -22,14 +22,24 @@ #define OC_OBSERVE_H /* In CoAP sequence number is a 24 bit field */ -#define MAX_SEQUENCE_NUMBER 0xFFFFFF -#define OC_RESOURCE_OBSERVE_REGISTER "0" -#define OC_RESOURCE_OBSERVE_DEREGISTER "1" +#define MAX_SEQUENCE_NUMBER (0xFFFFFF) +#define OC_RESOURCE_OBSERVE_REGISTER (0) +#define OC_RESOURCE_OBSERVE_DEREGISTER (1) +#define OC_RESOURCE_NO_OBSERVE (2) + +#define MAX_OBSERVER_FAILED_COMM (2) +#define MAX_OBSERVER_NON_COUNT (3) + +#define OC_OBSERVER_NOT_INTERESTED (0) +#define OC_OBSERVER_STILL_INTERESTED (1) +#define OC_OBSERVER_FAILED_COMM (2) /* This information is stored for each registerd observer */ -typedef struct ObserveResourceServer { +typedef struct ResourceObserver { // URI of observed resource unsigned char *resUri; + //Quality of service of the request + OCQualityOfService qos; // Query unsigned char *query; // CoAP token for the observe request @@ -38,14 +48,32 @@ typedef struct ObserveResourceServer { OCResource *resource; // IP address & port of client registered for observe OCDevAddr *addr; + // number of times the server failed to reach the observer + uint8_t failedCommCount; + // number of times the server sent NON notifications + uint8_t NONCount; + // force the qos value to CON + uint8_t forceCON; // next node in this list - struct ObserveResourceServer *next; -} ObserveResourceServer; + struct ResourceObserver *next; +} ResourceObserver; + +OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status); OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request); -OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr); +OCStackResult SendObserverNotification (OCResource *resPtr); void DeleteObserverList(); +OCStackResult AddObserver ( const char *resUri, + const char *query, + OCCoAPToken * token, + OCDevAddr *addr, + OCResource *resHandle, + OCQualityOfService qos); +OCStackResult DeleteObserver (OCCoAPToken * token); + +ResourceObserver* GetObserver (const OCCoAPToken * token); + #endif //OC_OBSERVE_H diff --git a/csdk/stack/include/internal/ocstackinternal.h b/csdk/stack/include/internal/ocstackinternal.h index 2291cc1..24530dc 100644 --- a/csdk/stack/include/internal/ocstackinternal.h +++ b/csdk/stack/include/internal/ocstackinternal.h @@ -125,7 +125,7 @@ typedef struct rsrc_t { typedef struct { // Observe option field - unsigned char *option; + uint8_t option; // IP address & port of client registered for observe OCDevAddr *subAddr; // CoAP token for the observe request diff --git a/csdk/stack/include/ocstack.h b/csdk/stack/include/ocstack.h index fe43cb6..c1952a3 100644 --- a/csdk/stack/include/ocstack.h +++ b/csdk/stack/include/ocstack.h @@ -117,6 +117,9 @@ typedef enum { OC_STACK_RESOURCE_ERROR, /*ex: not supported method or interface*/ OC_STACK_SLOW_RESOURCE, OC_STACK_NO_OBSERVERS, /* resource has no registered observers */ + OC_STACK_OBSERVER_NOT_FOUND, + OC_STACK_OBSERVER_ADDED, + OC_STACK_OBSERVER_REMOVED, OC_STACK_ERROR } OCStackResult; diff --git a/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp b/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp index a2feb9d..995481d 100644 --- a/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp +++ b/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp @@ -33,7 +33,7 @@ const char *getResult(OCStackResult result); std::string getIPAddrTBServer(OCClientResponse * clientResponse); std::string getPortTBServer(OCClientResponse * clientResponse); -std::string getQueryStrForGetPut(unsigned const char * responsePayload); +std::string getQueryStrForGetPut(OCClientResponse * clientResponse); #define TAG PCF("occlient") #define CTX_VAL 0x99 @@ -44,10 +44,12 @@ std::string getQueryStrForGetPut(unsigned const char * responsePayload); typedef enum { TEST_DISCOVER_REQ = 1, - TEST_GET_REQ, - TEST_PUT_REQ, - TEST_OBS_REQ, - TEST_GET_UNAVAILABLE_RES_REQ, + TEST_GET_REQ_NON, + TEST_PUT_REQ_NON, + TEST_OBS_REQ_NON, + TEST_GET_UNAVAILABLE_RES_REQ_NON, + TEST_GET_REQ_CON, + TEST_OBS_REQ_CON, MAX_TESTS } CLIENT_TEST; @@ -55,6 +57,9 @@ static int UNICAST_DISCOVERY = 0; static int TEST_CASE = 0; static const char * TEST_APP_UNICAST_DISCOVERY_QUERY = "coap://0.0.0.0:5683/oc/core"; static std::string putPayload = "{\"state\":\"off\",\"power\":\"0\"}"; +static std::string coapServerIP = "255.255.255.255"; +static std::string coapServerPort = "5683"; +static std::string coapServerResource = "/a/led"; // The handle for the observe registration OCDoHandle gObserveDoHandle; @@ -70,25 +75,26 @@ void handleSigInt(int signum) { } // Forward Declaration -OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse); -int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse); -int InitObserveRequest(OCClientResponse * clientResponse); -int InitPutRequest(OCClientResponse * clientResponse); -int InitGetRequest(OCClientResponse * clientResponse); +int InitGetRequestToUnavailableResource(); +int InitObserveRequest(OCQualityOfService qos); +int InitPutRequest(); +int InitGetRequest(OCQualityOfService qos); int InitDiscovery(); +void parseClientResponse(OCClientResponse * clientResponse); static void PrintUsage() { - OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3|4|5>"); + OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3|4|5|6|7>"); OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources"); OC_LOG(INFO, TAG, "-t 1 : Discover Resources"); - OC_LOG(INFO, TAG, "-t 2 : Discover Resources and Initiate Get Request"); - OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate Put Requests"); - OC_LOG(INFO, TAG, "-t 4 : Discover Resources and Initiate Observe Requests"); - OC_LOG(INFO, TAG, "-t 5 : Discover Resources and Initiate Get Request for a resource which is unavailable"); + OC_LOG(INFO, TAG, "-t 2 : Discover Resources and Initiate Nonconfirmable Get Request"); + OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate Nonconfirmable Put Requests"); + OC_LOG(INFO, TAG, "-t 4 : Discover Resources and Initiate Nonconfirmable Observe Requests"); + OC_LOG(INFO, TAG, "-t 5 : Discover Resources and Initiate Nonconfirmable Get Request for a resource which is unavailable"); + OC_LOG(INFO, TAG, "-t 6 : Discover Resources and Initiate Confirmable Get Request"); + OC_LOG(INFO, TAG, "-t 7 : Discover Resources and Initiate Confirmable Observe Requests"); } - OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method, OCQualityOfService qos, OCClientResponseHandler cb ) @@ -196,22 +202,30 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle, clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1], remoteIpAddr[2], remoteIpAddr[3], remotePortNu); - - if (TEST_CASE == TEST_GET_REQ) - { - InitGetRequest(clientResponse); - } - else if (TEST_CASE == TEST_PUT_REQ) - { - InitPutRequest(clientResponse); - } - else if (TEST_CASE == TEST_OBS_REQ) - { - InitObserveRequest(clientResponse); - } - else if (TEST_CASE == TEST_GET_UNAVAILABLE_RES_REQ) - { - InitGetRequestToUnavailableResource(clientResponse); + parseClientResponse(clientResponse); + + switch(TEST_CASE){ + case TEST_GET_REQ_NON: + InitGetRequest(OC_NON_CONFIRMABLE); + break; + case TEST_PUT_REQ_NON: + InitPutRequest(); + break; + case TEST_OBS_REQ_NON: + InitObserveRequest(OC_NON_CONFIRMABLE); + break; + case TEST_GET_UNAVAILABLE_RES_REQ_NON: + InitGetRequestToUnavailableResource(); + break; + case TEST_GET_REQ_CON: + InitGetRequest(OC_CONFIRMABLE); + break; + case TEST_OBS_REQ_CON: + InitObserveRequest(OC_CONFIRMABLE); + break; + default: + PrintUsage(); + break; } } @@ -219,40 +233,39 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle, } - -int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse) +int InitGetRequestToUnavailableResource() { OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__); std::ostringstream query; - query << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << "/SomeUnknownResource"; + query << "coap://" << coapServerIP << ":" << coapServerPort << "/SomeUnknownResource"; return (InvokeOCDoResource(query, OC_REST_GET, OC_NON_CONFIRMABLE, getReqCB)); } -int InitObserveRequest(OCClientResponse * clientResponse) +int InitObserveRequest(OCQualityOfService qos) { OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__); std::ostringstream query; - query << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload); - return (InvokeOCDoResource(query, OC_REST_OBSERVE, OC_NON_CONFIRMABLE, obsReqCB)); + query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource; + return (InvokeOCDoResource(query, OC_REST_OBSERVE, (qos == OC_CONFIRMABLE)? OC_CONFIRMABLE:OC_NON_CONFIRMABLE, obsReqCB)); } -int InitPutRequest(OCClientResponse * clientResponse) +int InitPutRequest() { OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__); std::ostringstream query; - query << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload); + query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource; return (InvokeOCDoResource(query, OC_REST_PUT, OC_NON_CONFIRMABLE, putReqCB)); } -int InitGetRequest(OCClientResponse * clientResponse) +int InitGetRequest(OCQualityOfService qos) { OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__); std::ostringstream query; - query << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload); - return (InvokeOCDoResource(query, OC_REST_GET, OC_NON_CONFIRMABLE, getReqCB)); + query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource; + return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_CONFIRMABLE)? OC_CONFIRMABLE:OC_NON_CONFIRMABLE, getReqCB)); } int InitDiscovery() @@ -372,12 +385,13 @@ std::string getPortTBServer(OCClientResponse * clientResponse){ return ss.str(); } -std::string getQueryStrForGetPut(unsigned const char * responsePayload){ - // JSON = {"oc":{"payload":[{"href":"/a/led","rt":["core.led"],"if":["core.rw"],"obs":1}]}} - - //std::string jsonPayload(responsePayload, responsePayload + sizeof responsePayload / sizeof responsePayload[0]); - std::string jsonPayload(reinterpret_cast(const_cast(responsePayload))); - //std::cout << jsonPayload << std::endl; +std::string getQueryStrForGetPut(OCClientResponse * clientResponse){ return "/a/led"; } + +void parseClientResponse(OCClientResponse * clientResponse){ + coapServerIP = getIPAddrTBServer(clientResponse); + coapServerPort = getPortTBServer(clientResponse); + coapServerResource = getQueryStrForGetPut(clientResponse); +} diff --git a/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp b/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp index 18a0e50..87fa43f 100644 --- a/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp +++ b/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp @@ -74,6 +74,7 @@ OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandle } } else if (entityHandlerRequest && flag == OC_OBSERVE_FLAG) { + //TODO : Should the OC_OBSERVE_FLAG behave just like a GET according to the standard? gLEDUnderObservation = 1; } @@ -170,4 +171,3 @@ void createLEDResource() { OC_DISCOVERABLE|OC_OBSERVABLE); OC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res)); } - diff --git a/csdk/stack/src/ocobserve.c b/csdk/stack/src/ocobserve.c index 66d9865..1ab9915 100644 --- a/csdk/stack/src/ocobserve.c +++ b/csdk/stack/src/ocobserve.c @@ -27,96 +27,185 @@ #include "debug.h" #include -#define TAG PCF("ocbserve") +// Module Name +#define MOD_NAME PCF("ocobserve") + +#define TAG PCF("OCStackObserve") #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} } -static struct ObserveResourceServer *serverObsList = NULL; +static struct ResourceObserver * serverObsList = NULL; -OCStackResult AddObserver (const char *resUri, - const char *query, - uint8_t *token, - size_t tokenLength, - OCDevAddr *addr, - OCResource *resHandle); -OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength); +OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status) +{ + OCStackResult result = OC_STACK_ERROR; + ResourceObserver * observer = NULL; + + switch(status) + { + case OC_OBSERVER_NOT_INTERESTED: + OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore")); + //observer is dead, or it is not observing anymore + result = DeleteObserver (token); + if(result == OC_STACK_OK) + { + OC_LOG(DEBUG, TAG, PCF("removing an observer")); + result = OC_STACK_OBSERVER_REMOVED; + } + break; + case OC_OBSERVER_STILL_INTERESTED: + //observer is still interested + OC_LOG(DEBUG, TAG, PCF("observer is interested in our \ + notifications, reset the failedCount")); + observer = GetObserver(token); + if(observer) + { + observer->forceCON = 0; + observer->failedCommCount = 0; + result = OC_STACK_OK; + } + else + { + result = OC_STACK_OBSERVER_NOT_FOUND; + } + break; + case OC_OBSERVER_FAILED_COMM: + //observer is not reachable + OC_LOG(DEBUG, TAG, PCF("observer is not reachable")); + observer = GetObserver(token); + if(observer) + { + if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM) + { + result = DeleteObserver (token); + OC_LOG(DEBUG, TAG, PCF("removing an observer")); + result = OC_STACK_OBSERVER_REMOVED; + } + else + { + observer->failedCommCount++; + result = OC_STACK_OK; + } + observer->forceCON = 1; + OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount); + } + break; + default: + break; + } + + return result; +} OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request) { - OCStackResult result; + OCStackResult result = OC_STACK_ERROR; OCEntityHandlerRequest *ehReq = request->entityHandlerRequest; OCObserveReq *obs = request->observe; OC_LOG(INFO, TAG, PCF("Entering ProcessObserveRequest")); - if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_REGISTER) == 0) { - if (NULL == resource) + + // Register new observation + request->entityHandlerRequest->resource = (OCResourceHandle)resource; + result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest); + + if (obs->option == OC_RESOURCE_OBSERVE_REGISTER) + { + // Add subscriber to the server observation list + // TODO: we need to check if the obsrever is already there using its OCDevAdd.... + result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query), + obs->token, obs->subAddr, resource, request->qos); + if(result == OC_STACK_OK) { - return OC_STACK_ERROR; + result = OC_STACK_OBSERVER_ADDED; } - // Register new observation - request->entityHandlerRequest->resource = (OCResourceHandle)resource; - result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest); - if (OC_STACK_OK == result) + OC_LOG(DEBUG, TAG, PCF("adding an observer")); + } + else if (obs->option == OC_RESOURCE_OBSERVE_DEREGISTER) + { + // Deregister observation + result = DeleteObserver (obs->token); + if(result == OC_STACK_OK) { - // Add subscriber to the server observation list - result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query), - obs->token->token, obs->token->tokenLength, obs->subAddr, resource); + OC_LOG(DEBUG, TAG, PCF("removing an observer")); + result = OC_STACK_OBSERVER_REMOVED; } - return result; - } else if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) { - // Deregister observation - result = DeleteObserver (obs->token->token, obs->token->tokenLength); - return result; - } else { + } + else + { // Invalid option OC_LOG(ERROR, TAG, PCF("Invalid CoAP observe option")); - return OC_STACK_INVALID_OBSERVE_PARAM; + result = OC_STACK_INVALID_OBSERVE_PARAM; } + return result; } -OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr) +OCStackResult SendObserverNotification (OCResource *resPtr) { uint8_t numObs = 0; - OCStackResult result; - ObserveResourceServer *obsRes = serverObsList; - OCEntityHandlerRequest entityHandlerReq; - unsigned char bufRes[MAX_RESPONSE_LENGTH] = { 0 } ; - /* - * TODO: In the current releast all observes are set as non-confirmable since the - * entity handler does not have a way to specify the message QoS - add a parameter. - * Sending all observes NON does not confirm with the observe draft (ver14). - */ + OCStackResult result = OC_STACK_ERROR; + ResourceObserver *resourceObserver = serverObsList; + OCEntityHandlerRequest * entityHandlerReq = NULL; + unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0}; + // TODO: we should allow the server application to define qos for each notification OCQualityOfService qos = OC_NON_CONFIRMABLE; // Increment the sequence number resPtr->sequenceNum += 1; if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER) + { resPtr->sequenceNum = 1; + } // Find clients that are observing this resource - while (obsRes) { - if (obsRes->resource == handle) { - // Invoke the entity handler for the client to process the query according to - // the new representation + while (resourceObserver) + { + if (resourceObserver->resource == resPtr) + { + // Invoke the entity handler for the client to process + // the query according to the new representation numObs++; - entityHandlerReq.resource = handle; - entityHandlerReq.query = obsRes->query; - entityHandlerReq.method = OC_REST_GET; - entityHandlerReq.reqJSONPayload = NULL; - entityHandlerReq.resJSONPayload = bufRes; - entityHandlerReq.resJSONPayloadLen = MAX_RESPONSE_LENGTH; - // Even if entity handler for a resource is not successful we continue calling - // entity handler for other resources - if ( BuildObsJSONResponse((OCResource *)handle, &entityHandlerReq) - == OC_EH_OK) + FormOCEntityHandlerRequest(&entityHandlerReq, OC_REST_GET, bufRes, + NULL, resourceObserver->query); + entityHandlerReq->resource = (OCResourceHandle)resPtr; + + // Even if entity handler for a resource is not successful + // we continue calling entity handler for other resources + result = resPtr->entityHandler (OC_REQUEST_FLAG, entityHandlerReq); + if (OC_STACK_OK == result) { - result = OC_STACK_OK; - OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->token, - (const char *)entityHandlerReq.resJSONPayload, - resPtr->sequenceNum); + OC_LOG_V(INFO, TAG, "OCStack payload: %s", + entityHandlerReq->resJSONPayload); + + // send notifications based on the qos of the request + qos = resourceObserver->qos; + if(qos == OC_NON_CONFIRMABLE) + { + OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d", + resourceObserver->NONCount); + if(resourceObserver->forceCON || + resourceObserver->NONCount >= MAX_OBSERVER_NON_COUNT) + { + resourceObserver->NONCount = 0; + // at some point we have to to send CON to check on the + // availability of observer + OC_LOG(INFO, TAG, PCF("This time we are sending the \ + notification as CON")); + qos = OC_CONFIRMABLE; + } + else + { + resourceObserver->NONCount++; + } + } + + OCSendCoAPNotification(resourceObserver->addr, result, qos, + resourceObserver->token, + (unsigned char *)entityHandlerReq->resJSONPayload, + resPtr->sequenceNum); } } - obsRes = obsRes->next; + resourceObserver = resourceObserver->next; } if (numObs == 0) { @@ -128,18 +217,20 @@ OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *res OCStackResult AddObserver (const char *resUri, const char *query, - uint8_t *token, - size_t tokenLength, + OCCoAPToken * token, OCDevAddr *addr, - OCResource *resHandle) + OCResource *resHandle, + OCQualityOfService qos) { - ObserveResourceServer *obsNode; - OCCoAPToken *tokPtr; + ResourceObserver *obsNode = NULL; + OCCoAPToken *tokPtr = NULL; - obsNode = (ObserveResourceServer *) OCMalloc(sizeof(ObserveResourceServer)); - if (obsNode) { + obsNode = (ResourceObserver *) OCMalloc(sizeof(ResourceObserver)); + if (obsNode) + { obsNode->resUri = (unsigned char *)OCMalloc(sizeof(strlen(resUri)+1)); VERIFY_NON_NULL (obsNode->resUri); + obsNode->qos = qos; memcpy (obsNode->resUri, resUri, sizeof(strlen(resUri)+1)); obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1)); VERIFY_NON_NULL (obsNode->query); @@ -147,12 +238,15 @@ OCStackResult AddObserver (const char *resUri, obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken)); VERIFY_NON_NULL (obsNode->token); tokPtr = obsNode->token; - memcpy (tokPtr->token, token, sizeof(OCCoAPToken)); - tokPtr->tokenLength = tokenLength; + tokPtr->tokenLength = token->tokenLength; + memcpy (tokPtr->token, token->token, tokPtr->tokenLength); obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr)); VERIFY_NON_NULL (obsNode->addr); memcpy (obsNode->addr, addr, sizeof(OCDevAddr)); obsNode->resource = resHandle; + obsNode->failedCommCount = 0; + obsNode->NONCount = 0; + obsNode->forceCON = 0; LL_APPEND (serverObsList, obsNode); return OC_STACK_OK; @@ -167,16 +261,17 @@ exit: return OC_STACK_NO_MEMORY; } -ObserveResourceServer* GetObserver (const uint8_t *token, const size_t tokenLength) +ResourceObserver* GetObserver (const OCCoAPToken * token) { - ObserveResourceServer *out = NULL; + ResourceObserver *out = NULL; - if(token) + if(token) { - LL_FOREACH (serverObsList, out) + LL_FOREACH (serverObsList, out) { - if((out->token->tokenLength == tokenLength) && - (memcmp(out->token->token, token, tokenLength) == 0)) { + if((out->token->tokenLength == token->tokenLength) && + (memcmp(out->token->token, token->token, token->tokenLength) == 0)) + { return out; } } @@ -185,30 +280,31 @@ ObserveResourceServer* GetObserver (const uint8_t *token, const size_t tokenLeng return NULL; } -OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength) +OCStackResult DeleteObserver (OCCoAPToken * token) { - ObserveResourceServer *obsNode = NULL; + ResourceObserver *obsNode = NULL; - obsNode = GetObserver (token, tokenLength); - if (obsNode) { + obsNode = GetObserver (token); + if (obsNode) + { LL_DELETE (serverObsList, obsNode); OCFree(obsNode->resUri); OCFree(obsNode->query); OCFree(obsNode->token); OCFree(obsNode->addr); OCFree(obsNode); - return OC_STACK_OK; } - return OC_STACK_ERROR; + // it is ok if we did not find the observer... + return OC_STACK_OK; } void DeleteObserverList() { - ObserveResourceServer *out; - ObserveResourceServer *tmp; - LL_FOREACH_SAFE (serverObsList, out, tmp) + ResourceObserver *out = NULL; + ResourceObserver *tmp = NULL; + LL_FOREACH_SAFE (serverObsList, out, tmp) { - DeleteObserver (out->token->token, out->token->tokenLength); + DeleteObserver (out->token); } serverObsList = NULL; } diff --git a/csdk/stack/src/ocresource.c b/csdk/stack/src/ocresource.c index 984f564..d17040b 100644 --- a/csdk/stack/src/ocresource.c +++ b/csdk/stack/src/ocresource.c @@ -461,6 +461,9 @@ BuildJSONResponse(ResourceHandling resHandling, OCResource *resource, OCRequest } case OC_RESOURCE_NOT_SPECIFIED: + // This case is not needed as the logic changed so OCCancel results in RESET + // rather than a GET. RESET is handled at lower layers. + // TODO: This is a special case. In M1 this occurs only for observation // delete since OCCancel (on the client) only takes OCDoHandle param. // TODO: Remove comments below before release - only for code review diff --git a/csdk/stack/src/ocstack.c b/csdk/stack/src/ocstack.c index 5cd4b09..baf9b14 100644 --- a/csdk/stack/src/ocstack.c +++ b/csdk/stack/src/ocstack.c @@ -56,7 +56,8 @@ OCResource *headResource = NULL; //----------------------------------------------------------------------------- //This function will be called back by occoap layer when a request is received -OCStackResult HandleStackRequests(OCRequest * request) { +OCStackResult HandleStackRequests(OCRequest * request) +{ OC_LOG(INFO, TAG, PCF("Entering OCStackHandleReceiveRequest (OCStack Layer)")); OCStackResult result = OC_STACK_ERROR; @@ -76,29 +77,37 @@ OCStackResult HandleStackRequests(OCRequest * request) { } //This function will be called back by occoap layer when a response is received -void HandleStackResponses(OCResponse * response) { +void HandleStackResponses(OCResponse * response) +{ OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION; OC_LOG(INFO, TAG, PCF("Entering HandleStackResponses (OCStack Layer)")); - if (response->cbNode) { + if (response->cbNode) + { OC_LOG(INFO, TAG, PCF("Calling into application address space")); - result = response->cbNode->callBack(response->cbNode->context, response->cbNode->handle, response->clientResponse); - if (result == OC_STACK_DELETE_TRANSACTION) { + result = response->cbNode->callBack(response->cbNode->context, + response->cbNode->handle, response->clientResponse); + if (result == OC_STACK_DELETE_TRANSACTION || + response->clientResponse->result == OC_STACK_COMM_ERROR) + { FindAndDeleteClientCB(response->cbNode); } } } -int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr) { +int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr) +{ size_t index = 0; unsigned char *itr, *coap; uint8_t dotCount = 0; /* search for scheme */ itr = ipAddrStr; - if (!isdigit((unsigned char) *ipAddrStr)) { + if (!isdigit((unsigned char) *ipAddrStr)) + { coap = (unsigned char *) OC_COAP_SCHEME; - while (*coap && tolower(*itr) == *coap) { + while (*coap && tolower(*itr) == *coap) + { coap++; itr++; } @@ -106,22 +115,30 @@ int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr) { ipAddrStr = itr; while (*ipAddrStr) { - if (isdigit((unsigned char) *ipAddrStr)) { + if (isdigit((unsigned char) *ipAddrStr)) + { ipAddr[index] *= 10; ipAddr[index] += *ipAddrStr - '0'; - } else if ((unsigned char) *ipAddrStr == '.') { + } + else if ((unsigned char) *ipAddrStr == '.') + { index++; dotCount++; - } else { + } + else + { break; } ipAddrStr++; } if (ipAddr[0] < 255 && ipAddr[1] < 255 && ipAddr[2] < 255 && ipAddr[3] < 255 - && dotCount == 3) { + && dotCount == 3) + { return 1; - } else { + } + else + { return 0; } } @@ -166,14 +183,17 @@ static void deleteAllResources(); * OC_STACK_OK - no errors * OC_STACK_ERROR - stack init error */ -OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) { +OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) +{ OC_LOG(INFO, TAG, PCF("Entering OCInit")); - if (ipAddr) { + if (ipAddr) + { OC_LOG_V(INFO, TAG, "IP Address = %s", ipAddr); } - switch (mode) { + switch (mode) + { case OC_CLIENT: OC_LOG(INFO, TAG, PCF("Client mode")); break; @@ -193,7 +213,8 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) { initResources(); // Make call to OCCoAP layer - if (OCInitCoAP(ipAddr, (uint16_t) port, mode) == 0) { + if (OCInitCoAP(ipAddr, (uint16_t) port, mode) == OC_STACK_OK) + { stackState = OC_STACK_INITIALIZED; return OC_STACK_OK; } @@ -208,18 +229,21 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) { * OC_STACK_OK - no errors * OC_STACK_ERROR - stack not initialized */ -OCStackResult OCStop() { +OCStackResult OCStop() +{ OCStackResult result = OC_STACK_ERROR; OC_LOG(INFO, TAG, PCF("Entering OCStop")); - if (stackState != OC_STACK_INITIALIZED) { + if (stackState != OC_STACK_INITIALIZED) + { OC_LOG(ERROR, TAG, PCF("Stack not initialized")); return OC_STACK_ERROR; } // Make call to OCCoAP layer - if (OCStopCoAP() == 0) { + if (OCStopCoAP() == OC_STACK_OK) + { // Remove all observers DeleteObserverList(); // Remove all the client callbacks @@ -286,18 +310,26 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ case OC_REST_OBSERVE_ALL: break; default: - return OC_STACK_INVALID_METHOD; + result = OC_STACK_INVALID_METHOD; + goto exit; } *handle = GenerateInvocationHandle(); - VERIFY_NON_NULL(*handle, FATAL, OC_STACK_ERROR); + if(!*handle) + { + result = OC_STACK_NO_MEMORY; + goto exit; + } + token = OCGenerateCoAPToken(); if (!token) { + result = OC_STACK_NO_MEMORY; goto exit; } if((result = AddClientCB(&clientCB, cbData, token, *handle, method)) != OC_STACK_OK) { + result = OC_STACK_NO_MEMORY; goto exit; } @@ -305,19 +337,12 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ result = (OCStackResult)OCDoCoAPResource(method, qos, token, requiredUri, request); exit: - if (result != OC_STACK_OK) { OC_LOG(ERROR, TAG, PCF("OCDoResource error")); - if (clientCB) - { - DeleteClientCB(clientCB); - } - else - { - OCFree(token); - OCFree(*handle); - } + FindAndDeleteClientCB(clientCB); + OCFree(token); + OCFree(*handle); } return result; } @@ -336,7 +361,7 @@ OCStackResult OCCancel(OCDoHandle handle) { * This ftn can be implemented one of two ways: * * 1. When observe is unobserved..Remove the callback associated on client side. - * When the next notification comes in from server, reply with RST message to server. + * When the next notification comes in from server, reply with RESET message to server. * * 2. When OCCancel is called, and it is associated with an observe request * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL), @@ -358,8 +383,7 @@ OCStackResult OCCancel(OCDoHandle handle) { { case OC_REST_OBSERVE: case OC_REST_OBSERVE_ALL: - // Make call to OCCoAP layer - DeleteClientCB(clientCB); + FindAndDeleteClientCB(clientCB); break; default: return OC_STACK_INVALID_METHOD; @@ -1054,7 +1078,7 @@ OCStackResult OCNotifyObservers(OCResourceHandle handle) { { return OC_STACK_NO_RESOURCE; } else { - result = SendObserverNotification (handle, resPtr); + result = SendObserverNotification (resPtr); return result; } } diff --git a/csdk/stack/test/arduino/ArduinoStackTest.cpp b/csdk/stack/test/arduino/ArduinoStackTest.cpp index 156fcd1..cd0f30c 100644 --- a/csdk/stack/test/arduino/ArduinoStackTest.cpp +++ b/csdk/stack/test/arduino/ArduinoStackTest.cpp @@ -55,9 +55,9 @@ void EXPECT_EQ(int a, int b) { void EXPECT_STREQ(const char *a, const char *b) { if (strcmp(a, b) == 0) { - OC_LOG(INFO, TAG, "PASS"); + OC_LOG(INFO, TAG, PCF("PASS")); } else { - OC_LOG(ERROR, TAG, "FAIL"); + OC_LOG(ERROR, TAG, PCF("FAIL")); } } //----------------------------------------------------------------------------- -- 2.7.4