To come on this changeset: All convergences between and server and client observation...
authorVijay Kesavan <vijay.s.kesavan@intel.com>
Tue, 5 Aug 2014 21:19:25 +0000 (14:19 -0700)
committerVijay Kesavan <vijay.s.kesavan@intel.com>
Tue, 5 Aug 2014 21:19:25 +0000 (14:19 -0700)
Added changes for implementing SequenceNum on Client Side.

Fixed token nuances. Now server and client utilize the same token.

Added Delete functionality to observer implementation.

Sequence Iterator work...It works!! :D

Patch #7 : Modified OCClientResponseHandler callback signature. Updated occlient sample app to reflect that.
   Updated code in OCDoResource API for proper error handling.
   Updated OCClientCb.h to store DoHandle instead of address of DoHandle.
   Took care of some other small tid-bits regarding code formatiing.

Patch #8 : Made one little change Sachin forgot. Check for ptr == NULL not needed when calling free().

Patch #9 : Put in logic for OBSERVE_ALL notification Vs. OBSERVE on client-side. Now client will not accept notifications out of order if OC_REST_OBSERVE is used.

Patch #10 & 11: Added more complete logic for OBSERVE Vs. OBSERVE_ALL logic.  Also verified that out of order notifications are handled correctly in each case.

Patch #12: Added functionality to convert coap errors to OC stack errors for server respsonses.
    Updated OCClient application to weild specific usage scenarios.

Patch #13: Added fix for some of code review comments by Jesse.
   Updated occlient.cpp to OC_REST_OBSERVE in InitObserveRequest method.

Patch #14: (Joey)  Added RST to Remove Observations logic.

Patch #15:  Rebase on master

Patch #16: (Vijay) Observe delete on server

Patch #17: (Vijay) Fixed issues with cancel (cancel observe still not working)

Patch #18: (Joey) Reverted and Fixed issues with cancel observe.

Patch #19: (Vijay) Observer list delete

Patch #20: (Joey) Fully implemented Cancel Observe. Needs Vijay's approval. (I.e. if Vijay +1's we're done make changes except for code review changes)

Patch #21: (Joey) Cleaned up ALL warnings (minus TODO pragma messages someone has put in.).

Patch #22: (Vijay) Clean up of observe delete and removed printfs

Patch #23: (Vijay) Addressed some of the review comments
Change-Id: Iad7a4263ece57f1545606a5cf05ddfcacb48d363

15 files changed:
csdk/libcoap-4.1.1/net.c
csdk/occoap/include/occoap.h
csdk/occoap/include/occoaphelper.h
csdk/occoap/src/occoap.c
csdk/occoap/src/occoaphelper.c
csdk/stack/include/internal/occlientcb.h
csdk/stack/include/internal/ocobserve.h
csdk/stack/include/internal/ocstackinternal.h
csdk/stack/include/ocstack.h
csdk/stack/samples/SimpleClientServer/makefile
csdk/stack/samples/SimpleClientServer/occlient.cpp
csdk/stack/samples/SimpleClientServer/ocserver.cpp
csdk/stack/src/occlientcb.c
csdk/stack/src/ocobserve.c
csdk/stack/src/ocstack.c

index 97819b2..ab70fd6 100644 (file)
@@ -1520,6 +1520,23 @@ handle_locally(coap_context_t *context __attribute__ ((unused)),
                         == 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);
+
+               /* find transaction in sendqueue to stop retransmission */
+               coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
+
+               if (sent)
+               coap_handle_rst(context, sent);
+               goto cleanup;
             default:
                 debug(
                         "TODO: Need to handle other message types in coap_dispatch");
index 8effdf4..517475d 100644 (file)
@@ -92,8 +92,12 @@ int OCStopCoAP();
 int OCProcessCoAP();
 
 OCCoAPToken * OCGenerateCoAPToken();
-/* Vijay: TODO: Add description */
 
+/**
+ * Initiate sending of CoAP messages. Example: server uses it to send observe messages
+ *
+ * @return OC_COAP_OK - success, OC_COAP_ERR
+ */
 int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode, 
                        OCQualityOfService qos, OCCoAPToken * token,
                        const char *payload, uint32_t seqNum);
index 4b7b309..19772fe 100644 (file)
 //-----------------------------------------------------------------------------
 // Includes
 //-----------------------------------------------------------------------------
+#include <unistd.h>
+#include <limits.h>
+#include <ctype.h>
 #include "coap.h"
 #include "ocstack.h"
 #include "occoaptoken.h"
 #include "ocstackinternal.h"
-#include <unistd.h>
-#include <limits.h>
-#include <ctype.h>
 
 // Convert OCStack code to CoAP code
 uint8_t OCToCoAPResponseCode(OCStackResult result);
 
+// Convert CoAP code to OCStack code
+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,
index 6d0eff7..fb84765 100644 (file)
@@ -24,6 +24,7 @@
 //=============================================================================
 #include "occoap.h"
 #include "occlientcb.h"
+#include "ocobserve.h"
 #include <coap.h>
 
 #ifndef WITH_ARDUINO
@@ -56,18 +57,20 @@ static coap_context_t *gCoAPCtx = NULL;
 //=============================================================================
 
 //generate a coap token
-OCCoAPToken * OCGenerateCoAPToken() {
-    OCCoAPToken *token;
+OCCoAPToken * OCGenerateCoAPToken()
+{
+    OCCoAPToken *token = NULL;
     // Generate token here, it will be deleted when the transaction is deleted
     token = (OCCoAPToken *) malloc(sizeof(OCCoAPToken));
-    token->tokenLength = MAX_TOKEN_LENGTH;
-    OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
+    if (token)
+    {
+        token->tokenLength = MAX_TOKEN_LENGTH;
+        OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
+    }
 
-    //OC_LOG_V(INFO,TAG,"Toke n generated %d bytes..........%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-    //         token->tokenLength,token->token[0],token->token[1],token->token[2],token->token[3],
-    //         token->token[4],token->token[5],token->token[6],token->token[7]);
     return token;
 }
+
 //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)
@@ -109,12 +112,9 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
     OC_LOG_V(INFO, TAG, " Receveid query:   %s", entityHandlerRequest->query);
     OC_LOG_V(INFO, TAG, " Receveid payload: %s",
             request->entityHandlerRequest->reqJSONPayload);
-
-    if(GetClientCB(rcvdToken, 0)) { //True if the token was found in the list of clientCBs
-        OC_LOG_V(INFO, TAG, " Token received %d bytes",
-                rcvdToken->tokenLength);
-        OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength);
-    }
+    OC_LOG_V(INFO, TAG, " Token received %d bytes",
+            rcvdToken->tokenLength);
+    OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength);
 
     // process the request
     result = HandleStackRequests(request);
@@ -158,10 +158,7 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
 
 exit:
     coap_delete_list(optList);
