Converting OTA payload for advertisements to JSON packaging.
authorJoseph Morrow <joseph.l.morrow@intel.com>
Thu, 28 May 2015 16:10:28 +0000 (12:10 -0400)
committerErich Keane <erich.keane@intel.com>
Thu, 28 May 2015 22:32:01 +0000 (22:32 +0000)
This commit ensures that presence advertisments comply with section
11.3.4, wrt. Table 21 of the OIC Core Specification 0.9. This further
ensures that any OIC Core Spec Compliant project will be able to
send/receive advertisements with IoTivity.

Change-Id: I4df50b5a7e322c6e1c2f422de4de1b5b38fa0af9
Signed-off-by: Joseph Morrow <joseph.l.morrow@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1123
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Mandeep Shetty <mandeep.shetty@intel.com>
Reviewed-by: Erich Keane <erich.keane@intel.com>
resource/csdk/stack/include/internal/ocobserve.h
resource/csdk/stack/include/internal/ocstackinternal.h
resource/csdk/stack/include/ocstack.h
resource/csdk/stack/include/octypes.h
resource/csdk/stack/src/ocobserve.c
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocstack.c
resource/csdk/stack/test/SConscript
resource/csdk/stack/test/stacktests.cpp

index fc76777..08f72c9 100644 (file)
@@ -74,7 +74,7 @@ typedef struct ResourceObserver
  * @return ::OC_STACK_OK on success, some other value upon failure.
  */
 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
-        OCResourceType *resourceType, OCQualityOfService qos);
+        OCPresenceTrigger trigger, OCResourceType *resourceType, OCQualityOfService qos);
 #else
 /**
  * Create an observe response and send to all observers in the observe list.
index 83989a5..76caaea 100644 (file)
@@ -140,16 +140,40 @@ OCStackResult SendDirectStackResponse(const CARemoteEndpoint_t* endPoint, const
         const uint8_t numOptions, const CAHeaderOption_t *options,
         CAToken_t token, uint8_t tokenLength);
 
-
 #ifdef WITH_PRESENCE
 /**
+ * The OCPresenceTrigger enum delineates the three spec-compliant modes for
+ * "Trigger." These enum values are then mapped to JSON strings
+ * "create", "change", "delete", respectively, before getting encoded into
+ * the JSON payload.
+ *
+ * @enum OC_PRESENCE_TRIGGER_CREATE The creation of a resource is associated with
+ *                            this invocation of @ref SendPresenceNotification.
+ * @enum OC_PRESENCE_TRIGGER_CHANGE The change/update of a resource is associated
+ *                            this invocation of @ref SendPresenceNotification.
+ * @enum OC_PRESENCE_TRIGGER_DELETE The deletion of a resource is associated with
+ *                            this invocation of @ref SendPresenceNotification.
+ *
+ */
+typedef enum
+{
+    OC_PRESENCE_TRIGGER_CREATE = 0,
+    OC_PRESENCE_TRIGGER_CHANGE = 1,
+    OC_PRESENCE_TRIGGER_DELETE = 2
+} OCPresenceTrigger;
+
+/**
  * Notify Presence subscribers that a resource has been modified.
  *
  * @param resourceType Handle to the resourceType linked list of resource
  *                     that was modified.
+ * @param trigger The simplified reason this API was invoked. Valid values are
+ *                  @ref OC_PRESENCE_TRIGGER_CREATE, @ref OC_PRESENCE_TRIGGER_CHANGE,
+ *                  @ref OC_PRESENCE_TRIGGER_DELETE.
  * @return ::OC_STACK_OK on success, some other value upon failure.
  */
