Update snapshot(2017-11-02)
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocobserve.c
index 6bcaa1c..db055ba 100644 (file)
 #include "oic_string.h"
 #include "ocpayload.h"
 #include "ocserverrequest.h"
+#include "octhread.h"
 #include "logger.h"
 
-#include "utlist.h"
-#include "pdu.h"
-
+#include <coap/utlist.h>
+#include <coap/pdu.h>
+#include <coap/coap.h>
 
 // Module Name
 #define MOD_NAME "ocobserve"
 
-#define TAG  "OCStackObserve"
+#define TAG  "OIC_RI_OBSERVE"
+
+#define VERIFY_NON_NULL(arg) { if (!arg) {OIC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
+
+static struct ResourceObserver * g_serverObsList = NULL;
+static oc_mutex g_serverObsListMutex = NULL;
+
+static ResourceObserver* GetObserverUsingIdAsOwner (const OCObservationId observeId);
+
+static ResourceObserver* CloneObserverNode (ResourceObserver* observer)
+{
+    ResourceObserver* dupObsNode = NULL;
+    if (observer)
+    {
+        dupObsNode = (ResourceObserver *) OICCalloc(1, sizeof(ResourceObserver));
+        VERIFY_NON_NULL(dupObsNode);
+        memcpy(dupObsNode, observer, sizeof(ResourceObserver));
+
+        if (observer->resUri)
+        {
+            dupObsNode->resUri = OICStrdup(observer->resUri);
+            VERIFY_NON_NULL(dupObsNode->resUri);
+        }
+
+        if (observer->query)
+        {
+            dupObsNode->query = OICStrdup(observer->query);
+            VERIFY_NON_NULL(dupObsNode->query);
+        }
 
-#define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
+        if (observer->token)
+        {
+            dupObsNode->token = (CAToken_t)OICMalloc(observer->tokenLength);
+            VERIFY_NON_NULL(dupObsNode->token);
+            memcpy(dupObsNode->token, observer->token, observer->tokenLength);
+        }
+
+        dupObsNode->next = NULL;
+    }
+
+    return dupObsNode;
+
+exit:
+    FreeObserver(dupObsNode);
+    return NULL;
+}
+
+static void FreeObserverList (ResourceObserver* list)
+{
+    ResourceObserver* head = list;
+    ResourceObserver* del = NULL;
+    while (NULL != head)
+    {
+        del = head;
+        head = head->next;
+
+        OICFree(del->resUri);
+        OICFree(del->query);
+        OICFree(del->token);
+        OICFree(del);
+    }
+}
+
+static ResourceObserver* CloneObserverList (ResourceObserver* obsList)
+{
+    ResourceObserver* dupList = NULL;
+    ResourceObserver* out = NULL;
+
+    LL_FOREACH(obsList, out)
+    {
+        ResourceObserver *obsNode = CloneObserverNode(out);
+        if (NULL == obsNode)
+        {
+            FreeObserverList(dupList);
+            dupList = NULL;
+            break;
+        }
+
+        LL_APPEND(dupList, obsNode);
+    }
+
+    return dupList;
+}
 