-    if(rcvdToken) {
-        OCFree(rcvdToken);
-        rcvdToken = NULL;
-    }
+    OCFree(rcvdToken);
     OCFree(entityHandlerRequest);
     OCFree(request);
 }
@@ -170,8 +167,9 @@ exit:
 static void HandleCoAPResponses(struct coap_context_t *ctx,
         const coap_queue_t * rcvdResponse) {
     OCResponse * response = NULL;
-    OCCoAPToken * _token = NULL;
+    OCCoAPToken * token = NULL;
     OCClientResponse * clientResponse = NULL;
+    ClientCB * cbNode = NULL;
     OCStackResult result;
 
     VERIFY_NON_NULL(ctx);
@@ -180,13 +178,14 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
     // TODO: we should check if we are interested in the token
     // Now, just accept NON packets
 
-    if (rcvdResponse->pdu->hdr->type == COAP_MESSAGE_NON) {
+    if (rcvdResponse->pdu->hdr->type == COAP_MESSAGE_NON)
+    {
         // fill OCResponse structure
         result = FormOCResponse(rcvdResponse, &response);
         VERIFY_SUCCESS(result, OC_STACK_OK);
 
         // fill OCCoAPToken structure
-        result = RetrieveOCCoAPToken(rcvdResponse, &_token);
+        result = RetrieveOCCoAPToken(rcvdResponse, &token);
         VERIFY_SUCCESS(result, OC_STACK_OK);
 
         // fill OCClientResponse structure
@@ -194,32 +193,63 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
         VERIFY_SUCCESS(result, OC_STACK_OK);
 
         // put everything together
-        ClientCB * clientCB = GetClientCB(_token, NULL);
-        OCDoHandle *handle = NULL;
-        if(clientCB) {
-            handle = clientCB->handle;
-            response->handle = handle;
-        }
         response->clientResponse = clientResponse;
 
+        cbNode = GetClientCB(token, 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);
+        OC_LOG_V(INFO, TAG,"Token received %d bytes", token->tokenLength);
+        OC_LOG_BUFFER(INFO, TAG, token->token,
+                      token->tokenLength);
 
-        response->clientResponse->result = OC_STACK_OK;
-        HandleStackResponses(response);
-        /*if (rcvdResponse->pdu->hdr->code == COAP_RESPONSE_CODE(205))
+        if(cbNode && (cbNode->method == OC_REST_OBSERVE || cbNode->method == OC_REST_OBSERVE_ALL))
         {
-            response->clientResponse->result = OC_STACK_OK;
-            HandleStackResponses(response);
+            if(clientResponse->sequenceNumber != 0)
+            {
+                if(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;
+                }
+            }
         }
-        else
+        else if(!cbNode && clientResponse  && clientResponse->sequenceNumber != 0) // Ensure that this is an observe notification.
         {
-            OC_LOG(DEBUG, TAG,
-                   "No other response codes are supported in HandleCoAPResponses");
-        }*/
+
+            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, "Deleting PDU");
+                coap_delete_pdu(pdu);
+            }
+            else
+            {
+                OC_LOG(INFO, TAG, "Keeping PDU, we should handle the retry of this pdu");
+            }
+            goto exit;
+        }
+        response->cbNode = cbNode;
+        response->clientResponse->result = CoAPToOCResponseCode(rcvdResponse->pdu->hdr->code);
+        HandleStackResponses(response);
     }
     else
     {
@@ -228,10 +258,7 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
 
 exit:
     OCFree(response);
-    if(_token) {
-        OCFree(_token);
-        _token = NULL;
-    }
+    OCFree(token);
     OCFree(clientResponse);
 }
 
@@ -295,6 +322,10 @@ int OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
     ret = OC_COAP_OK;
 
 exit:
+    if (ret != OC_COAP_OK)
+    {
+        OCStopCoAP(gCoAPCtx);
+    }
     return ret;
 }
 
@@ -318,7 +349,6 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
     int ret = OC_COAP_ERR;
     coap_pdu_t *pdu = NULL;
     coap_uri_t uri;
-    coap_tid_t tid = COAP_INVALID_TID;
     OCDevAddr dst;
     uint8_t ipAddr[4] = { 0 };
     coap_list_t *optList = NULL;
@@ -329,67 +359,63 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
     int res;
     uint8_t coapMsgType;
     uint8_t coapMethod;
-    // Vijay: TODO Observation registration is hardcoded here - change
-    unsigned char obs[] = "0";
 
     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
 
     if (Uri) {
         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
-    }
-
-    VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), 0);
-
-    // Generate the destination address
-    if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr)) {
-        OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
-                &dst);
-    } else {
-        goto exit;
-    }
-
-    //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);
-    }
-
-    if (uri.path.length) {
-        buflen = BUF_SIZE;
-        res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+        VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), 0);
+
+        // Generate the destination address
+        if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr)) {
+            OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
+                    &dst);
+        } else {
+            goto exit;
+        }
 
-        while (res--) {
+        //create appropriate coap options
+        if (uri.port != COAP_DEFAULT_PORT) {
             coap_insert(&optList,
-                    CreateNewOptionNode(COAP_OPTION_URI_PATH,
-                            COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
+                    CreateNewOptionNode(COAP_OPTION_URI_PORT,
+                            coap_encode_var_bytes(portBuf, uri.port), portBuf),
                     OrderOptions);
-
-            buf += COAP_OPT_SIZE(buf);
         }
-    }
 
-    if (uri.query.length) {
-        buflen = BUF_SIZE;
-        buf = _buf;
-        res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+        if (uri.path.length) {
+            buflen = BUF_SIZE;
+            res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
 
-        while (res--) {
-            coap_insert(&optList,
-                    CreateNewOptionNode(COAP_OPTION_URI_QUERY,
-                            COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
-                    OrderOptions);
+            while (res--) {
+                coap_insert(&optList,
+                        CreateNewOptionNode(COAP_OPTION_URI_PATH,
+                                COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
+                        OrderOptions);
 
-            buf += COAP_OPT_SIZE(buf);
+                buf += COAP_OPT_SIZE(buf);
+            }
         }
-    }
 
-    OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
-    OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
-    OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
-    OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
+        if (uri.query.length) {
+            buflen = BUF_SIZE;
+            buf = _buf;
+            res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+
+            while (res--) {
+                coap_insert(&optList,
+                        CreateNewOptionNode(COAP_OPTION_URI_QUERY,
+                                COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
+                        OrderOptions);
+
+                buf += COAP_OPT_SIZE(buf);
+            }
+        }
 
+        OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
+        OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
+        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;
 
     // Decide message type
@@ -397,7 +423,6 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
         coapMsgType = COAP_MESSAGE_CON;
         OC_LOG(FATAL, TAG, "qos == OC_CONFIRMABLE is not supported in OCDoCoAPResource");
     }
-
     // Decide method type
     switch (method) {
         case OC_REST_GET:
@@ -409,24 +434,8 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
         case OC_REST_OBSERVE_ALL:
         case OC_REST_OBSERVE:
             coapMethod = COAP_REQUEST_GET;
-#if 0
-            // Joey's add for observation registration: not working.
-            // Vijay's change below
-            buflen = BUF_SIZE;
-            buf = _buf;
-            res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
-            //Set observe option flag.
-            while (res--) {
-                coap_insert(&optList,
-                        CreateNewOptionNode(COAP_OPTION_SUBSCRIPTION,
-                                COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
-                        OrderOptions);
-
-                buf += COAP_OPT_SIZE(buf);
-            }
-#endif
             coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
-                        strlen((const char *)obs), (obs)), OrderOptions);
+                        strlen(OC_RESOURCE_OBSERVE_REGISTER), (unsigned char *)OC_RESOURCE_OBSERVE_REGISTER), OrderOptions);
 
             break;
         default:
@@ -441,20 +450,16 @@ int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * toke
             (unsigned char*) payload, optList);
     VERIFY_NON_NULL(pdu);
 
-    TODO ("Post Sprint 1 -- Send Confirmed requests for non-discovery requests");
-    tid = coap_send(gCoAPCtx, (coap_address_t*) &dst, pdu);
+    coap_send(gCoAPCtx, (coap_address_t*) &dst, pdu);
 
-    OC_LOG_V(INFO, TAG, "TID %d", tid);
-    if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
+    //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, "Deleting PDU");
         coap_delete_pdu(pdu);
         pdu = NULL;
     }