-OCStackResult SendPresenceNotification(OCResourceType *resourceType);
+OCStackResult SendPresenceNotification(OCResourceType *resourceType,
+        OCPresenceTrigger trigger);
 
 /**
  * Send Stop Notification to Presence subscribers.
@@ -236,6 +260,23 @@ OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
         OCResourceProperty resourceProperties, uint8_t enable);
 #endif
 
+/**
+ * Clones a string IFF its pointer value is not NULL.
+ *
+ * Note: The caller to this function is responsible for calling @ref OCFree
+ * for the destination parameter.
+ *
+ * @param dest The destination string for the string value to be cloned.
+ *
+ * @param src The source for the string value to be to cloned.
+ */
+OCStackResult CloneStringIfNonNull(char **dest, const char *src);
+
+
+const char *convertTriggerEnumToString(OCPresenceTrigger trigger);
+
+OCPresenceTrigger convertTriggerStringToEnum(const char * triggerStr);
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
index 73bcd8c..49b0778 100644 (file)
@@ -27,7 +27,6 @@
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
-#define WITH_PRESENCE
 #define USE_RANDOM_PORT (0)
 
 //-----------------------------------------------------------------------------
index c9dafbb..b6d35d3 100644 (file)
@@ -71,7 +71,9 @@ extern "C" {
 #define OC_RSRVD_RESOURCE_TYPE          "rt"
 #define OC_RSRVD_RESOURCE_TYPE_PRESENCE "oic.wk.ad"
 #define OC_RSRVD_INTERFACE              "if"
-
+#define OC_RSRVD_TTL                    "ttl"
+#define OC_RSRVD_NONCE                  "non"
+#define OC_RSRVD_TRIGGER                "trg"
 
 #define OC_RSRVD_INTERFACE_DEFAULT      "oic.if.baseline"
 #define OC_RSRVD_INTERFACE_LL           "oic.if.ll"
@@ -86,7 +88,13 @@ extern "C" {
 #define OC_RSRVD_HOSTING_PORT           "port"
 #define OC_RSRVD_SERVER_INSTANCE_ID     "sid"
 
-  //**** Platform ****
+//**** Presence "Announcement Triggers" ****
+#define OC_RSRVD_TRIGGER_CREATE         "create"
+#define OC_RSRVD_TRIGGER_CHANGE         "change"
+#define OC_RSRVD_TRIGGER_DELETE         "delete"
+//*******************
+
+//**** Platform ****
 #define OC_RSRVD_PLATFORM_ID            "pi"
 #define OC_RSRVD_MFG_NAME               "mnmn"
 #define OC_RSRVD_MFG_URL                "mnml"
@@ -100,7 +108,7 @@ extern "C" {
 #define OC_RSRVD_SYSTEM_TIME             "st"
 //*******************
 
-  //**** Device ****
+//**** Device ****
 #define OC_RSRVD_DEVICE_ID              "di"
 #define OC_RSRVD_DEVICE_NAME            "n"
 #define OC_RSRVD_SPEC_VERSION           "lcv"
index 654078d..ff573bd 100644 (file)
@@ -27,6 +27,7 @@
 #include "ocrandom.h"
 #include "ocmalloc.h"
 #include "ocserverrequest.h"
+#include "cJSON.h"
 
 #include "utlist.h"
 #include "pdu.h"
 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
 
 static struct ResourceObserver * serverObsList = NULL;
+#ifdef WITH_PRESENCE
+static char* GetJSONStringForPresence(uint32_t ttl, uint32_t nonce,
+        OCPresenceTrigger trigger, OCResourceType *resourceType)
+{
+    cJSON *rootObj = cJSON_CreateObject();
+    if (!rootObj)
+    {
+        return NULL;
+    }
+
+    char *jsonEncodedInfo = NULL;
+    const char * triggerStr = NULL;
+    cJSON_AddItemToObject (rootObj, OC_RSRVD_TTL, cJSON_CreateNumber(ttl));
+
+    cJSON_AddItemToObject (rootObj, OC_RSRVD_NONCE, cJSON_CreateNumber(nonce));
+
+    triggerStr = convertTriggerEnumToString(trigger);
+    cJSON_AddItemToObject (rootObj, OC_RSRVD_TRIGGER, cJSON_CreateString(triggerStr));
+
+    if(resourceType && resourceType->resourcetypename)
+    {
+        cJSON_AddItemToObject (rootObj, OC_RSRVD_RESOURCE_TYPE,
+                cJSON_CreateString(resourceType->resourcetypename));
+    }
+
+    jsonEncodedInfo = cJSON_PrintUnformatted (rootObj);
+
+exit:
+    cJSON_Delete(rootObj);
+
+    return jsonEncodedInfo;
+
+}
+
+static OCStackResult BuildPresenceResponse(char *out, uint16_t *remaining,
+        uint32_t ttl, uint32_t nonce, OCPresenceTrigger trigger,
+        OCResourceType *resourceType)
+{
+    if(!out || !remaining)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OCStackResult ret = OC_STACK_ERROR;
+    char *jsonStr = NULL;
+    uint16_t jsonLen = 0;
 
+    jsonStr = GetJSONStringForPresence(ttl, nonce, trigger, resourceType);
+
+    if(jsonStr)
+    {
+        jsonLen = strlen(jsonStr);
+
+        if (jsonLen < *remaining)
+        {
+            strncpy(out, jsonStr, (jsonLen + 1));
+            *remaining = *remaining - jsonLen;
+            ret = OC_STACK_OK;
+        }
+        else
+        {
+            ret = OC_STACK_ERROR;
+        }
+
+        OCFree(jsonStr);
+    }
+    else
+    {
+        OC_LOG(ERROR, TAG, PCF("Error encoding presence payload."));
+        ret = OC_STACK_ERROR;
+    }
+    return ret;
+}
+#endif // WITH_PRESENCE
 /**
  * Determine observe QOS based on the QOS of the request.
  * The qos passed as a parameter overrides what the client requested.
@@ -95,7 +169,7 @@ static OCQualityOfService DetermineObserverQoS(OCMethod method,
 
 #ifdef WITH_PRESENCE
 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
-        OCResourceType *resourceType, OCQualityOfService qos)
+        OCPresenceTrigger trigger, OCResourceType *resourceType, OCQualityOfService qos)
 #else
 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
         OCQualityOfService qos)
@@ -174,25 +248,24 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
 
                 if(result == OC_STACK_OK)
                 {
-                    // we create the payload here
-                    if(resourceType && resourceType->resourcetypename)
-                    {
-                        snprintf((char *)presenceResBuf, sizeof(presenceResBuf), "%u:%u:%s",
-                                resPtr->sequenceNum, maxAge, resourceType->resourcetypename);
-                    }
-                    else
+                    uint16_t remaining = MAX_RESPONSE_LENGTH;
+                    // create the payload here
+                    result = BuildPresenceResponse(presenceResBuf, &remaining,
+                            maxAge, resPtr->sequenceNum, trigger,
+                            resourceType);
+
+                    if(result == OC_STACK_OK && remaining < MAX_RESPONSE_LENGTH)
                     {
-                        snprintf((char *)presenceResBuf, sizeof(presenceResBuf), "%u:%u",
-                                resPtr->sequenceNum, maxAge);
+                        ehResponse.ehResult = OC_EH_OK;
+                        ehResponse.payload = presenceResBuf;
+                        ehResponse.payloadSize = strlen((const char *)presenceResBuf) + 1;
+                        ehResponse.persistentBufferFlag = 0;
+                        ehResponse.requestHandle = (OCRequestHandle) request;
+                        ehResponse.resourceHandle = (OCResourceHandle) resPtr;
+                        strcpy((char *)ehResponse.resourceUri,
+                                (const char *)resourceObserver->resUri);
+                        result = OCDoResponse(&ehResponse);
                     }
-                    ehResponse.ehResult = OC_EH_OK;
-                    ehResponse.payload = presenceResBuf;
-                    ehResponse.payloadSize = strlen((const char *)presenceResBuf) + 1;
-                    ehResponse.persistentBufferFlag = 0;
-                    ehResponse.requestHandle = (OCRequestHandle) request;
-                    ehResponse.resourceHandle = (OCResourceHandle) resPtr;
-                    strcpy((char *)ehResponse.resourceUri, (const char *)resourceObserver->resUri);
-                    result = OCDoResponse(&ehResponse);
                 }
             }
             #endif
index 7736e3b..976925b 100644 (file)
@@ -818,7 +818,7 @@ HandleVirtualResource (OCServerRequest *request, OCResource* resource)
         else
         {
             if(resource->resourceProperties & OC_ACTIVE){
-                SendPresenceNotification(NULL);
+                SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
             }
         }
         #endif
@@ -1091,24 +1091,6 @@ void DeletePlatformInfo()
     savedPlatformInfo.systemTime = NULL;
 }
 
-static OCStackResult CloneStringIfNonNull(char **dest, char *src)
-{
-    if (src)
-    {
-        *dest = (char*) OCMalloc(strlen(src) + 1);
-        if (!*dest)
-        {
-            return OC_STACK_NO_MEMORY;
-        }
-        strcpy(*dest, src);
-    }
-    else
-    {
-        *dest = NULL;
-    }
-    return OC_STACK_OK;
-}
-
 static OCStackResult DeepCopyPlatFormInfo(OCPlatformInfo info)
 {
     OCStackResult ret = OC_STACK_OK;
index 25d3681..aac4606 100644 (file)
@@ -54,6 +54,7 @@
 #include "coap_time.h"
 #include "utlist.h"
 #include "pdu.h"
+#include "cJSON.h"
 
 #ifndef ARDUINO
 #include <arpa/inet.h>
@@ -123,12 +124,8 @@ OCDeviceEntityHandler defaultDeviceHandler;
  * @param maxAge Time To Live (in seconds).
  * @param resType Resource type.
  */
-// TODO: Not sure if I agree with this.  I think it should be static but it is called in
-// stack/test/stacktests.cpp, not included via a header file.  If we intend to allow it
-// to be called externally, we should change the name to OCParsePresencePayload and make
-// it part of the official public API.  But can't change now due to current API freeze.
-// Another option might be to make non-API utility functions for doing stuff like this.
-void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType);
+void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge,
+        OCPresenceTrigger *presenceTrigger, char** resType);
 
 //-----------------------------------------------------------------------------
 // Private internal function prototypes
@@ -455,6 +452,33 @@ uint32_t GetTicks(uint32_t afterMilliSeconds)
         return UINT32_MAX;
     }
 }
