Active Discovery Resource Type Filtering - C SDK & App Changes only.
authorJoseph Morrow <joseph.l.morrow@intel.com>
Sat, 15 Nov 2014 04:34:52 +0000 (23:34 -0500)
committerJoseph Morrow <joseph.l.morrow@intel.com>
Sat, 15 Nov 2014 04:34:52 +0000 (23:34 -0500)
Applying required API changes and tying up a part of the functionality
required for implementing resource type filtering on presence
notifications.

Similar C++ SDK & App changes to follow this commit.

Change-Id: I9a8cd1a3e6e30c5de5788f593ef3efd2891b2f56
Signed-off-by: Omkar Hegde <omkar.m.hegde@intel.com>
Signed-off-by: Joseph Morrow <joseph.l.morrow@intel.com>
resource/csdk/occoap/src/occoap.c
resource/csdk/stack/include/internal/occlientcb.h
resource/csdk/stack/include/internal/ocobserve.h
resource/csdk/stack/include/internal/ocstackinternal.h
resource/csdk/stack/include/ocstack.h
resource/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp
resource/csdk/stack/src/occlientcb.c
resource/csdk/stack/src/ocobserve.c
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocstack.c

index 709f08d..5f3004f 100644 (file)
@@ -312,6 +312,7 @@ uint32_t GetTime(float afterSeconds)
 //This function is called back by libcoap when a response is received
 static void HandleCoAPResponses(struct coap_context_t *ctx,
         const coap_queue_t * rcvdResponse) {
+    uint8_t haltResponse = 0;
     OCResponse * response = NULL;
     OCCoAPToken rcvdToken;
     OCClientResponse clientResponse;
@@ -321,6 +322,7 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
     uint8_t * rcvMaxAgeOption = NULL;
     uint32_t sequenceNumber = OC_RESOURCE_NO_OBSERVE;
     uint32_t maxAge = 0;
+    char * resourceTypeName = NULL;
     OCStackResult result = OC_STACK_ERROR;
     coap_pdu_t *sendPdu = NULL;
     coap_pdu_t * recvPdu = NULL;
@@ -375,7 +377,19 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
         tok = strtok(NULL, ":");
         maxAge = (uint32_t )atoi(tok);
         OC_LOG_V(DEBUG, TAG, "The received TTL is %u", maxAge);
+        tok = strtok(NULL, ":");
         bufRes[strlen((char *)bufRes)] = ':';
+        if(tok) {
+            resourceTypeName = (char *)OCMalloc(strlen(tok));
+            if(!resourceTypeName)
+            {
+                goto exit;
+            }
+            strcpy(resourceTypeName, tok);
+            bufRes[strlen((char *)bufRes)] = ':';
+            OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s",
+                    resourceTypeName);
+        }
     }
     #endif
 
@@ -495,6 +509,16 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
                     OC_LOG(INFO, TAG, "===============Presence changed, calling up the stack");
                     cbNode->sequenceNumber = clientResponse.sequenceNumber;;
                 }
+
+                if(resourceTypeName && response->cbNode->filterResourceType)
+                {
+                    if(strcmp(resourceTypeName,
+                            (const char *)response->cbNode->filterResourceType)!=0)
+                    {
+                        //Ignore presence callback if resource type does not match filter.
+                        haltResponse = 1;
+                    }
+                }
             }
             else if(isMulticastPresence)
             {
@@ -541,7 +565,10 @@ static void HandleCoAPResponses(struct coap_context_t *ctx,
             }
             #endif
         }