-    else
-    {
-        OC_LOG(INFO, TAG, "Keeping PDU, we should handle the retry of this pdu");
-    }
 
     ret = OC_COAP_OK;
 
@@ -467,7 +472,7 @@ exit:
     return ret;
 }
 
-int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode, 
+int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode,
                        OCQualityOfService qos, OCCoAPToken * token,
                        const char *payload, uint32_t seqNum)
 {
@@ -479,7 +484,6 @@ int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode,
 
     OC_LOG(INFO, TAG, PCF("Entering OCCoAPSendMessage"));
 
-    printf ("Payload: %s\n", payload);
     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),
index 3c920e2..26e0581 100644 (file)
@@ -34,7 +34,7 @@
 // Helper Functions
 //=============================================================================
 
-//convert OCStack code to CoAP code
+// Convert OCStack code to CoAP code
 uint8_t OCToCoAPResponseCode(OCStackResult result)
 {
     uint8_t ret;
@@ -48,21 +48,59 @@ uint8_t OCToCoAPResponseCode(OCStackResult result)
             ret = COAP_RESPONSE_400;
             break;
 
-        case OC_STACK_INVALID_METHOD :
-            ret = COAP_RESPONSE_405;
+        case OC_STACK_NO_RESOURCE :
+            ret = COAP_RESPONSE_404;
             break;
 
-        case OC_STACK_NO_RESOURCE :
+        case OC_STACK_INVALID_METHOD :
             ret = COAP_RESPONSE_405;
             break;
 
         default:
             ret = COAP_RESPONSE_500;
+    }
+    return ret;
+}
+
+
+// Convert CoAP code to OCStack code
+OCStackResult CoAPToOCResponseCode(uint8_t coapCode)
+{
+    OCStackResult ret;
+    int decimal;
+    switch(coapCode)
+    {
+        case COAP_RESPONSE_200 :
+            ret = OC_STACK_OK;
+            break;
+
+        case COAP_RESPONSE_400 :
+            ret = OC_STACK_INVALID_QUERY;
+            break;
+
+        case COAP_RESPONSE_404 :
+            ret = OC_STACK_NO_RESOURCE;
+            break;
 
+        case COAP_RESPONSE_405 :
+            ret = OC_STACK_INVALID_METHOD;
+            break;
+
+        default:
+            decimal = ((coapCode >> 5) * 100) + (coapCode && 31);
+            if (decimal >= 200 && decimal <= 231)
+            {
+                ret = OC_STACK_OK;
+            }
+            else
+            {
+                ret = OC_STACK_ERROR;
+            }
     }
     return ret;
 }
 
+
 // Form the OCRequest struct
 OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
         OCRequest * * requestLoc, unsigned char * uriBuf,
@@ -136,7 +174,6 @@ OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
     coap_option_setb(filter, COAP_OPTION_OBSERVE);
     coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter);
     while ((option = coap_option_next(&opt_iter))) {
-        printf ("\n\n ******************* OBS ********** %d, %s\n\n\n", COAP_OPT_LENGTH(option), COAP_OPT_VALUE(option));
         request->observe = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq));
         if (request->observe)
         {
@@ -151,20 +188,25 @@ OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
             else
             {
                 OCFree (request->observe);
+                OCFree (request);
+                return OC_STACK_NO_MEMORY;
+            }
+            obsReq->token = (OCCoAPToken *)OCMalloc(sizeof(MAX_TOKEN_LENGTH));
+            if(obsReq->token)
+            {
+                memcpy (&obsReq->token->token, rcvdRequest->pdu->hdr->token, 
+                        rcvdRequest->pdu->hdr->token_length);
+                obsReq->token->tokenLength = rcvdRequest->pdu->hdr->token_length;
+            }
+            else
+            {
+                OCFree (request->observe);
+                OCFree (request);
                 return OC_STACK_NO_MEMORY;
             }
-            /*
-            // Vijay: TODO: Remove this code block before final commit
-            // TODO: Should we copy sizeof OCDevAddr or introspect the addr for size
-            memcpy (&(obsReq->subAddr), (OCDevAddr *) &(rcvdRequest->remote),sizeof(OCDevAddr));
-            coapTok = obsReq->coapTok;
-            coapTok->tokenLength = rcvdRequest->pdu->hdr->token_length;
-            memcpy(coapTok->token, rcvdRequest->pdu->hdr->token, coapTok->tokenLength);
-            */
             obsReq->subAddr = (OCDevAddr *)&(rcvdRequest->remote);
-            obsReq->coapToken = rcvdRequest->pdu->hdr->token;
-            obsReq->coapTokenLen = rcvdRequest->pdu->hdr->token_length;
         } else {
+            OCFree (request);
             return OC_STACK_NO_MEMORY;
         }
     }
@@ -233,7 +275,10 @@ OCStackResult FormOCResponse(const coap_queue_t * rcvdResponse,
 
 OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse,
         OCClientResponse * * clientResponseLoc) {
-    //OCClientResponse * * clientResponseLoc, unsigned char * resBuf) {
+
+    coap_opt_filter_t filter;
+    coap_opt_iterator_t opt_iter;
+    coap_opt_t *option;
     unsigned char * pRes = NULL;
     size_t bufLen = 0;
 
@@ -242,21 +287,26 @@ OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse,
     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)