-static struct ResourceObserver * serverObsList = NULL;
 /**
  * Determine observe QOS based on the QOS of the request.
  * The qos passed as a parameter overrides what the client requested.
@@ -57,35 +137,35 @@ static struct ResourceObserver * serverObsList = NULL;
 static OCQualityOfService DetermineObserverQoS(OCMethod method,
         ResourceObserver * resourceObserver, OCQualityOfService appQoS)
 {
-    if(!resourceObserver)
+    if (!resourceObserver)
     {
-        OC_LOG(ERROR, TAG, "DetermineObserverQoS called with invalid resourceObserver");
+        OIC_LOG(ERROR, TAG, "DetermineObserverQoS called with invalid resourceObserver");
         return OC_NA_QOS;
     }
 
     OCQualityOfService decidedQoS = appQoS;
-    if(appQoS == OC_NA_QOS)
+    if (appQoS == OC_NA_QOS)
     {
         decidedQoS = resourceObserver->qos;
     }
 
-    if(appQoS != OC_HIGH_QOS)
+    if (appQoS != OC_HIGH_QOS)
     {
-        OC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
+        OIC_LOG_V(INFO, TAG, "Current NON count for this observer is %d",
                 resourceObserver->lowQosCount);
 #ifdef WITH_PRESENCE
-        if((resourceObserver->forceHighQos \
+        if ((resourceObserver->forceHighQos \
                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT) \
                 && method != OC_REST_PRESENCE)
 #else
-        if(resourceObserver->forceHighQos \
+        if (resourceObserver->forceHighQos \
                 || resourceObserver->lowQosCount >= MAX_OBSERVER_NON_COUNT)
 #endif
         {
             resourceObserver->lowQosCount = 0;
             // at some point we have to to send CON to check on the
             // availability of observer
-            OC_LOG(INFO, TAG, "This time we are sending the  notification as High qos");
+            OIC_LOG(INFO, TAG, "This time we are sending the  notification as High qos");
             decidedQoS = OC_HIGH_QOS;
         }
         else
@@ -96,6 +176,67 @@ static OCQualityOfService DetermineObserverQoS(OCMethod method,
     return decidedQoS;
 }
 
+/**
+ * Create a get request and pass to entityhandler to notify specific observer.
+ *
+ * @param observer Observer that need to be notified.
+ * @param qos Quality of service of resource.
+ *
+ * @return ::OC_STACK_OK on success, some other value upon failure.
+ */
+static OCStackResult SendObserveNotification(ResourceObserver *observer,
+                                             OCQualityOfService qos)
+{
+    OCStackResult result = OC_STACK_ERROR;
+    OCServerRequest * request = NULL;
+    OCEntityHandlerRequest ehRequest = {0};
+    OCEntityHandlerResult ehResult = OC_EH_ERROR;
+
+    result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
+                              0, observer->resource->sequenceNum, qos,
+                              observer->query, NULL, NULL,
+                              observer->token, observer->tokenLength,
+                              observer->resUri, 0, observer->acceptFormat,
+                              &observer->devAddr);
+
+    if (request)
+    {
+        request->observeResult = OC_STACK_OK;
+        if (result == OC_STACK_OK)
+        {
+            result = FormOCEntityHandlerRequest(
+                        &ehRequest,
+                        (OCRequestHandle) request->requestId,
+                        request->method,
+                        &request->devAddr,
+                        (OCResourceHandle) observer->resource,
+                        request->query,
+                        PAYLOAD_TYPE_REPRESENTATION,
+                        request->payload,
+                        request->payloadSize,
+                        request->numRcvdVendorSpecificHeaderOptions,
+                        request->rcvdVendorSpecificHeaderOptions,
+                        OC_OBSERVE_NO_OPTION,
+                        0,
+                        request->coapID);
+            if (result == OC_STACK_OK)
+            {
+                ehResult = observer->resource->entityHandler(OC_REQUEST_FLAG, &ehRequest,
+                                    observer->resource->entityHandlerCallbackParam);
+                if (ehResult == OC_EH_ERROR)
+                {
+                    FindAndDeleteServerRequest(request);
+                }
+                // Reset Observer TTL.
+                observer->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
+            }
+            OCPayloadDestroy(ehRequest.payload);
+        }
+    }
+
+    return result;
+}
+
 #ifdef WITH_PRESENCE
 OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
         OCPresenceTrigger trigger, OCResourceType *resourceType, OCQualityOfService qos)
