[CONPRO-1398] Adjust server request handling
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocstack.c
index f588187..fa790d1 100644 (file)
@@ -61,6 +61,7 @@
 #include "ocpayload.h"
 #include "ocpayloadcbor.h"
 #include "cautilinterface.h"
+#include "camessagehandler.h"
 #include "oicgroup.h"
 
 #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
@@ -151,13 +152,14 @@ static const char COAP_TCP_SCHEME[] = "coap+tcp:";
 static const char COAPS_TCP_SCHEME[] = "coaps+tcp:";
 static const char CORESPEC[] = "core";
 
-CAAdapterStateChangedCB g_adapterHandler = NULL;
-CAConnectionStateChangedCB g_connectionHandler = NULL;
-
 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 static OCOtmEventHandler_t g_otmEventHandler = {NULL, NULL};
 #endif
 
+#ifdef WITH_PROCESS_EVENT
+static oc_event g_ocProcessEvent = NULL;
+#endif // WITH_PROCESS_EVENT
+
 //-----------------------------------------------------------------------------
 // Macros
 //-----------------------------------------------------------------------------
@@ -272,11 +274,11 @@ static void deleteResourceType(OCResourceType *resourceType);
 static void deleteResourceInterface(OCResourceInterface *resourceInterface);
 
 /**
- * Delete all child resources.
+ * Unbind all child resources.
  *
- * @param resourceChild Specified binded resource is deleted from parent.
+ * @param resourceChild Specified binded resource head is deleted from parent.
  */