+/**
+ * Clones a string IFF its pointer value is not NULL.
+ *
+ * Note: The caller to this function is responsible for calling @ref OCFree
+ * for the destination parameter.
+ *
+ * @param dest The destination string for the string value to be cloned.
+ *
+ * @param src The source for the string value to be to cloned.
+ */
+OCStackResult CloneStringIfNonNull(char **dest, const char *src)
+{
+    if (src)
+    {
+        *dest = (char*) OCMalloc(strlen(src) + 1);
+        if (!*dest)
+        {
+            return OC_STACK_NO_MEMORY;
+        }
+        strcpy(*dest, src);
+    }
+    else
+    {
+        *dest = NULL;
+    }
+    return OC_STACK_OK;
+}
 
 OCStackResult OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
         uint16_t port, OCDevAddr *ipAddr)
@@ -785,56 +809,144 @@ static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds)
     return OC_STACK_OK;
 }
 
-void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType)
+const char *convertTriggerEnumToString(OCPresenceTrigger trigger)
 {
-    char * tok = NULL;
-    char * savePtr = NULL;
-    // The format of the payload is {"oic":[%u:%u:%s]}
-    // %u : sequence number,
-    // %u : max age
-    // %s : Resource Type (Optional)
-
-    if (!payload || !seqNum || !maxAge || !resType)
+    if(trigger == OC_PRESENCE_TRIGGER_CREATE)
     {
-        return;
+        return OC_RSRVD_TRIGGER_CREATE;
     }
-    tok = strtok_r(payload, "[:]}", &savePtr);
-    payload[strlen(payload)] = ':';
-
-    //Retrieve sequence number
-    tok = strtok_r(NULL, "[:]}", &savePtr);
-    if(tok == NULL)
+    else if(trigger == OC_PRESENCE_TRIGGER_CHANGE)
     {
-        return;
+        return OC_RSRVD_TRIGGER_CHANGE;
     }
-    payload[strlen((char *)payload)] = ':';
-    *seqNum = (uint32_t) atoi(tok);
+    else
+    {
+        return OC_RSRVD_TRIGGER_DELETE;
+    }
+}
 