+        {
+            memcpy(&clientResponse->sequenceNumber, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
+        }
+        else
+        {
+            return OC_STACK_NO_MEMORY;
+        }
+    }
 
     coap_get_data(rcvdResponse->pdu, &bufLen, &pRes);
     clientResponse->resJSONPayload = pRes;
-    //clientResponse->resJSONPayloadLen = bufLen;
-
-    /*if (bufLen >= MAX_RESPONSE_LENGTH) {
-     return OC_STACK_NO_MEMORY;
-     }
-
-     memcpy(resBuf, pRes, bufLen);
-     resBuf[bufLen] = '\0';
-     clientResponse->resJSONPayload = resBuf;*/
 
     *clientResponseLoc = clientResponse;
     return OC_STACK_OK;
@@ -314,29 +364,29 @@ int OrderOptions(void *a, void *b) {
 
 //a function to create a coap option
 coap_list_t *
-CreateNewOptionNode(unsigned short key, unsigned int length,
-        unsigned char *data) {
-    coap_option *option;
+CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data)
+{
+    coap_option *option = NULL;
     coap_list_t *node;
 
+    VERIFY_NON_NULL(data);
     option = coap_malloc(sizeof(coap_option) + length);
-    if (!option) {
-        goto exit;
-    }
+    VERIFY_NON_NULL(option);
 
     COAP_OPTION_KEY(*option) = key;
     COAP_OPTION_LENGTH(*option) = length;
-    VERIFY_NON_NULL(data);
     memcpy(COAP_OPTION_DATA(*option), data, length);
 
     /* we can pass NULL here as delete function since option is released automatically  */
     node = coap_new_listnode(option, NULL);
 
-    if (node) {
+    if (node)
+    {
         return node;
     }
 
-    exit: OC_LOG(ERROR,TAG,"new_option_node: malloc: was not created");
+exit:
+    OC_LOG(ERROR,TAG,"new_option_node: malloc: was not created");
     coap_free(option);
     return NULL;
 }
index 60b89a1..1c6d3ac 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <ocstack.h>
 #include <occoaptoken.h>
-#include <occoap.h>
 
 typedef struct ClientCB {
     // callback method defined in application address space
@@ -34,9 +33,11 @@ typedef struct ClientCB {
     //  when a response is recvd with this token, above callback will be invoked
     OCCoAPToken * token;
     // Invocation handle tied to original call to OCDoResource()
-    OCDoHandle handle;
+    OCDoHandle handle;
     // This is used to determine if all responses should be consumed or not. (For now, only pertains to OC_REST_OBSERVE_ALL Vs. OC_REST_OBSERVE functionality)
     OCMethod method;
+    // This is the sequence identifier the server applies to the invocation tied to 'handle'.
+    uint32_t sequenceNumber;
     // next node in this list
     struct ClientCB    *next;
 } ClientCB;
@@ -60,7 +61,7 @@ typedef struct ClientCB {
  * @retval OC_STACK_OK for Success, otherwise some error value
  */
 //------------------------------------------------------------------------
-OCStackResult AddClientCB(ClientCB* clientCB, OCCallbackData *cbData, OCCoAPToken * token, OCDoHandle * handle, OCMethod method);
+OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData *cbData, OCCoAPToken * token, OCDoHandle handle, OCMethod method);
 
 //-- DeleteClientCB -----------------------------------------------------------
 /** @ingroup ocstack
index 8c635dc..da622ce 100644 (file)
 #define OC_RESOURCE_OBSERVE_REGISTER     "0"
 #define OC_RESOURCE_OBSERVE_DEREGISTER   "1"
 
-/* Vijay: TODO add comments */
+/* This information is stored for each registerd observer */
 typedef struct ObserveResourceServer {
-    // xxxxxxxxxxxxxxxx
+    // URI of observed resource
     unsigned char *resUri;
-    // xxxxxxxxxxxxxxxxx
+    // Query
     unsigned char *query;
-    // xxxxxxxxxxxxxxxxx
-    OCCoAPToken *coapTok;
-    // xxxxxxxxxxxxxxxxx
+    // CoAP token for the observe request
+    OCCoAPToken *token;
+    // Resource handle
     OCResource *resource;
-    // xxxxxxxxxxxxxxxxx
+    // IP address & port of client registered for observe
     OCDevAddr *addr;
     // next node in this list
     struct ObserveResourceServer *next;
@@ -46,4 +46,6 @@ OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request);
 
 OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *resPtr);
 
+void DeleteObserverList();
+
 #endif //OC_OBSERVE_H
index defd13a..b619d3f 100644 (file)
@@ -30,6 +30,7 @@
 //-----------------------------------------------------------------------------
 #include "ocstack.h"
 #include "occoaptoken.h"
+#include "occlientcb.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -119,16 +120,13 @@ typedef struct rsrc_t {
     uint32_t sequenceNum;
 } OCResource;
 
-/* Vijay: TODO add comments */
 typedef struct {
-    // xxxxxxxxxxxxxxxx
+    // Observe option field
     unsigned char *option;
-    // xxxxxxxxxxxxxxxx
+    // IP address & port of client registered for observe
     OCDevAddr *subAddr;
-    // xxxxxxxxxxxxxxxx
-    uint8_t *coapToken;
-    // xxxxxxxxxxxxxxxx
-    size_t coapTokenLen;
+    // CoAP token for the observe request
+    OCCoAPToken *token;
 } OCObserveReq;
 
 // following structure will be created in occoap and passed up the stack on the server side
@@ -139,6 +137,8 @@ typedef struct {
     OCQualityOfService qos;
     // this structure points to the information for processing observe option 
     OCObserveReq *observe;
+    // If a subscription update, this is count of observe notifications from server perspective.
+    uint32_t sequenceNum;
     // this structure will be passed to entity handler
     OCEntityHandlerRequest * entityHandlerRequest;
 } OCRequest;
@@ -146,7 +146,7 @@ typedef struct {
 // following structure will be created in occoap and passed up the stack on the client side
 typedef struct {
     // handle is retrieved by comparing the token-handle pair in the PDU.
-    OCDoHandle * handle;
+    ClientCB * cbNode;
     // this structure will be passed to client
     OCClientResponse * clientResponse;
 } OCResponse;
index d3810e6..ec955da 100644 (file)
@@ -160,7 +160,7 @@ typedef struct {
     // Address of remote server
     OCDevAddr * addr;
     // If associated with observe, this will represent the sequence of notifications from server.
-    uint8_t sequenceNumber;
+    uint32_t sequenceNumber;
     // resJSONPayload is retrieved from the payload of the received request PDU
     unsigned  const char * resJSONPayload;
 }OCClientResponse;
@@ -184,7 +184,7 @@ typedef enum {
 /**
  * Client applications implement this callback to consume responses received from Servers.
  */
-typedef OCStackApplicationResult (* OCClientResponseHandler)(void *context, OCClientResponse * clientResponse);
+typedef OCStackApplicationResult (* OCClientResponseHandler)(void *context, OCDoHandle handle, OCClientResponse * clientResponse);
 
 
 /*
index a4d493c..cff6ab3 100644 (file)
@@ -32,9 +32,9 @@ INC_DIRS      += -I$(OCCOAP_INC)
 INC_DIRS       += -I$(OCTBSTACK_INC)
 
 CC_FLAGS.debug      := -O0 -g3 -Wall -ffunction-sections -fdata-sections -fno-exceptions \
-                        -pedantic $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
+                        -std=c++0x -pedantic $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
 CC_FLAGS.release    := -Os -Wall -fdata-sections -Wl,--gc-sections -Wl,-s -fno-exceptions \
-                        $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
+                        -std=c++0x $(INC_DIRS) -L$(ROOT_DIR) -DTB_LOG
                                        
 LDLIBS         += -loctbstack -lpthread
 CPPFLAGS       += $(CC_FLAGS.$(BUILD)) $(LDLIBS)
index 2763d44..6b29355 100644 (file)
@@ -38,8 +38,17 @@ std::string getQueryStrForGetPut(unsigned  const char * responsePayload);
 #define MAX_LENGTH_IPv4_ADDR 16
 #endif
 
+#define MAX_TEST_CASES 5
+
+static int UNICAST_DISCOVERY = 0;
+static int TEST_CASE = 0;
 static std::string putPayload = "{\"state\":\"off\",\"power\":\"0\"}";
 
+// The handle for the observe registration
+OCDoHandle gObserveDoHandle;
+// After this crosses a threshold client deregisters for further observations
+int gNumNotifies = 1;
+
 int gQuitFlag = 0;
 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
 void handleSigInt(int signum) {
@@ -48,53 +57,67 @@ void handleSigInt(int signum) {
        }
 }
 
-OCStackApplicationResult clientApplicationGETCb(void* ctx, OCClientResponse * clientResponse);
+// 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 InitDiscovery();
+
+void PrintUsage()
+{
+    OC_LOG(INFO, TAG, "Usage : occlient <Unicast Discovery> <Test Case>");
+    OC_LOG(INFO, TAG, "Test Case 1 : Discover Resources");
+    OC_LOG(INFO, TAG, "Test Case 2 : Discover Resources and Initiate Get Request");
+    OC_LOG(INFO, TAG, "Test Case 3 : Discover Resources and Initiate Get/Put Requests");
+    OC_LOG(INFO, TAG, "Test Case 4 : Discover Resources and Initiate Observe Requests");
+    OC_LOG(INFO, TAG, "Test Case 5 : Discover Resources and Initiate Get Request for a resource which is unavailable");
+}
 
-OCStackApplicationResult clientApplicationPUTCb(void* ctx, OCClientResponse * clientResponse) {        
+OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
        if(clientResponse) {}
        if(ctx == (void*)CTX_VAL) {
                OC_LOG_V(INFO, TAG, "Callback Context for PUT query recvd successfully");
-               OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);     
+               OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
        }
 
        return OC_STACK_KEEP_TRANSACTION;
 }
 
-OCStackApplicationResult clientApplicationGETCb(void* ctx, OCClientResponse * clientResponse) {
-       if(clientResponse) {}
-       if(ctx == (void*)CTX_VAL) {
-               OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
-               OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
-#if 0
-       //* Make a GET query*/
-               std::ostringstream getQuery;
-               getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
-               OCCallbackData cbData;
-               cbData.cb = clientApplicationPUTCb;
-               cbData.context = (void*)CTX_VAL;
-               OCDoHandle handle;
-
-               OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());       
-               if (OCDoResource(&handle, OC_REST_PUT, getQuery.str().c_str(), 0, putPayload.c_str(), OC_NON_CONFIRMABLE, &cbData)
-                               != OC_STACK_OK) {
-                       OC_LOG_V(ERROR, TAG, "OCStack resource error");
-                       //reOC_LOG_Vturn 0;
-               }
-#endif
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
+    OC_LOG_V(INFO, TAG, "StackResult: %s",
+            getResult(clientResponse->result));
+    if(ctx == (void*)CTX_VAL) {
+        OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
+        if(clientResponse->sequenceNumber == 0) {
+            OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
+            OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
+        }
+        else {
+            OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumNotifies);
+            OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
+            gNumNotifies++;
+            if (gNumNotifies == 3)
+            {
+                if (OCCancel (gObserveDoHandle) != OC_STACK_OK){
+                    OC_LOG(ERROR, TAG, "Observe cancel error");
+                }
+            }
+        }
        }
        return OC_STACK_KEEP_TRANSACTION;
 }
 
 
 // This is a function called back when a device is discovered