-static void deleteResourceChild(OCChildResource *resourceChild);
+static void unbindChildResources(OCChildResource *resourceChild);
 
 /**
  * Delete all of the dynamically allocated elements that were created for the resource.
@@ -722,6 +724,9 @@ OCStackResult CAResponseToOCStackResult(CAResponseResult_t caCode)
         case CA_FORBIDDEN_REQ:
             ret = OC_STACK_FORBIDDEN_REQ;
             break;
+        case CA_TOO_MANY_REQUESTS:
+            ret = OC_STACK_TOO_MANY_REQUESTS;
+            break;
         case CA_INTERNAL_SERVER_ERROR:
             ret = OC_STACK_INTERNAL_SERVER_ERROR;
             break;
@@ -807,6 +812,9 @@ CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method)
         case OC_STACK_FORBIDDEN_REQ:
             ret = CA_FORBIDDEN_REQ;
             break;
+        case OC_STACK_TOO_MANY_REQUESTS:
+            ret = CA_TOO_MANY_REQUESTS;
+            break;
         case OC_STACK_INTERNAL_SERVER_ERROR:
             ret = CA_INTERNAL_SERVER_ERROR;
             break;
@@ -1236,6 +1244,7 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint,
                     OIC_LOG(ERROR, TAG,
                                   "Could not allocate memory for cbNode->presence->timeOut");
                     OICFree(cbNode->presence);
+                    cbNode->presence = NULL;
                     result = OC_STACK_NO_MEMORY;
                     goto exit;
                 }
@@ -1578,13 +1587,20 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp
                     return;
                 }
 
-                for (uint8_t i = start; i < responseInfo->info.numOptions; i++)
+                if (response.numRcvdVendorSpecificHeaderOptions > 0)
                 {
-                    if(&(responseInfo->info.options[i]))
+                    response.rcvdVendorSpecificHeaderOptions =
+                        (OCHeaderOption *) OICCalloc(response.numRcvdVendorSpecificHeaderOptions, sizeof(OCHeaderOption));
+                    if (NULL == response.rcvdVendorSpecificHeaderOptions)
                     {
-                        memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]),
-                                &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
+                        OIC_LOG(ERROR, TAG, "Failed to allocate memory for vendor header options");
+                        OCPayloadDestroy(response.payload);
+                        OICFree((void *)response.resourceUri);
+                        return;
                     }
+
+                    memcpy(response.rcvdVendorSpecificHeaderOptions, responseInfo->info.options + start,
+                        response.numRcvdVendorSpecificHeaderOptions*sizeof(OCHeaderOption));
                 }
             }
 
@@ -1678,6 +1694,7 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp
 
             OICFree((void *)response.resourceUri);
             OCPayloadDestroy(response.payload);
+            OICFree(response.rcvdVendorSpecificHeaderOptions);
         }
         return;
     }
@@ -1998,6 +2015,8 @@ OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
         {
             request->requestComplete = 1;
         }
+
+        OIC_LOG_V(WARNING, TAG, "Server request ID = [%u]", request->requestId);
     }
     else
     {
@@ -2195,10 +2214,20 @@ void OCHandleRequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
         OICFree(serverRequest.requestToken);
         return;
     }
+
     serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
     if (serverRequest.numRcvdVendorSpecificHeaderOptions && requestInfo->info.options)
     {
-        memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
+        serverRequest.rcvdVendorSpecificHeaderOptions = (OCHeaderOption*) OICCalloc(tempNum, sizeof(OCHeaderOption));
+        if (NULL == serverRequest.rcvdVendorSpecificHeaderOptions)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to allocated memory to vnd header options!");
+            OICFree(serverRequest.payload);
+            OICFree(serverRequest.requestToken);
+            return;
+        }
+
+        memcpy (serverRequest.rcvdVendorSpecificHeaderOptions, requestInfo->info.options,
             sizeof(CAHeaderOption_t)*tempNum);
     }
 
@@ -2237,6 +2266,12 @@ void OCHandleRequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
     {
         OIC_LOG_V(ERROR, TAG, "HandleStackRequests failed. error: %d", requestResult);
 
+        // Delete observer node if it is OBSERVE failure from app
+        if (serverRequest.observationOption == OC_OBSERVE_REGISTER)
+        {
+            DeleteObserverUsingToken(requestInfo->info.token, requestInfo->info.tokenLength);
+        }
+
         CAResponseResult_t stackResponse =
             OCToCAStackResult(requestResult, serverRequest.method);
 
@@ -2250,6 +2285,7 @@ void OCHandleRequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
     // The token is copied in there, and is thus still owned by this function.
     OICFree(serverRequest.payload);
     OICFree(serverRequest.requestToken);
+    OICFree(serverRequest.rcvdVendorSpecificHeaderOptions);
     OIC_LOG(INFO, TAG, "Exit OCHandleRequests");
 }
 
@@ -2502,7 +2538,7 @@ OCStackResult OCInit2(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag
     }
 #endif
 
-    InitializeObseverList();
+    InitializeObserverList();
 
 exit:
     if(result != OC_STACK_OK)
@@ -2560,7 +2596,7 @@ OCStackResult OCStop()
 
     TerminateScheduleResourceList();
     // Remove all observers
-    TerminateObserverList();
+    DeleteObserverList();
     // Free memory dynamically allocated for resources
     deleteAllResources();
     // Remove all the client callbacks
@@ -2572,6 +2608,9 @@ OCStackResult OCStop()
     // TODO after BeachHead delivery: consolidate into single SRMDeInit()
     SRMDeInitPolicyEngine();
 
+    // Destroy Observer List Mutex
+    TerminateObserverList();
+
     stackState = OC_STACK_UNINITIALIZED;
     return OC_STACK_OK;
 }
@@ -3098,6 +3137,8 @@ OCStackResult OCDoRequest(OCDoHandle *handle,
         goto exit;
     }
 
+    cbData = NULL;        // Client CB list entry now owns it
+    token = NULL;         // Client CB list entry now owns it
     devAddr = NULL;       // Client CB list entry now owns it
     resourceUri = NULL;   // Client CB list entry now owns it
     resourceType = NULL;  // Client CB list entry now owns it
@@ -3111,6 +3152,9 @@ OCStackResult OCDoRequest(OCDoHandle *handle,
         {
             *handle = resHandle;
         }
+#ifdef WITH_PROCESS_EVENT
+        OCSendProcessEventSignal();
+#endif // WITH_PROCESS_EVENT
 
         goto exit;
     }
@@ -3132,6 +3176,10 @@ exit:
     if (result != OC_STACK_OK)
     {
         OIC_LOG(ERROR, TAG, "OCDoResource error");
+        if (NULL != cbData && NULL != cbData->cd)
+        {
+            cbData->cd(cbData->context);
+        }
         FindAndDeleteClientCB(clientCB);
         CADestroyToken(token);
         if (handle)
@@ -3195,8 +3243,10 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption
 
             CopyDevAddrToEndpoint(clientCB->devAddr, &endpoint);
 
-            if ((endpoint.adapter & CA_ADAPTER_IP) && qos != OC_HIGH_QOS)
+            if (((endpoint.adapter & CA_ADAPTER_IP) && qos != OC_HIGH_QOS) ||
+                    ((endpoint.adapter & CA_ADAPTER_TCP) && OC_LOW_QOS_WITH_TCP == qos))
             {
+                OIC_LOG_V(INFO, TAG, "the %s observe callback is removed", clientCB->requestUri);
                 FindAndDeleteClientCB(clientCB);
                 break;
             }
@@ -3289,7 +3339,11 @@ OCStackResult OCRegisterPersistentStorageHandler(OCPersistentStorage* persistent
 
 #ifdef WITH_PRESENCE
 
-OCStackResult OCProcessPresence()
+#ifdef WITH_PROCESS_EVENT
+OCStackResult OCProcessPresence(uint32_t *nextEventTime)
+#else   // WITH_PROCESS_EVENT
+OCStackResult OCProcessPresence(void)
+#endif  // !WITH_PROCESS_EVENT
 {
     OCStackResult result = OC_STACK_OK;
 
@@ -3297,10 +3351,11 @@ OCStackResult OCProcessPresence()
     // to most purposes.  Uncomment as needed.
     //OIC_LOG(INFO, TAG, "Entering RequestPresence");
     ClientCB* cbNode = NULL;
+    ClientCB* tempcbNode = NULL;
     OCClientResponse clientResponse;
     OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
 
-    LL_FOREACH(cbList, cbNode)
+    LL_FOREACH_SAFE(cbList, cbNode, tempcbNode)
     {
         if (OC_REST_PRESENCE != cbNode->method || !cbNode->presence)
         {
@@ -3346,10 +3401,18 @@ OCStackResult OCProcessPresence()
             {
                 FindAndDeleteClientCB(cbNode);
             }
+            continue;
         }
 
-        if (now < cbNode->presence->timeOut[cbNode->presence->TTLlevel])
+        uint32_t timeout = cbNode->presence->timeOut[cbNode->presence->TTLlevel];
+        if (now < timeout)
         {
+#ifdef WITH_PROCESS_EVENT
+            if (nextEventTime && (timeout - now) < *nextEventTime)
+            {
+                *nextEventTime = timeout - now;
+            }
+#endif // WITH_PROCESS_EVENT
             continue;
         }
 
@@ -3387,6 +3450,56 @@ exit:
 }
 #endif // WITH_PRESENCE
 
+#ifdef WITH_PROCESS_EVENT
+OCStackResult OCProcess(void)
+{
+    uint32_t nextEventTime;
+    return OCProcessEvent(&nextEventTime);
+}
+
+OCStackResult OCProcessEvent(uint32_t *nextEventTime)
+{
+    if (stackState == OC_STACK_UNINITIALIZED)
+    {
+        OIC_LOG(ERROR, TAG, "OCProcess has failed. ocstack is not initialized");
+        return OC_STACK_ERROR;
+    }
+
+    *nextEventTime = UINT32_MAX;
+
+#ifdef WITH_PRESENCE
+    OCProcessPresence(nextEventTime);
+    OIC_LOG_V(INFO, TAG, "OCProcessPresence next event time : %u", *nextEventTime);
+#endif
+    CAHandleRequestResponse();
+
+// TODO
+#ifdef ROUTING_GATEWAY
+    RMProcess(nextEventTime);
+#endif
+
+#ifdef TCP_ADAPTER
+    OCProcessKeepAlive(nextEventTime);
+    OIC_LOG_V(INFO, TAG, "OCProcessKeepAlive next event time : %u", *nextEventTime);
+#endif
+    return OC_STACK_OK;
+}
+
+void OCRegisterProcessEvent(oc_event event)
+{
+    g_ocProcessEvent = event;
+    CARegisterProcessEvent(event);
+}
+
+void OCSendProcessEventSignal(void)
+{
+    if (g_ocProcessEvent)
+    {
+        oc_event_signal(g_ocProcessEvent);
+    }
+}
+#else // WITH_PROCESS_EVENT
+
 OCStackResult OCProcess()
 {
     if (stackState == OC_STACK_UNINITIALIZED)
@@ -3408,6 +3521,7 @@ OCStackResult OCProcess()
 #endif
     return OC_STACK_OK;
 }
+#endif // !WITH_PROCESS_EVENT
 
 #ifdef WITH_PRESENCE
 OCStackResult OCStartPresence(const uint32_t ttl)
@@ -3966,6 +4080,37 @@ OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
     return result;
 }
 
+OCStackResult OCResetResourceTypes(OCResourceHandle handle,
+                                   const char *newResourceType)
+{
+    OCStackResult result = OC_STACK_ERROR;
+    OCResource *resource = NULL;
+
+    resource = findResource((OCResource *) handle);
+    if (!resource)
+    {
+        OIC_LOG(ERROR, TAG, "Resource not found");
+        return OC_STACK_ERROR;
+    }
+
+    // Clear all bound resource types
+    deleteResourceType(resource->rsrcType);
+    resource->rsrcType = NULL;
+
+    // Bind new resource type to resource
+    result = BindResourceTypeToResource(resource, newResourceType);
+
+#ifdef WITH_PRESENCE
+    if(presenceResource.handle)
+    {
+        ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
+        SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
+    }
+#endif
+
+    return result;
+}
+
 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
         const char *resourceInterfaceName)
 {
@@ -3993,6 +4138,37 @@ OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
     return result;
 }
 
+OCStackResult OCResetResourceInterfaces(OCResourceHandle handle,
+                                        const char *newResourceInterface)
+{
+    OCStackResult result = OC_STACK_ERROR;
+    OCResource *resource = NULL;
+
+    resource = findResource((OCResource *) handle);
+    if (!resource)
+    {
+        OIC_LOG(ERROR, TAG, "Resource not found");
+        return OC_STACK_ERROR;
+    }
+
+    // Clear all bound interface
+    deleteResourceInterface(resource->rsrcInterface);
+    resource->rsrcInterface = NULL;
+
+    // Bind new interface to resource
+    result = BindResourceInterfaceToResource(resource, newResourceInterface);
+
+#ifdef WITH_PRESENCE
+    if (presenceResource.handle)
+    {
+        ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
+        SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
+    }
+#endif
+
+    return result;
+}
+
 OCStackResult OCGetNumberOfResources(uint8_t *numResources)
 {
     OCResource *pointer = headResource;
@@ -4606,6 +4782,9 @@ OCStackResult deleteResource(OCResource *resource)
                 SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_DELETE);
             }
 #endif
+            // Delete resource's all observers
+            DeleteObserverUsingResource(resource);
+
             // Only resource in list.
             if (temp == headResource && temp == tailResource)
             {
@@ -4666,7 +4845,7 @@ void deleteResourceElements(OCResource *resource)
     }
     if (resource->rsrcChildResourcesHead)
     {
-        deleteResourceChild(resource->rsrcChildResourcesHead);
+        unbindChildResources(resource->rsrcChildResourcesHead);
         resource->rsrcChildResourcesHead = NULL;
     }
     if (resource->rsrcAttributes)
@@ -4674,6 +4853,8 @@ void deleteResourceElements(OCResource *resource)
         OCDeleteResourceAttributes(resource->rsrcAttributes);
         resource->rsrcAttributes = NULL;
     }
+
+    resource->entityHandler = NULL;
     resource = NULL;
 }
 
@@ -4708,18 +4889,13 @@ void deleteResourceInterface(OCResourceInterface *resourceInterface)
     }
 }
 
-void deleteResourceChild(OCChildResource *resourceChild)
+void unbindChildResources(OCChildResource *head)
 {
     OCChildResource *next = NULL;
-    for (OCChildResource *pointer = resourceChild; pointer; pointer = next)
+    for (OCChildResource *current = head; current; current = next)
     {
-        next = pointer->next ? pointer->next : NULL;
-        if (pointer->rsrcResource)
-        {
-            deleteResourceElements(pointer->rsrcResource);
-            pointer->rsrcResource = NULL;
-        }
-        OICFree(pointer);
+        next = current->next;
+        OICFree(current);
     }
 }
 
@@ -5313,7 +5489,7 @@ OCStackResult OCGetResourceIns(OCResourceHandle handle, int64_t *ins)
 #endif
 
 OCStackResult OCSetHeaderOption(OCHeaderOption* ocHdrOpt, size_t* numOptions, uint16_t optionID,
-                                void* optionData, size_t optionDataLength)
+                                const void* optionData, size_t optionDataLength)
 {
     if (!ocHdrOpt)
     {
@@ -5395,19 +5571,14 @@ OCStackResult OCGetHeaderOption(OCHeaderOption* ocHdrOpt, size_t numOptions, uin
 void OCDefaultAdapterStateChangedHandler(CATransportAdapter_t adapter, bool enabled)
 {
     OIC_LOG(DEBUG, TAG, "OCDefaultAdapterStateChangedHandler");
-    if (g_adapterHandler)
-    {
-        g_adapterHandler(adapter, enabled);
-    }
+
+    OC_UNUSED(adapter);
+    OC_UNUSED(enabled);
 }
 
 void OCDefaultConnectionStateChangedHandler(const CAEndpoint_t *info, bool isConnected)
 {
     OIC_LOG(DEBUG, TAG, "OCDefaultConnectionStateChangedHandler");
-    if (g_connectionHandler)
-    {
-       g_connectionHandler(info, isConnected);
-    }
 
     /*
      * If the client observes one or more resources over a reliable connection,
@@ -5473,6 +5644,17 @@ OCStackResult OCGetDeviceOwnedState(bool *isOwned)
     return ret;
 }
 
+OCStackResult OCGetDeviceOperationalState(bool* isOp)
+{
+    if(NULL != isOp)
+    {
+        *isOp = GetPstatIsop();
+        return OC_STACK_OK;
+    }
+
+    return OC_STACK_ERROR;
+}
+
 void OCClearCallBackList()
 {
     DeleteClientCBList();