-    //Retrieve MaxAge
-    tok = strtok_r(NULL, "[:]}", &savePtr);
-    if(tok == NULL)
+OCPresenceTrigger convertTriggerStringToEnum(const char * triggerStr)
+{
+    if(strcmp(triggerStr, OC_RSRVD_TRIGGER_CREATE) == 0)
     {
-        return;
+        return OC_PRESENCE_TRIGGER_CREATE;
+    }
+    else if(strcmp(triggerStr, OC_RSRVD_TRIGGER_CHANGE) == 0)
+    {
+        return OC_PRESENCE_TRIGGER_CHANGE;
+    }
+    else
+    {
+        return OC_PRESENCE_TRIGGER_DELETE;
     }
-    *maxAge = (uint32_t) atoi(tok);
+}
 
-    //Retrieve ResourceType
-    tok = strtok_r(NULL, "[:]}",&savePtr);
-    if(tok == NULL)
+void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge,
+        OCPresenceTrigger *presenceTrigger, char** resType)
+{
+    if(!payload || !seqNum || !maxAge || !presenceTrigger || !resType)
     {
         return;
     }
 
-    *resType = (char *)OCMalloc(strlen(tok) + 1);
-    if(!*resType)
+    cJSON *repObj = cJSON_Parse(payload);
+    cJSON *ocObj = NULL;
+    cJSON *presenceObj = NULL;
+    cJSON *seqNumObj = NULL;
+    cJSON *maxAgeObj = NULL;
+    cJSON *triggerObj = NULL;
+    cJSON *resObj = NULL;
+    size_t size = 0;
+    if(repObj)
     {
-        return;
+        ocObj = cJSON_GetObjectItem(repObj, OC_RSRVD_OC);
+        if(ocObj)
+        {
+            //Presence payloads should only carry one JSON payload. The first
+            //    & only array item is retrieved.
+            presenceObj = cJSON_GetArrayItem(ocObj, 0);
+            if(presenceObj)
+            {
+                seqNumObj = cJSON_GetObjectItem(presenceObj, OC_RSRVD_NONCE);
+                if(seqNumObj)
+                {
+                    *seqNum = seqNumObj->valueint;
+                }
+                else
+                {
+                    OC_LOG(ERROR, TAG, PCF("Nonce (AKA SeqNum) not found in"
+                            " JSON Presence Payload."));
+                    goto exit;
+                }
+                maxAgeObj = cJSON_GetObjectItem(presenceObj, OC_RSRVD_TTL);
+                if(maxAgeObj)
+                {
+                    *maxAge = maxAgeObj->valueint;
+                }
+                else
+                {
+                    OC_LOG(ERROR, TAG, PCF("TTL (AKA MaxAge) not found in"
+                            " JSON Presence Payload."));
+                    goto exit;
+                }
+                triggerObj = cJSON_GetObjectItem(presenceObj,
+                        OC_RSRVD_TRIGGER);
+                if(triggerObj)
+                {
+                    char * triggerStr = triggerObj->valuestring;
+                    *presenceTrigger = convertTriggerStringToEnum(triggerStr);
+                }
+                else
+                {
+                    OC_LOG(ERROR, TAG, PCF("Trigger Reason not found in"
+                            " JSON Presence Payload."));
+                    goto exit;
+                }
+                resObj = cJSON_GetObjectItem(presenceObj,
+                        OC_RSRVD_RESOURCE_TYPE);
+                if(resObj)
+                {
+                    size = strlen(resObj->valuestring) + 1;
+                    *resType = (char *)OCMalloc(size);
+                    if(!*resType)
+                    {
+                        goto exit;
+                    }
+                    strncpy(*resType, resObj->valuestring, size);
+                }
+                else
+                {
+                    OC_LOG(ERROR, TAG, PCF("Resource Type not found in"
+                            " JSON Presence Payload."));
+                    goto exit;
+                }
+            }
+            else
+            {
+                OC_LOG(ERROR, TAG, PCF("JSON Presence Object not found in"
+                        " Presence Payload."));
+                OCFree(*resType);
+                goto exit;
+            }
+        }
+        else
+        {
+            OC_LOG(ERROR, TAG, PCF("JSON Presence Payload does not contain a"
+                                    " valid \"oic\" JSON representation."));
+            OCFree(*resType);
+            goto exit;
+        }
+    }
+    else
+    {
+        OC_LOG(ERROR, TAG, PCF("JSON Presence Payload does map to a valid JSON"
+                " representation."));
+        OCFree(*resType);
+        goto exit;
     }
-    payload[strlen((char *)payload)] = ':';
-    strcpy(*resType, tok);
-    OC_LOG_V(DEBUG, TAG, "resourceTypeName %s", *resType);
 
-    payload[strlen((char *)payload)] = ']';
+exit:
+    cJSON_Delete(repObj);
 }
 
 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
