replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocobserve.c
index 636572a..9cc6557 100644 (file)
@@ -31,9 +31,9 @@
 #include "ocserverrequest.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"
@@ -96,6 +96,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)
@@ -129,45 +190,7 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
             {
 #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
@@ -199,7 +222,7 @@ OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr,
                         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);
@@ -285,7 +308,7 @@ OCStackResult SendListObserverNotification (OCResource * resource,
                         }
                         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)
@@ -302,6 +325,9 @@ OCStackResult SendListObserverNotification (OCResource * resource,
                         {
                             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
                     {
@@ -344,7 +370,10 @@ OCStackResult GenerateObserverId (OCObservationId *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);
@@ -376,7 +405,7 @@ OCStackResult AddObserver (const char         *resUri,
         return OC_STACK_RESOURCE_ERROR;
     }
 
-    if (!resUri || !token || !*token)
+    if (!resUri || !token)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -409,6 +438,17 @@ OCStackResult AddObserver (const char         *resUri,
         obsNode->devAddr = *devAddr;
         obsNode->resource = resHandle;
 
+#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);
+        }
+
         LL_APPEND (g_serverObsList, obsNode);
 
         return OC_STACK_OK;
@@ -424,6 +464,31 @@ 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;
@@ -436,6 +501,7 @@ ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
             {
                 return out;
             }
+            CheckTimedOutObserver(out);
         }
     }
     OIC_LOG(INFO, TAG, "Observer node not found!!");
@@ -444,21 +510,22 @@ ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
 
 ResourceObserver* GetObserverUsingToken (const CAToken_t token, uint8_t tokenLength)
 {
-    ResourceObserver *out = NULL;
-
-    if (token && *token)
+    if (token)
     {
         OIC_LOG(INFO, TAG, "Looking for token");
         OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)token, tokenLength);
-        OIC_LOG(INFO, TAG, "\tFound token:");
 
+        ResourceObserver *out = NULL;
         LL_FOREACH (g_serverObsList, out)
         {
-            OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)out->token, tokenLength);
+            /* 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
@@ -472,7 +539,7 @@ ResourceObserver* GetObserverUsingToken (const CAToken_t token, uint8_t tokenLen
 
 OCStackResult DeleteObserverUsingToken (CAToken_t token, uint8_t tokenLength)
 {
-    if (!token || !*token)
+    if (!token)
     {
         return OC_STACK_INVALID_PARAM;
     }
@@ -492,6 +559,32 @@ OCStackResult DeleteObserverUsingToken (CAToken_t token, uint8_t tokenLength)
     return OC_STACK_OK;
 }
 
+OCStackResult DeleteObserverUsingDevAddr(const OCDevAddr *devAddr)
+{
+    if (!devAddr)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    ResourceObserver *out = NULL;
+    ResourceObserver *tmp = NULL;
+    LL_FOREACH_SAFE(g_serverObsList, out, tmp)
+    {
+        if (out)
+        {
+            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);
+            }
+        }
+    }
+
+    return OC_STACK_OK;
+}
+
 void DeleteObserverList()
 {
     ResourceObserver *out = NULL;