From cfc48d24897c67536758b804e1d798d17271ccfc Mon Sep 17 00:00:00 2001 From: Sashi Penta Date: Mon, 23 Feb 2015 22:09:08 -0800 Subject: [PATCH] Fix Presence notification issues. * Handle duplicate stop notification on the client side. * Once StopPresence is called on the server, no more notifications are sent. Fixes IOT-66. * Correct implementation for sending the presence notification when unbinding. Change-Id: I112a1ef2cb5c04d847c0c83f5309d67acdc4c1fb Signed-off-by: Sashi Penta Reviewed-on: https://gerrit.iotivity.org/gerrit/402 Tested-by: jenkins-iotivity Reviewed-by: Patrick Lankswert --- .../csdk/stack/include/internal/ocstackinternal.h | 1 + resource/csdk/stack/src/ocstack.c | 190 ++++++++++++++------- 2 files changed, 130 insertions(+), 61 deletions(-) diff --git a/resource/csdk/stack/include/internal/ocstackinternal.h b/resource/csdk/stack/include/internal/ocstackinternal.h index e02ee39..7f5d366 100644 --- a/resource/csdk/stack/include/internal/ocstackinternal.h +++ b/resource/csdk/stack/include/internal/ocstackinternal.h @@ -173,6 +173,7 @@ OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest); OCStackResult HandleStackResponses(OCResponse * response); #ifdef WITH_PRESENCE OCStackResult SendPresenceNotification(OCResourceType *resourceType); +OCStackResult SendStopNotification(); #endif // WITH_PRESENCE int ParseIPv4Address(unsigned char * ipAddrStr, uint8_t * ipAddr, uint16_t * port); diff --git a/resource/csdk/stack/src/ocstack.c b/resource/csdk/stack/src/ocstack.c index 2bd3591..e505e2b 100644 --- a/resource/csdk/stack/src/ocstack.c +++ b/resource/csdk/stack/src/ocstack.c @@ -395,6 +395,7 @@ void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, cha tok = strtok_r(NULL, "[:]}", &savePtr); payload[strlen((char *)payload)] = ':'; *seqNum = (uint32_t) atoi(tok); + tok = strtok_r(NULL, "[:]}", &savePtr); *maxAge = (uint32_t) atoi(tok); tok = strtok_r(NULL, "[:]}",&savePtr); @@ -502,62 +503,79 @@ OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint, &resourceTypeName); } - if(maxAge == 0) + if(presenceSubscribe) { - OC_LOG(INFO, TAG, PCF("===============Stopping presence")); - response.result = OC_STACK_PRESENCE_STOPPED; - if(cbNode->presence) + if(cbNode->sequenceNumber == response.sequenceNumber) { - OCFree(cbNode->presence->timeOut); - OCFree(cbNode->presence); - cbNode->presence = NULL; + OC_LOG(INFO, TAG, PCF("===============No presence change")); + goto exit; } - } - else if(presenceSubscribe) - { - if(!cbNode->presence) + + if(maxAge == 0) { - cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence)); - VERIFY_NON_NULL_V(cbNode->presence); - cbNode->presence->timeOut = NULL; - cbNode->presence->timeOut = (uint32_t *) - OCMalloc(PresenceTimeOutSize * sizeof(uint32_t)); - if(!(cbNode->presence->timeOut)){ + OC_LOG(INFO, TAG, PCF("===============Stopping presence")); + response.result = OC_STACK_PRESENCE_STOPPED; + if(cbNode->presence) + { + OCFree(cbNode->presence->timeOut); OCFree(cbNode->presence); - result = OC_STACK_NO_MEMORY; + cbNode->presence = NULL; } } - - OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %u", GetTime(0)); - cbNode->presence->TTL = maxAge; - for(int index = 0; index < PresenceTimeOutSize; index++) - { - lowerBound = GetTime(((float)(PresenceTimeOut[index]) - /(float)100)*(float)cbNode->presence->TTL); - higherBound = GetTime(((float)(PresenceTimeOut[index + 1]) - /(float)100)*(float)cbNode->presence->TTL); - cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound); - OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout %d", lowerBound); - OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound); - OC_LOG_V(DEBUG, TAG, "----------------timeOut entry %d", - cbNode->presence->timeOut[index]); - } - cbNode->presence->TTLlevel = 0; - OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel); - if(cbNode->sequenceNumber == response.sequenceNumber) + else { - OC_LOG(INFO, TAG, PCF("===============No presence change")); - goto exit; - } - OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack")); - cbNode->sequenceNumber = response.sequenceNumber; + if(!cbNode->presence) + { + cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence)); - // Ensure that a filter is actually applied. - if(resourceTypeName && cbNode->filterResourceType) - { - if(!findResourceType(cbNode->filterResourceType, resourceTypeName)) + if(!(cbNode->presence)) + { + OC_LOG(ERROR, TAG, PCF("Could not allocate memory for cbNode->presence")); + result = OC_STACK_NO_MEMORY; + goto exit; + } + + VERIFY_NON_NULL_V(cbNode->presence); + cbNode->presence->timeOut = NULL; + cbNode->presence->timeOut = (uint32_t *) + OCMalloc(PresenceTimeOutSize * sizeof(uint32_t)); + if(!(cbNode->presence->timeOut)){ + OC_LOG(ERROR, TAG, + PCF("Could not allocate memory for cbNode->presence->timeOut")); + OCFree(cbNode->presence); + result = OC_STACK_NO_MEMORY; + goto exit; + } + } + + OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %u", GetTime(0)); + cbNode->presence->TTL = maxAge; + for(int index = 0; index < PresenceTimeOutSize; index++) { - goto exit; + lowerBound = GetTime(((float)(PresenceTimeOut[index]) + /(float)100)*(float)cbNode->presence->TTL); + higherBound = GetTime(((float)(PresenceTimeOut[index + 1]) + /(float)100)*(float)cbNode->presence->TTL); + cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound); + OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout %d", lowerBound); + OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound); + OC_LOG_V(DEBUG, TAG, "----------------timeOut entry %d", + cbNode->presence->timeOut[index]); + } + cbNode->presence->TTLlevel = 0; + OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel); + + + OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack")); + cbNode->sequenceNumber = response.sequenceNumber; + + // Ensure that a filter is actually applied. + if(resourceTypeName && cbNode->filterResourceType) + { + if(!findResourceType(cbNode->filterResourceType, resourceTypeName)) + { + goto exit; + } } } } @@ -576,6 +594,12 @@ OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint, goto exit; } mcNode->nonce = response.sequenceNumber; + + if(maxAge == 0) + { + OC_LOG(INFO, TAG, PCF("===============Stopping presence")); + response.result = OC_STACK_PRESENCE_STOPPED; + } } else { @@ -598,6 +622,7 @@ OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint, OC_LOG(INFO, TAG, PCF("===============No Memory for Multicast Presence Node")); result = OC_STACK_NO_MEMORY; + OCFree(uri); goto exit; } } @@ -2143,13 +2168,25 @@ OCStackResult OCStartPresence(const uint32_t ttl) OCStackResult OCStopPresence() { OCStackResult result = OC_STACK_ERROR; - //make resource inactive + + if(presenceResource.handle) + { + ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); + } + + // make resource inactive result = OCChangeResourceProperty( &(((OCResource *) presenceResource.handle)->resourceProperties), OC_ACTIVE, 0); - result = SendPresenceNotification(NULL); - return result; + if(result != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, + PCF("Changing the presence resource properties to ACTIVE not successful")); + return result; + } + + return SendStopNotification(); } #endif @@ -2458,20 +2495,22 @@ OCStackResult OCUnBindResource( if (resourceHandle == resource->rsrcResources[i]) { resource->rsrcResources[i] = (OCResource *) NULL; OC_LOG(INFO, TAG, PCF("resource unbound")); + + // Send notification when resource is unbounded successfully. + #ifdef WITH_PRESENCE + if(presenceResource.handle) + { + ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); + SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType); + } + #endif + return OC_STACK_OK; } } OC_LOG(INFO, TAG, PCF("resource not found in collection")); - #ifdef WITH_PRESENCE - if(presenceResource.handle) - { - ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); - SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType); - } - #endif - // Unable to add resourceHandle, so return error return OC_STACK_ERROR; } @@ -2978,12 +3017,17 @@ void incrementSequenceNumber(OCResource * resPtr) * that was modified. * @param qos - Quality Of Service * + * @return + * OC_STACK_OK - no errors + * OC_STACK_ERROR - stack process error */ #ifdef WITH_PRESENCE + + OCStackResult SendPresenceNotification(OCResourceType *resourceType) { OCResource *resPtr = NULL; - OCStackResult result; + OCStackResult result = OC_STACK_ERROR; OCMethod method = OC_REST_PRESENCE; uint32_t maxAge = 0; resPtr = findResource((OCResource *) presenceResource.handle); @@ -2991,19 +3035,43 @@ OCStackResult SendPresenceNotification(OCResourceType *resourceType) { return OC_STACK_NO_RESOURCE; } + if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE) { maxAge = presenceResource.presenceTTL; + + result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS); } - else + + return result; +} + +/** + * Send Stop Notification to Presence subscribers + * + * @return + * OC_STACK_OK - no errors + * OC_STACK_ERROR - stack process error + * + */ + +OCStackResult SendStopNotification() +{ + OCResource *resPtr = NULL; + OCStackResult result = OC_STACK_ERROR; + OCMethod method = OC_REST_PRESENCE; + resPtr = findResource((OCResource *) presenceResource.handle); + if(NULL == resPtr) { - maxAge = 0; + return OC_STACK_NO_RESOURCE; } - result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS); + // maxAge is 0. ResourceType is NULL. + result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS); return result; } + #endif // WITH_PRESENCE /** * Notify observers that an observed value has changed. -- 2.7.4