#include "coap_time.h"
#include "utlist.h"
#include "pdu.h"
+#include "cJSON.h"
#ifndef ARDUINO
#include <arpa/inet.h>
* @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
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)
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,
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;
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);
parsePresencePayload(responseInfo->info.payload,
&(response.sequenceNumber),
&maxAge,
+ &presenceTrigger,
&resourceTypeName);
}
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.
// 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()
if(presenceResource.handle)
{
((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
- SendPresenceNotification(pointer->rsrcType);
+ SendPresenceNotification(pointer->rsrcType, OC_PRESENCE_TRIGGER_CREATE);
}
#endif
exit:
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;
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;
if(presenceResource.handle)
{
((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
- SendPresenceNotification(resource->rsrcType);
+ SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
}
#endif
if(presenceResource.handle)
{
((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
- SendPresenceNotification(resource->rsrcType);
+ SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
}
#endif
if(presenceResource.handle)
{
((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
- SendPresenceNotification(resource->rsrcType);
+ SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
}
#endif
}
#ifdef WITH_PRESENCE
-OCStackResult SendPresenceNotification(OCResourceType *resourceType)
+OCStackResult SendPresenceNotification(OCResourceType *resourceType,
+ OCPresenceTrigger trigger)
{
OCResource *resPtr = NULL;
OCStackResult result = OC_STACK_ERROR;
{
maxAge = presenceResource.presenceTTL;
- result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
+ result = SendAllObserverNotification(method, resPtr, maxAge,
+ trigger, resourceType, OC_LOW_QOS);
}
return result;
}
// 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;
}
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
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.