@@ -104,70 +245,32 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
         OCQualityOfService qos)
 #endif
 {
-    OC_LOG(INFO, TAG, "Entering SendObserverNotification");
-    if(!resPtr)
+    OIC_LOG(INFO, TAG, "Entering SendObserverNotification");
+    if (!resPtr)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
     OCStackResult result = OC_STACK_ERROR;
-    ResourceObserver * resourceObserver = serverObsList;
+    ResourceObserver * resourceObserver = NULL;
     uint8_t numObs = 0;
     OCServerRequest * request = NULL;
-    OCEntityHandlerRequest ehRequest = {0};
-    OCEntityHandlerResult ehResult = OC_EH_ERROR;
     bool observeErrorFlag = false;
 
     // Find clients that are observing this resource
+    oc_mutex_lock(g_serverObsListMutex);
+    resourceObserver = g_serverObsList;
     while (resourceObserver)
     {
         if (resourceObserver->resource == resPtr)
         {
             numObs++;
 #ifdef WITH_PRESENCE
-            if(method != OC_REST_PRESENCE)
+            if (method != OC_REST_PRESENCE)
             {
 #endif
                 qos = DetermineObserverQoS(method, resourceObserver, qos);
-
-                result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
-                        0, resPtr->sequenceNum, qos, resourceObserver->query,
-                        NULL, NULL,
-                        resourceObserver->token, resourceObserver->tokenLength,
-                        resourceObserver->resUri, 0, resourceObserver->acceptFormat,
-                        &resourceObserver->devAddr);
-
-                if(request)
-                {
-                    request->observeResult = OC_STACK_OK;
-                    if(result == OC_STACK_OK)
-                    {
-                        result = FormOCEntityHandlerRequest(
-                                    &ehRequest,
-                                    (OCRequestHandle) request,
-                                    request->method,
-                                    &request->devAddr,
-                                    (OCResourceHandle) resPtr,
-                                    request->query,
-                                    PAYLOAD_TYPE_REPRESENTATION,
-                                    request->payload,
-                                    request->payloadSize,
-                                    request->numRcvdVendorSpecificHeaderOptions,
-                                    request->rcvdVendorSpecificHeaderOptions,
-                                    OC_OBSERVE_NO_OPTION,
-                                    0);
-                        if(result == OC_STACK_OK)
-                        {
-                            ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest,
-                                                resPtr->entityHandlerCallbackParam);
-                            if(ehResult == OC_EH_ERROR)
-                            {
-                                FindAndDeleteServerRequest(request);
-                            }
-                        }
-                        OCPayloadDestroy(ehRequest.payload);
-                    }
-                }
+                result = SendObserveNotification(resourceObserver, qos);
 #ifdef WITH_PRESENCE
             }
             else
@@ -175,7 +278,7 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
                 OCEntityHandlerResponse ehResponse = {0};
 
                 //This is effectively the implementation for the presence entity handler.
-                OC_LOG(DEBUG, TAG, "This notification is for Presence");
+                OIC_LOG(DEBUG, TAG, "This notification is for Presence");
                 result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
                         0, resPtr->sequenceNum, qos, resourceObserver->query,
                         NULL, NULL,
@@ -183,23 +286,24 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
                         resourceObserver->resUri, 0, resourceObserver->acceptFormat,
                         &resourceObserver->devAddr);
 