-        HandleStackResponses(response);
+        if(!haltResponse)
+        {
+            HandleStackResponses(response);
+        }
     }
     else if(!cbNode && isObserveNotification)
     {
index 0d47ead..0f3a49f 100644 (file)
@@ -61,6 +61,7 @@ typedef struct ClientCB {
     // Struct to hold TTL info for presence
     #ifdef WITH_PRESENCE
     OCPresence * presence;
+    unsigned char * filterResourceType;
     #endif
     // next node in this list
     struct ClientCB    *next;
@@ -83,6 +84,8 @@ extern struct ClientCB *cbList;
  *              Masked in the public API as an 'invocation handle' - Used for callback management.
  * @param[in] requestUri
  *              the resource uri of the request.
+ * @param[in] resourceType
+ *              the resourceType associated with this request.
  *
  * @brief If the handle you're looking for does not exist, the stack will reply with a RST message.
  *
@@ -91,7 +94,7 @@ extern struct ClientCB *cbList;
 //------------------------------------------------------------------------
 OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData,
         OCCoAPToken * token, OCDoHandle handle, OCMethod method,
-        unsigned char * requestUri);
+        unsigned char * requestUri, unsigned char * resourceType);
 
 //-- DeleteClientCB -----------------------------------------------------------
 /** @ingroup ocstack
index 3efc1ad..a84bb98 100644 (file)
@@ -65,7 +65,7 @@ OCStackResult OCObserverStatus(OCCoAPToken * token, uint8_t status);
 OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request);
 
 OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
-        OCQualityOfService qos);
+                                        OCResourceType *resourceType, OCQualityOfService qos);
 
 void DeleteObserverList();
 
index 26ce7af..d082ed6 100644 (file)
@@ -184,6 +184,7 @@ typedef struct {
 //-----------------------------------------------------------------------------
 
 OCStackResult HandleStackRequests(OCRequest * request);
+OCStackResult SendPresenceNotification(OCResourceType *resourceType, OCQualityOfService qos);
 void HandleStackResponses(OCResponse * response);
 int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port);
 
index 3f3dc2d..c6f5357 100644 (file)
@@ -392,6 +392,8 @@ OCStackResult OCProcess();
  *     OC_STACK_INVALID_CALLBACK - invalid callback function pointer
  *     OC_STACK_INVALID_METHOD   - invalid resource method
  *     OC_STACK_INVALID_URI      - invalid required or reference URI
+ *     OC_STACK_INVALID_QUERY    - number of resource types specified for filtering presence
+ *                                 notifications exceeds @ref MAX_PRESENCE_FILTERS.
  */
 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char  *requiredUri, const char  *referenceUri,
                 const char *request, OCQualityOfService qos, OCCallbackData *cbData, OCHeaderOption * options,
index dd185cb..565ed10 100644 (file)
@@ -339,7 +339,8 @@ int InitPresence()
 {
     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
     std::ostringstream query;
-    query << "coap://" << coapServerIP << ":" << coapServerPort << OC_PRESENCE_URI;
+    query << "coap://" << coapServerIP << ":" << coapServerPort << OC_PRESENCE_URI
+            << "?rt=core.led";
     return (InvokeOCDoResource(query, OC_REST_PRESENCE, OC_LOW_QOS, presenceCB, NULL, 0));
 }
 #endif
index 6f97025..e5e98e3 100644 (file)
@@ -34,7 +34,7 @@ OCMulticastNode * mcPresenceNodes = NULL;
 
 OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData,
         OCCoAPToken * token, OCDoHandle handle, OCMethod method,