-OCStackApplicationResult clientApplicationCB(void* ctx,
+OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
         OCClientResponse * clientResponse) {
     uint8_t remoteIpAddr[4];
     uint16_t remotePortNu;
-    OCDoHandle handle;
 
     OC_LOG(INFO, TAG,
-            "Entering clientApplicationCB (Application Layer CB)");
+            "Entering discoveryReqCB (Application Layer CB)");
     OC_LOG_V(INFO, TAG, "StackResult: %s",
             getResult(clientResponse->result));
 
@@ -110,43 +133,155 @@ OCStackApplicationResult clientApplicationCB(void* ctx,
             "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
             clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
             remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
-   
-       std::ostringstream obsReg;
-       obsReg << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+
+    if (TEST_CASE == 2)
+    {
+        InitGetRequest(clientResponse);
+    }
+    else if (TEST_CASE == 3)
+    {
+        InitPutRequest(clientResponse);
+    }
+    else if (TEST_CASE == 4)
+    {
+        InitObserveRequest(clientResponse);
+    }
+    else if (TEST_CASE == 5)
+    {
+        InitGetRequestToUnavailableResource(clientResponse);
+    }
+       return OC_STACK_KEEP_TRANSACTION;
+}
+
+
+int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse)
+{
+    OCStackResult ret;
        OCCallbackData cbData;
-       cbData.cb = clientApplicationGETCb;
-       cbData.context = (void*)CTX_VAL;
-       if (OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData)
-                       != OC_STACK_OK) {
+    OCDoHandle handle;
+    std::ostringstream getQuery;
+    getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << "/SomeUnknownResource";
+    cbData.cb = getReqCB;
+    cbData.context = (void*)CTX_VAL;
+    ret = OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
+    if (ret != OC_STACK_OK)
+    {
                OC_LOG(ERROR, TAG, "OCStack resource error");
-               //return 0;
-       }
-       return OC_STACK_KEEP_TRANSACTION;
-#if 0
-       //* Make a GET query*/
-       std::ostringstream getQuery;
-       getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+    }
+    return ret;
+}
+
+
+int InitObserveRequest(OCClientResponse * clientResponse)
+{
+    OCStackResult ret;
+    OCCallbackData cbData;
+    OCDoHandle handle;
+    std::ostringstream obsReg;
+    obsReg << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+    cbData.cb = getReqCB;
+    cbData.context = (void*)CTX_VAL;
+    OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
+    ret = OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
+    if (ret != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack resource error");
+    }
+    else 
+    {
+        gObserveDoHandle = handle;
+    }
+    return ret;
+}
+
+
+int InitPutRequest(OCClientResponse * clientResponse)
+{
+    OCStackResult ret;
+    OCCallbackData cbData;
+    OCDoHandle handle;
+    //* Make a PUT query*/
+    std::ostringstream getQuery;
+    getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+    cbData.cb = putReqCB;
+    cbData.context = (void*)CTX_VAL;
+    OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
+    ret = OCDoResource(&handle, OC_REST_PUT, getQuery.str().c_str(), 0, putPayload.c_str(), OC_NON_CONFIRMABLE, &cbData);
+    if (ret != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack resource error");
+    }
+    return ret;
+}
+
+
+int InitGetRequest(OCClientResponse * clientResponse)
+{
+    OCStackResult ret;
        OCCallbackData cbData;
-       cbData.cb = clientApplicationGETCb;
-       cbData.context = (void*)CTX_VAL;
-       if (OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData)
-                       != OC_STACK_OK) {
+    OCDoHandle handle;
+    //* Make a GET query*/
+    std::ostringstream getQuery;
+    getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
+    cbData.cb = getReqCB;
+    cbData.context = (void*)CTX_VAL;
+    ret = OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
+    if (ret != OC_STACK_OK)
+    {
                OC_LOG(ERROR, TAG, "OCStack resource error");
-               //return 0;
-       }
+    }
+    return ret;
+}
 