-                if(result == OC_STACK_OK)
+                if (result == OC_STACK_OK)
                 {
                     OCPresencePayload* presenceResBuf = OCPresencePayloadCreate(
                             resPtr->sequenceNum, maxAge, trigger,
                             resourceType ? resourceType->resourcetypename : NULL);
 
-                    if(!presenceResBuf)
+                    if (!presenceResBuf)
                     {
+                        oc_mutex_unlock(g_serverObsListMutex);
                         return OC_STACK_NO_MEMORY;
                     }
 
-                    if(result == OC_STACK_OK)
+                    if (result == OC_STACK_OK)
                     {
                         ehResponse.ehResult = OC_EH_OK;
                         ehResponse.payload = (OCPayload*)presenceResBuf;
                         ehResponse.persistentBufferFlag = 0;
-                        ehResponse.requestHandle = (OCRequestHandle) request;
+                        ehResponse.requestHandle = (OCRequestHandle) request->requestId;
                         ehResponse.resourceHandle = (OCResourceHandle) resPtr;
                         OICStrcpy(ehResponse.resourceUri, sizeof(ehResponse.resourceUri),
                                 resourceObserver->resUri);
@@ -220,14 +324,16 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
         resourceObserver = resourceObserver->next;
     }
 
+    oc_mutex_unlock(g_serverObsListMutex);
+
     if (numObs == 0)
     {
-        OC_LOG(INFO, TAG, "Resource has no observers");
+        OIC_LOG(INFO, TAG, "Resource has no observers");
         result = OC_STACK_NO_OBSERVERS;
     }
     else if (observeErrorFlag)
     {
-        OC_LOG(ERROR, TAG, "Observer notification error");
+        OIC_LOG(ERROR, TAG, "Observer notification error");
         result = OC_STACK_ERROR;
     }
     return result;
@@ -240,7 +346,7 @@ OCStackResult SendListObserverNotification (OCResource * resource,
         OCQualityOfService qos)
 {
     (void)maxAge;
-    if(!resource || !obsIdList || !payload)
+    if (!resource || !obsIdList || !payload)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -252,11 +358,12 @@ OCStackResult SendListObserverNotification (OCResource * resource,
     OCStackResult result = OC_STACK_ERROR;
     bool observeErrorFlag = false;
 
-    OC_LOG(INFO, TAG, "Entering SendListObserverNotification");
+    OIC_LOG(INFO, TAG, "Entering SendListObserverNotification");
     while(numIds)
     {
-        observer = GetObserverUsingId (*obsIdList);
-        if(observer)
+        oc_mutex_lock(g_serverObsListMutex);
+        observer = GetObserverUsingIdAsOwner (*obsIdList);
+        if (observer)
         {
             // Found observer - verify if it matches the resource handle
             if (observer->resource == resource)
@@ -270,27 +377,28 @@ OCStackResult SendListObserverNotification (OCResource * resource,
                         observer->resUri, 0, observer->acceptFormat,
                         &observer->devAddr);
 
-                if(request)
+                if (request)
                 {
                     request->observeResult = OC_STACK_OK;
-                    if(result == OC_STACK_OK)
+                    if (result == OC_STACK_OK)
                     {
                         OCEntityHandlerResponse ehResponse = {0};
                         ehResponse.ehResult = OC_EH_OK;
                         ehResponse.payload = (OCPayload*)OCRepPayloadCreate();
-                        if(!ehResponse.payload)
+                        if (!ehResponse.payload)
                         {
                             FindAndDeleteServerRequest(request);
+                            oc_mutex_unlock(g_serverObsListMutex);
                             continue;
                         }
                         memcpy(ehResponse.payload, payload, sizeof(*payload));
                         ehResponse.persistentBufferFlag = 0;
-                        ehResponse.requestHandle = (OCRequestHandle) request;
+                        ehResponse.requestHandle = (OCRequestHandle) request->requestId;
                         ehResponse.resourceHandle = (OCResourceHandle) resource;
                         result = OCDoResponse(&ehResponse);
-                        if(result == OC_STACK_OK)
+                        if (result == OC_STACK_OK)
                         {
-                            OC_LOG_V(INFO, TAG, "Observer id %d notified.", *obsIdList);
+                            OIC_LOG_V(INFO, TAG, "Observer id %d notified.", *obsIdList);
 
                             // Increment only if OCDoResponse is successful
                             numSentNotification++;
@@ -300,14 +408,18 @@ OCStackResult SendListObserverNotification (OCResource * resource,
                         }
                         else
                         {
-                            OC_LOG_V(INFO, TAG, "Error notifying observer id %d.", *obsIdList);
+                            OIC_LOG_V(INFO, TAG, "Error notifying observer id %d.", *obsIdList);
                         }
+                        // Reset Observer TTL.
+                        observer->TTL =
+                                GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
                     }
                     else
                     {
                         FindAndDeleteServerRequest(request);
                     }
                 }
+
                 // Since we are in a loop, set an error flag to indicate
                 // at least one error occurred.
                 if (result != OC_STACK_OK)
@@ -316,40 +428,45 @@ OCStackResult SendListObserverNotification (OCResource * resource,
                 }
             }
         }
+
+        oc_mutex_unlock(g_serverObsListMutex);
         obsIdList++;
         numIds--;
     }
 
-    if(numSentNotification == numberOfIds && !observeErrorFlag)
+    if (numSentNotification == numberOfIds && !observeErrorFlag)
     {
         return OC_STACK_OK;
     }
-    else if(numSentNotification == 0)
+    else if (numSentNotification == 0)
     {
         return OC_STACK_NO_OBSERVERS;
     }
     else
     {
-        OC_LOG(ERROR, TAG, "Observer notification error");
+        OIC_LOG(ERROR, TAG, "Observer notification error");
         return OC_STACK_ERROR;
     }
 }
 
 OCStackResult GenerateObserverId (OCObservationId *observationId)
 {
-    ResourceObserver *resObs = NULL;
+    bool found = false;
 
-    OC_LOG(INFO, TAG, "Entering GenerateObserverId");
+    OIC_LOG(INFO, TAG, "Entering GenerateObserverId");
     VERIFY_NON_NULL (observationId);
 
     do
     {
-        *observationId = OCGetRandomByte();
+        do
+        {
+            *observationId = OCGetRandomByte();
+        } while (0 == *observationId); //Make sure *observationId is not 0
         // Check if observation Id already exists
-        resObs = GetObserverUsingId (*observationId);
-    } while (NULL != resObs);
+        found = IsObserverAvailable (*observationId);
+    } while (found);
 
-    OC_LOG_V(INFO, TAG, "GeneratedObservation ID is %u", *observationId);
+    OIC_LOG_V(INFO, TAG, "GeneratedObservation ID is %u", *observationId);
 
     return OC_STACK_OK;
 exit:
@@ -375,14 +492,13 @@ OCStackResult AddObserver (const char         *resUri,
     {
         return OC_STACK_RESOURCE_ERROR;
     }
-    ResourceObserver *obsNode = NULL;
 
-    if(!resUri || !token || !*token)
+    if (!resUri || !token)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
-    obsNode = (ResourceObserver *) OICCalloc(1, sizeof(ResourceObserver));
+    ResourceObserver *obsNode = (ResourceObserver *) OICCalloc(1, sizeof(ResourceObserver));
     if (obsNode)
     {
         obsNode->observeId = obsId;
@@ -392,14 +508,14 @@ OCStackResult AddObserver (const char         *resUri,
 
         obsNode->qos = qos;
         obsNode->acceptFormat = acceptFormat;
-        if(query)
+        if (query)
         {
             obsNode->query = OICStrdup(query);
             VERIFY_NON_NULL (obsNode->query);
         }
         // If tokenLength is zero, the return value depends on the
         // particular library implementation (it may or may not be a null pointer).
-        if(tokenLength)
+        if (tokenLength)
         {
             obsNode->token = (CAToken_t)OICMalloc(tokenLength);
             VERIFY_NON_NULL (obsNode->token);
@@ -410,7 +526,20 @@ OCStackResult AddObserver (const char         *resUri,
         obsNode->devAddr = *devAddr;
         obsNode->resource = resHandle;
 
-        LL_APPEND (serverObsList, obsNode);
+#ifdef WITH_PRESENCE
+        if ((strcmp(resUri, OC_RSRVD_PRESENCE_URI) == 0))
+        {
+            obsNode->TTL = 0;
+        }
+        else
+#endif
+        {
+            obsNode->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
+        }
+
+        oc_mutex_lock(g_serverObsListMutex);
+        LL_APPEND (g_serverObsList, obsNode);
+        oc_mutex_unlock(g_serverObsListMutex);
 
         return OC_STACK_OK;
     }
@@ -425,88 +554,228 @@ exit:
     return OC_STACK_NO_MEMORY;
 }
 
+/*
+ * This function checks if the node is past its time to live and
+ * deletes it if timed-out. Calling this function with a  presence callback
+ * with ttl set to 0 will not delete anything as presence nodes have
+ * their own mechanisms for timeouts. A null argument will cause the function to
+ * silently return.
+ */
+static void CheckTimedOutObserver(ResourceObserver* observer)
+{
+    if (!observer || observer->TTL == 0)
+    {
+        return;
+    }
+
+    coap_tick_t now;
+    coap_ticks(&now);
+
+    if (observer->TTL < now)
+    {
+        // Send confirmable notification message to observer.
+        OIC_LOG(INFO, TAG, "Sending High-QoS notification to observer");
+        SendObserveNotification(observer, OC_HIGH_QOS);
+    }
+}
+
 ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
 {
     ResourceObserver *out = NULL;
 
     if (observeId)
     {
-        LL_FOREACH (serverObsList, out)
+        oc_mutex_lock(g_serverObsListMutex);
+        LL_FOREACH (g_serverObsList, out)
+        {
+            if (out->observeId == observeId)
+            {
+                oc_mutex_unlock(g_serverObsListMutex);
+                return CloneObserverNode(out);
+            }
+            CheckTimedOutObserver(out);
+        }
+        oc_mutex_unlock(g_serverObsListMutex);
+    }
+    OIC_LOG(INFO, TAG, "Observer node not found!!");
+    return NULL;
+}
+
+static ResourceObserver* GetObserverUsingIdAsOwner (const OCObservationId observeId)
+{
+    ResourceObserver *out = NULL;
+
+    if (observeId)
+    {
+        LL_FOREACH (g_serverObsList, out)
         {
             if (out->observeId == observeId)
             {
                 return out;
             }
+            CheckTimedOutObserver(out);
         }
     }
-    OC_LOG(INFO, TAG, "Observer node not found!!");
+    OIC_LOG(INFO, TAG, "Observer node not found!!");
     return NULL;
 }
 
-ResourceObserver* GetObserverUsingToken (const CAToken_t token, uint8_t tokenLength)
+bool IsObserverAvailable (const OCObservationId observeId)
 {
     ResourceObserver *out = NULL;
 
-    if(token && *token)
+    if (observeId)
     {
-        OC_LOG(INFO, TAG, "Looking for token");
-        OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
-        OC_LOG(INFO, TAG, "\tFound token:");
+        oc_mutex_lock(g_serverObsListMutex);
+        LL_FOREACH (g_serverObsList, out)
+        {
+            if (out->observeId == observeId)
+            {
+                oc_mutex_unlock(g_serverObsListMutex);
+                return true;
+            }
+        }
+        oc_mutex_unlock(g_serverObsListMutex);
+    }
 
-        LL_FOREACH (serverObsList, out)
+    return false;
+}
+
+ResourceObserver* GetObserverUsingToken (const CAToken_t token, uint8_t tokenLength)
+{
+    if (token)
+    {
+        OIC_LOG(INFO, TAG, "Looking for token");
+        OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
+
+        ResourceObserver *out = NULL;
+        oc_mutex_lock(g_serverObsListMutex);
+        LL_FOREACH (g_serverObsList, out)
+        {
+            /* de-annotate below line if want to see all token in cbList */
+            //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
+            if ((memcmp(out->token, token, tokenLength) == 0))
+            {
+                OIC_LOG(INFO, TAG, "Found in observer list");
+                ResourceObserver *observer = CloneObserverNode(out);
+                oc_mutex_unlock(g_serverObsListMutex);
+                return observer;
+            }
+            CheckTimedOutObserver(out);
+        }
+        oc_mutex_unlock(g_serverObsListMutex);
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Passed in NULL token");
+    }
+
+    OIC_LOG(INFO, TAG, "Observer node not found!!");
+    return NULL;
+}
+
+static ResourceObserver* GetObserverUsingTokenAsOwner (const CAToken_t token, uint8_t tokenLength)
+{
+    if (token)
+    {
+        OIC_LOG(INFO, TAG, "Looking for token");
+        OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
+
+        ResourceObserver *out = NULL;
+        LL_FOREACH (g_serverObsList, out)
         {
-            OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
-            if((memcmp(out->token, token, tokenLength) == 0))
+            /* de-annotate below line if want to see all token in cbList */
+            //OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
+            if ((memcmp(out->token, token, tokenLength) == 0))
             {
+                OIC_LOG(INFO, TAG, "Found in observer list");
                 return out;
             }
+            CheckTimedOutObserver(out);
         }
     }
     else
     {
-        OC_LOG(ERROR, TAG, "Passed in NULL token");
+        OIC_LOG(ERROR, TAG, "Passed in NULL token");
     }
 
-    OC_LOG(INFO, TAG, "Observer node not found!!");
+    OIC_LOG(INFO, TAG, "Observer node not found!!");
     return NULL;
 }
 
 OCStackResult DeleteObserverUsingToken (CAToken_t token, uint8_t tokenLength)
 {
-    if(!token || !*token)
+    if (!token)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
-    ResourceObserver *obsNode = NULL;
-
-    obsNode = GetObserverUsingToken (token, tokenLength);
+    oc_mutex_lock(g_serverObsListMutex);
+    ResourceObserver *obsNode = GetObserverUsingTokenAsOwner (token, tokenLength);
     if (obsNode)
     {
-        OC_LOG_V(INFO, TAG, "deleting observer id  %u with token", obsNode->observeId);
-        OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)obsNode->token, tokenLength);
-        LL_DELETE (serverObsList, obsNode);
-        OICFree(obsNode->resUri);
-        OICFree(obsNode->query);
-        OICFree(obsNode->token);
-        OICFree(obsNode);
+        OIC_LOG_V(INFO, TAG, "deleting observer id  %u with token", obsNode->observeId);
+        OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)obsNode->token, tokenLength);
+
+        LL_DELETE (g_serverObsList, obsNode);
+        FreeObserver(obsNode);
     }
+    oc_mutex_unlock(g_serverObsListMutex);
+
     // it is ok if we did not find the observer...
     return OC_STACK_OK;
 }
 
-void DeleteObserverList()
+OCStackResult DeleteObserverUsingDevAddr(const OCDevAddr *devAddr)
 {
+    if (!devAddr)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    oc_mutex_lock(g_serverObsListMutex);
+    ResourceObserver* obsDupList = CloneObserverList(g_serverObsList);
+    oc_mutex_unlock(g_serverObsListMutex);
+
     ResourceObserver *out = NULL;
     ResourceObserver *tmp = NULL;
-    LL_FOREACH_SAFE (serverObsList, out, tmp)
+    LL_FOREACH_SAFE(obsDupList, out, tmp)
     {
-        if(out)
+        if (out)
         {
-            DeleteObserverUsingToken ((out->token), out->tokenLength);
+            if ((strcmp(out->devAddr.addr, devAddr->addr) == 0)
+                    && out->devAddr.port == devAddr->port)
+            {
+                OIC_LOG_V(INFO, TAG, "deleting observer id  %u with %s:%u",
+                          out->observeId, out->devAddr.addr, out->devAddr.port);
+                OCStackFeedBack(out->token, out->tokenLength, OC_OBSERVER_NOT_INTERESTED);
+            }
         }
     }
-    serverObsList = NULL;
+
+    FreeObserverList(obsDupList);
+    return OC_STACK_OK;
+}
+
+void DeleteObserverList()
+{
+    oc_mutex_lock(g_serverObsListMutex);
+
+    ResourceObserver* head = g_serverObsList;
+    ResourceObserver* del = NULL;
+    while (NULL != head)
+    {
+        del = head;
+        head = head->next;
+
+        OIC_LOG_V(INFO, TAG, "deleting observer id  %u with token", del->observeId);
+        OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)del->token, del->tokenLength);
+
+        FreeObserver(del);
+    }
+
+    g_serverObsList = NULL;
+    oc_mutex_unlock(g_serverObsListMutex);
 }
 
 /*
@@ -523,14 +792,14 @@ CreateObserveHeaderOption (CAHeaderOption_t **caHdrOpt,
                            uint8_t numOptions,
                            uint8_t observeFlag)
 {
-    if(!caHdrOpt)
+    if (!caHdrOpt)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
     if (numOptions > 0 && !ocHdrOpt)
     {
-        OC_LOG (INFO, TAG, "options are NULL though number is non zero");
+        OIC_LOG (INFO, TAG, "options are NULL though number is non zero");
         return OC_STACK_INVALID_PARAM;
     }
 
@@ -567,20 +836,20 @@ GetObserveHeaderOption (uint32_t * observationOption,
                         CAHeaderOption_t *options,
                         uint8_t * numOptions)
 {
-    if(!observationOption)
+    if (!observationOption)
     {
         return OC_STACK_INVALID_PARAM;
     }
 
-    if(!options || !numOptions)
+    if (!options || !numOptions)
     {
-        OC_LOG (INFO, TAG, "No options present");
+        OIC_LOG (INFO, TAG, "No options present");
         return OC_STACK_OK;
     }
 
     for(uint8_t i = 0; i < *numOptions; i++)
     {
-        if(options[i].protocolID == CA_COAP_ID &&
+        if (options[i].protocolID == CA_COAP_ID &&
                 options[i].optionID == COAP_OPTION_OBSERVE)
         {
             *observationOption = options[i].optionData[0];
@@ -595,3 +864,41 @@ GetObserveHeaderOption (uint32_t * observationOption,
     return OC_STACK_OK;
 }
 
+OCStackResult InitializeObseverList()
+{
+    OIC_LOG(DEBUG, TAG, "InitializeObseverList IN");
+
+    if (NULL == g_serverObsListMutex)
+    {
+        g_serverObsListMutex = oc_mutex_new();
+    }
+
+    OIC_LOG(DEBUG, TAG, "InitializeObseverList OUT");
+    return OC_STACK_OK;
+}
+
+void TerminateObserverList()
+{
+    OIC_LOG(DEBUG, TAG, "TerminateObserverList IN");
+
+    DeleteObserverList();
+
+    if (NULL != g_serverObsListMutex)
+    {
+        oc_mutex_free(g_serverObsListMutex);
+        g_serverObsListMutex = NULL;
+    }
+
+    OIC_LOG(DEBUG, TAG, "TerminateObserverList OUT");
+}
+
+void FreeObserver (ResourceObserver* obsNode)
+{
+    if (NULL != obsNode)
+    {
+        OICFree(obsNode->resUri);
+        OICFree(obsNode->query);
+        OICFree(obsNode->token);
+        OICFree(obsNode);
+    }
+}