@@ -847,7 +959,7 @@ static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
     OCDevAddr address = {};
     OCStackResult result = OC_STACK_ERROR;
     uint32_t maxAge = 0;
-
+    OCPresenceTrigger presenceTrigger = OC_PRESENCE_TRIGGER_CHANGE;
     char *fullUri = NULL;
     char *ipAddress = NULL;
     int presenceSubscribe = 0;
@@ -908,8 +1020,7 @@ static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
         goto exit;
     }
 
-    // No payload to the application in case of presence
-    response.resJSONPayload = NULL;
+    response.resJSONPayload = responseInfo->info.payload;
     response.result = OC_STACK_OK;
 
     result = UpdateResponseAddr(&address, endPoint);
@@ -932,6 +1043,7 @@ static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
         parsePresencePayload(responseInfo->info.payload,
                                 &(response.sequenceNumber),
                                 &maxAge,
+                                &presenceTrigger,
                                 &resourceTypeName);
     }
 
@@ -995,7 +1107,6 @@ static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
 
             ResetPresenceTTL(cbNode, maxAge);
 
-            OC_LOG(INFO, TAG, PCF("Presence changed, calling up the stack"));
             cbNode->sequenceNumber = response.sequenceNumber;
 
             // Ensure that a filter is actually applied.