-        unsigned char * requestUri) {
+        unsigned char * requestUri, unsigned char * resourceType) {
     ClientCB *cbNode;
     cbNode = (ClientCB*) OCMalloc(sizeof(ClientCB));
     if (cbNode) {
@@ -47,6 +47,7 @@ OCStackResult AddClientCB(ClientCB** clientCB, OCCallbackData* cbData,
         cbNode->sequenceNumber = 0;
         #ifdef WITH_PRESENCE
         cbNode->presence = NULL;
+        cbNode->filterResourceType = resourceType;
         #endif
         cbNode->requestUri = requestUri;
         LL_APPEND(cbList, cbNode);
@@ -73,6 +74,7 @@ void DeleteClientCB(ClientCB * cbNode) {
         if(cbNode->presence) {
             OCFree(cbNode->presence->timeOut);
             OCFree(cbNode->presence);
+            OCFree(cbNode->filterResourceType);
         }
         #endif
         OCFree(cbNode);
index 655a01c..68382c0 100644 (file)
@@ -235,7 +235,7 @@ OCStackResult ProcessObserveRequest (OCResource *resource, OCRequest *request)
 }
 
 OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
-        OCQualityOfService qos)
+                OCResourceType *resourceType, OCQualityOfService qos)
 {
     uint8_t numObs = 0;
     OCStackResult stackRet = OC_STACK_ERROR;
@@ -271,11 +271,22 @@ OCStackResult SendObserverNotification (OCMethod method, OCResource *resPtr, uin
             {
                 //we know it is the default entity handler
                 OC_LOG(DEBUG, TAG, "This notification is for Presence");
+
                 // we create the payload here
-                sprintf((char *)bufRes, "%u:%u", resPtr->sequenceNum, maxAge);
+                if(resourceType)
+                {
+                    sprintf((char *)bufRes, "%u:%u:%s",
+                            resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
+                }
+                else
+                {
+                    sprintf((char *)bufRes, "%u:%u", resPtr->sequenceNum, maxAge);
+                }
+
                 jsonPayload = bufRes;
                 ehRet = OC_EH_OK;
             }
+
             #endif
             if (OC_EH_OK == ehRet)
             {
index b47d621..c9ed805 100644 (file)
@@ -434,7 +434,7 @@ HandleVirtualResource (OCRequest *request, OCResource* resource)
         else
         {
             if(resource->resourceProperties & OC_ACTIVE){
-                OCNotifyAllObservers((OCResourceHandle) resource, OC_LOW_QOS);
+                SendPresenceNotification(resource->rsrcType, OC_LOW_QOS);
             }
             result = OC_STACK_PRESENCE_DO_NOT_HANDLE;
         }
index 763e836..61b8368 100644 (file)
@@ -206,6 +206,7 @@ static void deleteAllResources();
 static void incrementSequenceNumber(OCResource * resPtr);
 static OCStackResult verifyUriQueryLength(const char * inputUri,
         uint16_t uriLen);
+OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI);
 
 
 //-----------------------------------------------------------------------------
@@ -380,6 +381,8 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
     OCCoAPToken token;
     ClientCB *clientCB = NULL;
     unsigned char * requestUri = NULL;
+    unsigned char * resourceType = NULL;
+    char * newURI = (char *)requiredUri;
     (void) referenceUri;
 
     OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
@@ -424,10 +427,21 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
         goto exit;
     }
 
+#ifdef WITH_PRESENCE
+    if(method == OC_REST_PRESENCE)
+    {
+        result = getResourceType(requiredUri, &resourceType, &newURI);
+        if(result != OC_STACK_OK)
+        {
+            goto exit;
+        }
+    }
+#endif // WITH_PRESENCE
+
     requestUri = (unsigned char *) OCMalloc(uriLen + 1);
     if(requestUri)
     {
-        memcpy(requestUri, requiredUri, (uriLen + 1));
+        memcpy(requestUri, newURI, (uriLen + 1));
     }
     else
     {
@@ -446,16 +460,21 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ
     // with the request
     OCGenerateCoAPToken(&token);
 
-    if((result = AddClientCB(&clientCB, cbData, &token, *handle, method, requestUri)) != OC_STACK_OK)
+    if((result = AddClientCB(&clientCB, cbData, &token, *handle, method, requestUri, resourceType))
+            != OC_STACK_OK)
     {
         result = OC_STACK_NO_MEMORY;
         goto exit;
     }
 
     // Make call to OCCoAP layer
-    result = OCDoCoAPResource(method, qos, &token, requiredUri, request, options, numOptions);
+    result = OCDoCoAPResource(method, qos, &token, newURI, request, options, numOptions);
 
 exit:
+    if(newURI != requiredUri)
+    {
+        OCFree(newURI);
+    }
     if (result != OC_STACK_OK)
     {
         OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
@@ -672,7 +691,7 @@ OCStackResult OCStartPresence(const uint32_t ttl)
     // a different random 32-bit integer number is used
     ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
 
-    return OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+    return SendPresenceNotification(NULL, OC_LOW_QOS);
 }
 
 /**
@@ -693,7 +712,8 @@ OCStackResult OCStopPresence()
     result = OCChangeResourceProperty(
             &(((OCResource *) presenceResource.handle)->resourceProperties),
             OC_ACTIVE, 0);
-    result = OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+    result = SendPresenceNotification(NULL, OC_LOW_QOS);
+
     return result;
 }
 #endif
@@ -826,7 +846,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+        SendPresenceNotification(pointer->rsrcType, OC_LOW_QOS);
     }
     #endif
 exit:
@@ -939,7 +959,7 @@ OCStackResult OCBindResource(
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+        SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType, OC_LOW_QOS);
     }
     #endif
 
@@ -997,7 +1017,7 @@ OCStackResult OCUnBindResource(
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+        SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType, OC_LOW_QOS);
     }
     #endif
 
@@ -1064,7 +1084,7 @@ OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+        SendPresenceNotification(resource->rsrcType, OC_LOW_QOS);
     }
     #endif
 
@@ -1133,7 +1153,7 @@ OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+        SendPresenceNotification(resource->rsrcType, OC_LOW_QOS);
     }
     #endif
 
@@ -1435,7 +1455,7 @@ OCStackResult OCBindResourceHandler(OCResourceHandle handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+        SendPresenceNotification(resource->rsrcType, OC_LOW_QOS);
     }
     #endif
 
@@ -1478,6 +1498,39 @@ void incrementSequenceNumber(OCResource * resPtr)
     return;
 }
 
+/**
+ * Notify Presence subscribers that a resource has been modified
+ *
+ * @param resourceType - Handle to the resourceType linked list of resource
+ *                       that was modified.
+ * @param qos          - Quality Of Service
+ *
+ */
+OCStackResult SendPresenceNotification(OCResourceType *resourceType, OCQualityOfService qos)
+{
+    OCResource *resPtr = NULL;
+    OCStackResult result;
+    OCMethod method = OC_REST_PRESENCE;
+    uint32_t maxAge = 0;
+    resPtr = findResource((OCResource *) presenceResource.handle);
+    if(NULL == resPtr)
+    {
+        return OC_STACK_NO_RESOURCE;
+    }
+    if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
+    {
+        maxAge = presenceResource.presenceTTL;
+    }
+    else
+    {
+        maxAge = 0;
+    }
+
+    result = SendObserverNotification(method, resPtr, maxAge, resourceType, qos);
+
+    return result;
+}
+
 /**
  * Notify observers that an observed value has changed.
  *
@@ -1500,35 +1553,17 @@ OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService q
 
     // Verify that the resource exists
     resPtr = findResource ((OCResource *) handle);
-    if (NULL == resPtr || myStackMode == OC_CLIENT)
+    if (NULL == resPtr)
     {
         return OC_STACK_NO_RESOURCE;
-    } else {
-        #ifdef WITH_PRESENCE
-        if(strcmp(resPtr->uri, OC_PRESENCE_URI))
-        {
-        #endif
-            //only increment in the case of regular observing (not presence)
-            incrementSequenceNumber(resPtr);
-            method = OC_REST_OBSERVE;
-            maxAge = 0x2FFFF;
-        #ifdef WITH_PRESENCE
-        }
-        else
-        {
-            method = OC_REST_PRESENCE;
-            if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
-            {
-                maxAge = presenceResource.presenceTTL;
-            }
-            else
-            {
-                maxAge = 0;
-            }
-
-        }
-        #endif
-        result = SendObserverNotification (method, resPtr, maxAge, qos);
+    }
+    else
+    {
+        //only increment in the case of regular observing (not presence)
+        incrementSequenceNumber(resPtr);
+        method = OC_REST_OBSERVE;
+        maxAge = 0x2FFFF;
+        result = SendObserverNotification (method, resPtr, maxAge, NULL, qos);
         return result;
     }
 }
@@ -1784,7 +1819,7 @@ int deleteResource(OCResource *resource) {
             if(presenceResource.handle)
             {
                 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-                OCNotifyAllObservers(presenceResource.handle, OC_LOW_QOS);
+                SendPresenceNotification(resource->rsrcType, OC_LOW_QOS);
             }
             #endif
 
@@ -1869,10 +1904,17 @@ void deleteResourceInterface(OCResourceInterface *resourceInterface) {
 void insertResourceType(OCResource *resource, OCResourceType *resourceType) {
     OCResourceType *pointer;
 
-    if (!resource->rsrcType) {
+    if (resource && !resource->rsrcType) {
         resource->rsrcType = resourceType;
     } else {
-        pointer = resource->rsrcType;
+        if(resource)
+        {
+            pointer = resource->rsrcType;
+        }
+        else
+        {
+            pointer = resourceType;
+        }
         while (pointer->next) {
             pointer = pointer->next;
         }
@@ -1976,4 +2018,65 @@ OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
     return pointer;
 }
 
+/**
+ * Retrieves a resource type based upon a uri string if the uri string contains only just one
+ * resource attribute (and that has to be of type "rt").
+ *
+ * @remark This API malloc's memory for the resource type and newURI. Do not malloc resourceType
+ * or newURI before passing in.
+ *
+ * @param uri - Valid URI for "requiredUri" parameter to OCDoResource API.
+ * @param resourceType - The resource type to be populated; pass by reference.
+ * @param newURI - Return URI without resourceType appended to the end of it. This is used to
+ *                 ensure that the uri parameter is not modified; pass by reference.
+ *
+ * @return
+ *  OC_STACK_INVALID_URI   - Returns this if the URI is invalid/NULL.
+ *  OC_STACK_INVALID_PARAM - Returns this if the resourceType parameter is invalid/NULL.
+ *  OC_STACK_OK            - Success
+ */
+OCStackResult getResourceType(const char * uri, unsigned char** resourceType, char ** newURI)
+{
+    if(!uri)
+    {
+        return OC_STACK_INVALID_URI;
+    }
+    if(!resourceType || !newURI)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    char * ptr = NULL;
+    char * leftToken = NULL;
+    char * tempURI = (char *) OCMalloc(strlen(uri));
+    if(!tempURI)
+    {
+        goto exit;
+    }
+    ptr = tempURI;
+    strcpy(tempURI, uri);
+    leftToken = strtok((char *)tempURI, "?");
+
+    while(leftToken != NULL)
+    {
+        if(strncmp(leftToken, "rt=", 3) == 0)
+        {
+            *resourceType = (unsigned char *) OCMalloc(strlen(leftToken)-3);
+            if(!*resourceType)
+            {
+                goto exit;
+            }
+            strcpy((char *)*resourceType, ((const char *)&leftToken[3]));
+            break;
+        }
+        leftToken = strtok(NULL, "?");
+    }
+
+    *newURI = ptr;
+
+    return OC_STACK_OK;
+
+    exit:
+        return OC_STACK_NO_MEMORY;
+}
+