-       return OC_STACK_KEEP_TRANSACTION;
-#endif
+#define TEST_APP_UNICAST_DISCOVERY_QUERY                  PCF("coap://0.0.0.0:5683/oc/core")
+int InitDiscovery()
+{
+    OCStackResult ret;
+       OCCallbackData cbData;
+    OCDoHandle handle;
+       /* Start a discovery query*/
+       char szQueryUri[64] = { 0 };
+    if (UNICAST_DISCOVERY)
+    {
+        strcpy(szQueryUri, TEST_APP_UNICAST_DISCOVERY_QUERY);
+    }
+    else
+    {
+        strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
+    }
+       cbData.cb = discoveryReqCB;
+       cbData.context = (void*)CTX_VAL;
+       ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_NON_CONFIRMABLE, &cbData);
+    if (ret != OC_STACK_OK)
+    {
+               OC_LOG(ERROR, TAG, "OCStack resource error");
+    }
+    return ret;
 }
-//This function is called back when a resource is discovered.
 
-int main() {
+int main(int argc, char* argv[]) {
        uint8_t addr[20] = {0};
        uint8_t* paddr = NULL;
        uint16_t port = USE_RANDOM_PORT;
        uint8_t ifname[] = "eth0";
-       OCCallbackData cbData;
-    OCDoHandle handle;
+
+    if (argc == 3)
+    {
+        UNICAST_DISCOVERY = atoi(argv[1]);
+        TEST_CASE = atoi(argv[2]);
+        if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
+            (TEST_CASE < 1 || TEST_CASE > MAX_TEST_CASES) )
+        {
+            PrintUsage();
+            return -1;
+        }
+    }
+    else
+    {
+        PrintUsage();
+        return -1;
+    }
+
 
        /*Get Ip address on defined interface and initialize coap on it with random port number
         * this port number will be used as a source port in all coap communications*/
@@ -163,16 +298,7 @@ int main() {
                return 0;
        }
 
-       /* Start a discovery query*/
-       char szQueryUri[64] = { 0 };
-       strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
-       cbData.cb = clientApplicationCB;
-       cbData.context = (void*)CTX_VAL;
-       if (OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_NON_CONFIRMABLE, &cbData)
-                       != OC_STACK_OK) {
-               OC_LOG(ERROR, TAG, "OCStack resource error");
-               return 0;
-       }
+    InitDiscovery();
 
        // Break from loop with Ctrl+C
        OC_LOG(INFO, TAG, "Entering occlient main loop...");
index 899bf9f..d4bd3f5 100644 (file)
@@ -92,26 +92,26 @@ void handleSigInt(int signum) {
        }
 }
 
-void * ChangeLEDRepresentation (void *param)
+void *ChangeLEDRepresentation (void *param)
 {
     (void)param;
     OCStackResult result = OC_STACK_ERROR;
 
     while (1)
     {
-        sleep (15);
+        sleep(10);
         LED.power += 5;
         if (gLEDUnderObservation)
         {
                OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", LED.power);
             result = OCNotifyObservers (LED.handle);
-            printf ("==========> Result from stack: %s\n", getResult(result));
             if (OC_STACK_NO_OBSERVERS == result)
             {
                 gLEDUnderObservation = 0;
             }
         }
     }
+    return NULL;
 }
 
 int main() {
index 298d2cf..2a563b2 100644 (file)
@@ -20,6 +20,7 @@
 
 
 #include "occlientcb.h"
+#include "occoap.h"
 #include "utlist.h"
 #include "logger.h"
 #include <string.h>
@@ -29,7 +30,7 @@
 
 static struct ClientCB *cbList = NULL;
 
-OCStackResult AddClientCB(ClientCB* clientCB, OCCallbackData* cbData, OCCoAPToken * token, OCDoHandle * handle, OCMethod method) {
+OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData, OCCoAPToken * token, OCDoHandle handle, OCMethod method) {
     ClientCB *cbNode;
     cbNode = (ClientCB*) OCMalloc(sizeof(ClientCB));
     if (cbNode) {
@@ -38,21 +39,20 @@ OCStackResult AddClientCB(ClientCB* clientCB, OCCallbackData* cbData, OCCoAPToke
         cbNode->token = token;
         cbNode->handle = handle;
         cbNode->method = method;
+        cbNode->sequenceNumber = 0;
         LL_APPEND(cbList, cbNode);
-        clientCB = cbNode;
+        *clientCB = cbNode;
         return OC_STACK_OK;
     }
-    clientCB = NULL;
+    *clientCB = NULL;
     return OC_STACK_NO_MEMORY;
 }
 
 void DeleteClientCB(ClientCB * cbNode) {
     if(cbNode) {
         LL_DELETE(cbList, cbNode);
-        if(cbNode->token) {
-            OCFree(cbNode->token);
-            cbNode->token = NULL;
-        }
+        OCFree(cbNode->token);
+        OCFree(cbNode->handle);
         OCFree(cbNode);
         cbNode = NULL;
     }
index 3c4ea5c..92ab227 100644 (file)
@@ -41,6 +41,7 @@ OCStackResult AddObserver (const char   *resUri,
                            size_t       tokenLength,
                            OCDevAddr    *addr,
                            OCResource   *resHandle);
+OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength);
 
 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
 {
@@ -49,23 +50,28 @@ OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
     OCObserveReq *obs = request->observe;
 
     OC_LOG(INFO, TAG, "Entering ProcessObserveRequest");
-    printf ("Observer option: %s\n", obs->option);
     if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_REGISTER) == 0) {
+        if (NULL == resource)
+        {
+            return OC_STACK_ERROR;
+        }
         // Register new observation
-        printf ("Register new observation\n\n");
+        request->entityHandlerRequest->resource = (OCResourceHandle)resource;
         result = resource->entityHandler(OC_OBSERVE_FLAG, request->entityHandlerRequest);
         if (OC_STACK_OK == result)
         {
             // Add subscriber to the server observation list
             result = AddObserver ((const char*)(request->resourceUrl), (const char *)(ehReq->query), 
-                                   obs->coapToken, obs->coapTokenLen, obs->subAddr, resource);
+                                   obs->token->token, obs->token->tokenLength, obs->subAddr, resource);
         } 
         return result;
-    } else if (strcmp ((char *)request->observe, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) {
+    } else if (strcmp ((char *)obs->option, OC_RESOURCE_OBSERVE_DEREGISTER) == 0) {
         // Deregister observation
-        return OC_STACK_NOTIMPL;
+        result = DeleteObserver (obs->token->token, obs->token->tokenLength);
+        return result;
     } else {
         // Invalid option
+        OC_LOG(ERROR, TAG, "Invalid CoAP observe option");
         return OC_STACK_INVALID_OBSERVE_PARAM;
     }
 }