@@ -2411,7 +2522,8 @@ OCStackResult OCStartPresence(const uint32_t ttl)
     // a different random 32-bit integer number is used
     ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
 
-    return SendPresenceNotification(NULL);
+    return SendPresenceNotification(((OCResource *)presenceResource.handle)->rsrcType,
+            OC_PRESENCE_TRIGGER_CREATE);
 }
 
 OCStackResult OCStopPresence()
@@ -2600,7 +2712,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        SendPresenceNotification(pointer->rsrcType);
+        SendPresenceNotification(pointer->rsrcType, OC_PRESENCE_TRIGGER_CREATE);
     }
     #endif
 exit:
@@ -2693,7 +2805,8 @@ OCStackResult OCBindResource(
             if(presenceResource.handle)
             {
                 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-                SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
+                SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType,
+                        OC_PRESENCE_TRIGGER_CHANGE);
             }
             #endif
             return OC_STACK_OK;
@@ -2745,7 +2858,8 @@ OCStackResult OCUnBindResource(
             if(presenceResource.handle)
             {
                 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-                SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
+                SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType,
+                        OC_PRESENCE_TRIGGER_CHANGE);
             }
             #endif
             return OC_STACK_OK;
@@ -2876,7 +2990,7 @@ OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        SendPresenceNotification(resource->rsrcType);
+        SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
     }
     #endif
 
@@ -2905,7 +3019,7 @@ OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        SendPresenceNotification(resource->rsrcType);
+        SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
     }
     #endif
 
@@ -3117,7 +3231,7 @@ OCStackResult OCBindResourceHandler(OCResourceHandle handle,
     if(presenceResource.handle)
     {
         ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-        SendPresenceNotification(resource->rsrcType);
+        SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
     }
     #endif
 
@@ -3154,7 +3268,8 @@ void incrementSequenceNumber(OCResource * resPtr)
 }
 
 #ifdef WITH_PRESENCE
-OCStackResult SendPresenceNotification(OCResourceType *resourceType)
+OCStackResult SendPresenceNotification(OCResourceType *resourceType,
+        OCPresenceTrigger trigger)
 {
     OCResource *resPtr = NULL;
     OCStackResult result = OC_STACK_ERROR;
@@ -3170,7 +3285,8 @@ OCStackResult SendPresenceNotification(OCResourceType *resourceType)
     {
         maxAge = presenceResource.presenceTTL;
 
-        result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
+        result = SendAllObserverNotification(method, resPtr, maxAge,
+                trigger, resourceType, OC_LOW_QOS);
     }
 
     return result;
@@ -3188,7 +3304,8 @@ OCStackResult SendStopNotification()
     }
 
     // maxAge is 0. ResourceType is NULL.
-    result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS);
+    result = SendAllObserverNotification(method, resPtr, 0, OC_PRESENCE_TRIGGER_DELETE,
+            NULL, OC_LOW_QOS);
 
     return result;
 }
@@ -3226,7 +3343,8 @@ OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService q
         method = OC_REST_OBSERVE;
         maxAge = MAX_OBSERVE_AGE;
         #ifdef WITH_PRESENCE
-        result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
+        result = SendAllObserverNotification (method, resPtr, maxAge,
+                OC_PRESENCE_TRIGGER_DELETE, NULL, qos);
         #else
         result = SendAllObserverNotification (method, resPtr, maxAge, qos);
         #endif
@@ -3453,14 +3571,7 @@ OCStackResult deleteResource(OCResource *resource)
             if(presenceResource.handle)
             {
                 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
-                if(resource != (OCResource *) presenceResource.handle)
-                {
-                    SendPresenceNotification(resource->rsrcType);
-                }
-                else
-                {
-                    SendPresenceNotification(NULL);
-                }
+                SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_DELETE);
             }
             #endif
             // Only resource in list.
index a331fa3..82c6e09 100644 (file)
@@ -29,9 +29,13 @@ src_dir = stacktest_env.get('SRC_DIR')
 # Build flags
 ######################################################################
 stacktest_env.PrependUnique(CPPPATH = [
+               '../../security/include',
                '../../ocsocket/include',
                '../../logger/include',
+               '../../ocrandom/include',
                '../../stack/include',
+               '../../stack/include/internal',
+               '../../connectivity/api',
                '../../ocmalloc/include',
                '../../extlibs/cjson',
                '../../../oc_logger/include',
index f1a1d60..c20d821 100644 (file)
@@ -22,6 +22,7 @@
 extern "C"
 {
     #include "ocstack.h"
+    #include "ocstackinternal.h"
     #include "logger.h"
     #include "ocmalloc.h"
 }
@@ -1433,7 +1434,8 @@ TEST(StackResourceAccess, DeleteMiddleResource)
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
-    void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType);
+    void parsePresencePayload(char* payload, uint32_t* seqNum,
+            uint32_t* maxAge, OCPresenceTrigger* presenceTrigger, char** resType);
 #ifdef __cplusplus
 }
 #endif // __cplusplus
@@ -1445,59 +1447,76 @@ TEST(StackPresence, ParsePresencePayload)
 
     char payload[100];
     uint32_t seqNum = 0, maxAge = 0;
+    OCPresenceTrigger presenceTrigger = OC_PRESENCE_TRIGGER_CHANGE;
     char * resType = NULL;
 
     //Good Scenario
-    strncpy(payload, "{\"oc\":[100:99:presence]}", sizeof(payload));
-    parsePresencePayload(payload, &seqNum, &maxAge, &resType);
+    strncpy(payload, "{\"oic\":[{\"ttl\":99,\"non\":100,\"trg\":"
+            "\"delete\",\"rt\":\"presence\"}]}", sizeof(payload));
+    parsePresencePayload(payload, &seqNum, &maxAge,
+            &presenceTrigger, &resType);
     EXPECT_TRUE(100 == seqNum);
     EXPECT_TRUE(99 == maxAge);