@@ -106,8 +112,7 @@ OCStackResult SendObserverNotification (OCResourceHandle handle, OCResource *res
             result = resPtr->entityHandler (OC_REQUEST_FLAG, &entityHandlerReq);
             if (OC_STACK_OK == result)
             {
-                printf ("Calling OCCoAPSendMessage: Payload: %s\n", entityHandlerReq.resJSONPayload);
-                OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->coapTok,
+                OCCoAPSendMessage (obsRes->addr, result, qos, obsRes->token,
                                    (const char *)entityHandlerReq.resJSONPayload,
                                     resPtr->sequenceNum);
             }
@@ -140,9 +145,9 @@ OCStackResult AddObserver (const char   *resUri,
         obsNode->query = (unsigned char *)OCMalloc(sizeof(strlen(query)+1));
         VERIFY_NON_NULL (obsNode->query);
         memcpy (obsNode->query, query, sizeof(strlen(query)+1));
-        obsNode->coapTok = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
-        VERIFY_NON_NULL (obsNode->coapTok);
-        tokPtr = obsNode->coapTok;
+        obsNode->token = (OCCoAPToken *)OCMalloc(sizeof(OCCoAPToken));
+        VERIFY_NON_NULL (obsNode->token);
+        tokPtr = obsNode->token;
         memcpy (tokPtr->token, token, sizeof(OCCoAPToken));
         tokPtr->tokenLength = tokenLength;
         obsNode->addr = (OCDevAddr *)OCMalloc(sizeof(OCDevAddr));
@@ -157,8 +162,54 @@ OCStackResult AddObserver (const char   *resUri,
 exit:
     OCFree(obsNode->resUri);
     OCFree(obsNode->query);
-    OCFree(obsNode->coapTok);
+    OCFree(obsNode->token);
     OCFree(obsNode->addr);
     OCFree(obsNode);
     return OC_STACK_NO_MEMORY;
 }
+
+ObserveResourceServer* GetObserver (const uint8_t *token, const size_t tokenLength)
+{
+    ObserveResourceServer *out = NULL;
+
+    if(token) 
+    {
+        LL_FOREACH (serverObsList, out) 
+        {
+            if((out->token->tokenLength == tokenLength) &&
+               (memcmp(out->token->token, token, tokenLength) == 0)) {
+                return out;
+            }
+        }
+    }
+    OC_LOG(INFO, MOD_NAME, PCF("Observer node not found!!"));
+    return NULL;
+}
+
+OCStackResult DeleteObserver (uint8_t *token, size_t tokenLength)
+{
+    ObserveResourceServer *obsNode = NULL;
+
+    obsNode = GetObserver (token, tokenLength);
+    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;
+}
+
+void DeleteObserverList() 
+{
+    ObserveResourceServer *out;
+    ObserveResourceServer *tmp;
+    LL_FOREACH_SAFE (serverObsList, out, tmp) 
+    {
+        DeleteObserver (out->token->token, out->token->tokenLength);
+    }
+    serverObsList = NULL;
+}
index 075763b..cea6415 100644 (file)
@@ -31,9 +31,6 @@
 #include "ocrandom.h"
 #include "debug.h"
 #include "occoap.h"
-#include "cJSON.h"
-#include <string.h>
-#include <stdlib.h>
 
 //-----------------------------------------------------------------------------
 // Typedefs
@@ -89,17 +86,18 @@ OCStackResult HandleStackRequests(OCRequest * request) {
         OCResource* resource = FindResourceByUri((const char*)request->resourceUrl);
         if (resource)
         {
+            request->entityHandlerRequest->resource = (OCResourceHandle)resource;
             result = resource->entityHandler(OC_REQUEST_FLAG, request->entityHandlerRequest);
-            if (request->observe != NULL)
-            {
-                printf ("\n *** An observe is included in message \n");
-                ProcessObserveRequest (resource, request);
-            }
         }
         else
         {
+            OC_LOG(INFO, TAG, "Resource Not found");
             result = OC_STACK_NO_RESOURCE;
         }
+        if (request->observe != NULL)
+        {
+            result = ProcessObserveRequest (resource, request);
+        }
     }
 
     return result;
@@ -107,24 +105,16 @@ OCStackResult HandleStackRequests(OCRequest * request) {
 
 //This function will be called back by occoap layer when a response is received
 void HandleStackResponses(OCResponse * response) {
-    ClientCB * cbNode = NULL;
     OCStackApplicationResult result = OC_STACK_DELETE_TRANSACTION;
-    OC_LOG(INFO, TAG, "Entering OCHandleClientReceiveResponse (OCStack Layer)");
+    OC_LOG(INFO, TAG, "Entering HandleStackResponses (OCStack Layer)");
 
-    TODO ("What does the stack does in case of error");
-    if (response->clientResponse->result != OC_STACK_OK) {
-        OC_LOG(DEBUG, TAG, "The response has an error, should we do anything?");
-    }
-
-    cbNode = GetClientCB(NULL, response->handle);
-    if (cbNode) {
+    if (response->cbNode) {
         OC_LOG(INFO, TAG, PCF("Calling into application address space"));
-        result = cbNode->callBack(cbNode->context, response->clientResponse);
+        result = response->cbNode->callBack(response->cbNode->context, response->cbNode->handle, response->clientResponse);
         if (result == OC_STACK_DELETE_TRANSACTION) {
-            DeleteClientCB(cbNode);
+            DeleteClientCB(response->cbNode);
         }
     }
-    TODO ("What does the stack does in case of error");
 }
 
 int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr) {
@@ -167,7 +157,7 @@ int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr) {
 // Private internal function prototypes
 //-----------------------------------------------------------------------------
 
-OCDoHandle *generateInvocationHandle();
+static OCDoHandle GenerateInvocationHandle();
 static void initResources();
 static void insertResource(OCResource *resource);
 static OCResource *findResource(OCResource *resource);
@@ -265,6 +255,8 @@ OCStackResult OCStop() {
 
     // Make call to OCCoAP layer
     if (OCStopCoAP() == 0) {
+        // Remove all observers
+        DeleteObserverList();
         // Remove all the client callbacks
         DeleteClientCBList();
         stackState = OC_STACK_UNINITIALIZED;
@@ -298,8 +290,8 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
                            const char *referenceUri, const char *request,
                            OCQualityOfService qos, OCCallbackData *cbData)
 {
-    OCDoHandle * _handle;
-    OCCoAPToken * _token;
+    OCStackResult result = OC_STACK_ERROR;
+    OCCoAPToken * token = NULL;
     ClientCB *clientCB = NULL;
     (void) referenceUri;
 
@@ -309,17 +301,14 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
     VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
     VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
 
-    _handle = generateInvocationHandle();
-    *handle = *_handle;
-    _token = OCGenerateCoAPToken();
-    if(AddClientCB(clientCB, cbData, _token, handle, method) != OC_STACK_OK) {
-        return OC_STACK_NO_MEMORY;
-    }
+    TODO ("Need to form the final query by concatenating require and reference URI's");
+    VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
 
     switch (method)
     {
         case OC_REST_GET:
         case OC_REST_PUT:
+            break;
         case OC_REST_OBSERVE:
         case OC_REST_OBSERVE_ALL:
             break;
@@ -328,23 +317,37 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
             return OC_STACK_INVALID_METHOD;
     }
 
-    TODO ("Need to form the final query by concatenating require and reference URI's");
-    // Validate required URI
-    VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
-
-    if (method == OC_REST_OBSERVE)
+    *handle = GenerateInvocationHandle();
+    VERIFY_NON_NULL(*handle, FATAL, OC_STACK_ERROR);
+    token = OCGenerateCoAPToken();
+    if (!token)
     {
-        printf ("\n\n ********* OBSERVE REGISTRATION ******* \n\n");
+        goto exit;
     }
-    // Make call to OCCoAP layer
-    if (OCDoCoAPResource(method, qos, _token, requiredUri, request) == OC_COAP_OK) {
-        OC_LOG(INFO, TAG, "Done with this function");
-        return OC_STACK_OK;
+    if((result = AddClientCB(&clientCB, cbData, token, *handle, method)) != OC_STACK_OK)
+    {
+        goto exit;
     }
 
-    OC_LOG(ERROR, TAG, PCF("Stack stop error"));
-    DeleteClientCB(clientCB);
-    return OC_STACK_ERROR;
+    // Make call to OCCoAP layer
+    result = 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);
+        }
+    }
+    return result;
 }
 
 /**
@@ -357,15 +360,40 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
  *     OC_STACK_INVALID_PARAM    - The handle provided is invalid.
  */
 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.
+     *
+     * 2. When OCCancel is called, and it is associated with an observe request
+     *      (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
+     *      Send Observe request to server with observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
+     *      Remove the callback associated on client side.
+     *
+     *      Number 1 is implemented here.
+     */
     if(!handle) {
         return OC_STACK_INVALID_PARAM;
     }
+
+    OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
+
     ClientCB *clientCB = GetClientCB(NULL, handle);
+
     if(clientCB) {
-        DeleteClientCB(clientCB);
-        return OC_STACK_OK;
+        switch (clientCB->method)
+        {
+            case OC_REST_OBSERVE:
+            case OC_REST_OBSERVE_ALL:
+                // Make call to OCCoAP layer
+                    DeleteClientCB(clientCB);
+                break;
+            default:
+                return OC_STACK_INVALID_METHOD;
+        }
     }
-    return OC_STACK_INVALID_PARAM;
+    return OC_STACK_OK;
 }
 
 /**
@@ -489,7 +517,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
         OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
         goto exit;
     }
-    
+
     // added [CL]
     result = OCBindResourceHandler((OCResourceHandle) pointer, entityHandler);
     if (result != OC_STACK_OK) {
@@ -500,7 +528,9 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
     *handle = pointer;
     result = OC_STACK_OK;
 
-    exit: if (result != OC_STACK_OK) {
+exit:
+    if (result != OC_STACK_OK)
+    {
         OCFree(pointer);
         OCFree(str);
     }
@@ -1069,12 +1099,11 @@ OCStackResult OCNotifyObservers(OCResourceHandle handle) {
     OCResource *resPtr = NULL;
     OCStackResult result;
 
-    OC_LOG(INFO, TAG, PCF("====>Entering OCNotifyObservers"));
+    OC_LOG(INFO, TAG, PCF("Entering OCNotifyObservers"));
 
     VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
 
     // Verify that the resource exists
-    printf ("====> Finding resource\n");
     resPtr = findResource ((OCResource *) handle);
     if (NULL == resPtr)
     {
@@ -1091,13 +1120,15 @@ OCStackResult OCNotifyObservers(OCResourceHandle handle) {
 /**
  * Generate handle of OCDoResource invocation for callback management.
  */
-OCDoHandle *generateInvocationHandle() {
-    OCDoHandle *handle = NULL;
-    uint8_t val = sizeof(uint8_t[MAX_TOKEN_LENGTH]);
+static OCDoHandle GenerateInvocationHandle()
+{
+    OCDoHandle handle = NULL;
     // Generate token here, it will be deleted when the transaction is deleted
-    handle = (OCDoHandle *) malloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
-    memset(handle, 0, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
-    OCFillRandomMem((uint8_t*)handle, val);
+    handle = (OCDoHandle) malloc(sizeof(uint8_t[MAX_TOKEN_LENGTH]));
+    if (handle)
+    {
+        OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[MAX_TOKEN_LENGTH]));
+    }
 
     return handle;
 }
@@ -1363,8 +1394,6 @@ void *OCMalloc(size_t size) {
 
 void OCFree(void *ptr) {
     TODO ("This should be moved into an ocmalloc dir and implemented as a separate OC module");
-    if(ptr) {
-        free(ptr);
-    }
+    free(ptr);
 }