+    EXPECT_TRUE(OC_PRESENCE_TRIGGER_DELETE == presenceTrigger);
+    EXPECT_TRUE(NULL != resType);
     EXPECT_STREQ("presence", resType);
     OCFree(resType);
 
+    presenceTrigger = OC_PRESENCE_TRIGGER_CHANGE;
+
     //Bad Scenario -- should not result in Seg Fault
-    parsePresencePayload(payload, NULL, &maxAge, &resType);
+    parsePresencePayload(payload, NULL, &maxAge, &presenceTrigger, &resType);
 
     //Bad Scenario
     seqNum = 0; maxAge = 0; resType = NULL;
     strncpy(payload, "{abracadabra}", sizeof(payload));
-    parsePresencePayload(payload, &seqNum, &maxAge, &resType);
+    parsePresencePayload(payload, &seqNum, &maxAge, &presenceTrigger, &resType);
     EXPECT_TRUE(0 == seqNum);
     EXPECT_TRUE(0 == maxAge);
+    EXPECT_TRUE(OC_PRESENCE_TRIGGER_CHANGE == presenceTrigger);
+    EXPECT_TRUE(NULL == resType);
     EXPECT_EQ(NULL, resType);
     OCFree(resType);
 
     //Bad Scenario
     seqNum = 0; maxAge = 0; resType = NULL;
-    strncpy(payload, "{\"oc\":[100]}", sizeof(payload));
-    parsePresencePayload(payload, &seqNum, &maxAge, &resType);
-    EXPECT_TRUE(100 == seqNum);
+    strncpy(payload, "{\"oic\":[100]}", sizeof(payload));
+    parsePresencePayload(payload, &seqNum, &maxAge, &presenceTrigger, &resType);
+    EXPECT_TRUE(0 == seqNum);
     EXPECT_TRUE(0 == maxAge);
+    EXPECT_TRUE(OC_PRESENCE_TRIGGER_CHANGE == presenceTrigger);
+    EXPECT_TRUE(NULL == resType);
     EXPECT_EQ(NULL, resType);
     OCFree(resType);
 
     //Bad Scenario
     seqNum = 0; maxAge = 0; resType = NULL;
-    strncpy(payload, "{\"oc\":[]}", sizeof(payload));
-    parsePresencePayload(payload, &seqNum, &maxAge, &resType);
+    strncpy(payload, "{\"oic\":[]}", sizeof(payload));
+    parsePresencePayload(payload, &seqNum, &maxAge, &presenceTrigger, &resType);
     EXPECT_TRUE(0 == seqNum);
     EXPECT_TRUE(0 == maxAge);
+    EXPECT_TRUE(OC_PRESENCE_TRIGGER_CHANGE == presenceTrigger);
+    EXPECT_TRUE(NULL == resType);
     EXPECT_EQ(NULL, resType);
     OCFree(resType);
 
     //Bad Scenario
     strncpy(payload, "{:]}", sizeof(payload));
-    parsePresencePayload(payload, &seqNum, &maxAge, &resType);
+    parsePresencePayload(payload, &seqNum, &maxAge, &presenceTrigger, &resType);
     EXPECT_TRUE(0 == seqNum);
     EXPECT_TRUE(0 == maxAge);
+    EXPECT_TRUE(OC_PRESENCE_TRIGGER_CHANGE == presenceTrigger);
+    EXPECT_TRUE(NULL == resType);
     EXPECT_EQ(NULL, resType);
     OCFree(resType);
 
     //Bad Scenario
     strncpy(payload, "{:[presence}", sizeof(payload));
-    parsePresencePayload(payload, &seqNum, &maxAge, &resType);
+    parsePresencePayload(payload, &seqNum, &maxAge, &presenceTrigger, &resType);
     EXPECT_TRUE(0 == seqNum);
     EXPECT_TRUE(0 == maxAge);
+    EXPECT_TRUE(OC_PRESENCE_TRIGGER_CHANGE == presenceTrigger);
+    EXPECT_TRUE(NULL == resType);
     EXPECT_EQ(NULL, resType);
     OCFree(resType);
 }