Removed execute permissions from non-executable files.
[platform/upstream/iotivity.git] / resource / csdk / stack / src / occollection.c
index 2e4b276..23980ba 100644 (file)
 #include <string.h>
 #include "ocstack.h"
 #include "ocstackinternal.h"
-#include "ocresource.h"
+#include "ocresourcehandler.h"
 #include "logger.h"
 #include "debug.h"
 #include "cJSON.h"
 /// Module Name
+#include <stdio.h>
+
+#define WITH_GROUPACTION 1
+
+#ifdef WITH_GROUPACTION
+#include "oicgroup.h"
+#endif
+
 #define TAG PCF("occollection")
 
 #define NUM_PARAM_IN_QUERY  2
@@ -92,10 +100,10 @@ ValidateQuery (const unsigned char *query, OCResourceHandle resource,
         char *endToken;
         char *innerToken = strtok_r (token, "=", &endToken);
         numParam = 0;
+
         // Internal loop parses the field to extract values (parameters) assigned to each field
         while (innerToken != NULL)
         {
-
             numParam++;
             if (strcmp (innerToken, OC_RSRVD_INTERFACE) == 0)
             {
@@ -123,45 +131,63 @@ ValidateQuery (const unsigned char *query, OCResourceHandle resource,
         return OC_STACK_INVALID_QUERY;
     }
 
-    if (!ifPtr)
-    {
-        // IF not specified in query, use default IF
-        *ifParam = STACK_IF_DEFAULT;
-    }
-    else
+    if (ifPtr)
     {
         if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
+        {
             return OC_STACK_INVALID_QUERY;
-
+        }
         if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
+        {
             *ifParam = STACK_IF_DEFAULT;
+        }
         else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
+        {
             *ifParam = STACK_IF_LL;
+        }
         else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
+        {
             *ifParam = STACK_IF_BATCH;
+        }
+        else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
+        {
+            *ifParam = STACK_IF_GROUP;
+        }
         else
         {
             return OC_STACK_ERROR;
         }
     }
-
-    if (!rtPtr)
+    else
     {
-        // RT not specified in query. Use the first resource type for the resource as default.
-        *rtParam = (char *) OCGetResourceTypeName (resource, 0);
+        // IF not specified in query, use default IF
+        *ifParam = STACK_IF_DEFAULT;
     }
-    else
+
+    if (rtPtr)
     {
         if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
+        {
             *rtParam = rtPtr;
+        }
         else
+        {
             return OC_STACK_INVALID_QUERY;
+        }
+    }
+    else
+    {
+        // RT not specified in query. Use the first resource type for the resource as default.
+        *rtParam = (char *) OCGetResourceTypeName (resource, 0);
     }
     OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
 
     return OC_STACK_OK;
 }
-static OCStackResult BuildRootResourceJSON(OCResource *resource, OCEntityHandlerRequest *ehRequest)
+
+
+static OCStackResult BuildRootResourceJSON(OCResource *resource,
+        unsigned char * bufferPtr, uint16_t *remaining)
 {
     OCStackResult ret = OC_STACK_ERROR;
     cJSON *resObj;
@@ -170,25 +196,18 @@ static OCStackResult BuildRootResourceJSON(OCResource *resource, OCEntityHandler
 
     OC_LOG(INFO, TAG, PCF("Entering BuildRootResourceJSON"));
     resObj = cJSON_CreateObject();
+
     if (resource)
     {
         cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resource->uri));
     }
     jsonStr = cJSON_PrintUnformatted (resObj);
     jsonLen = strlen(jsonStr);
-    if (jsonLen < ehRequest->resJSONPayloadLen)
+    if (jsonLen < *remaining)
     {
-        strcpy((char*)ehRequest->resJSONPayload, jsonStr);
-        ehRequest->resJSONPayloadLen -= jsonLen;
-        ehRequest->resJSONPayload += jsonLen;
-        ret = OC_STACK_OK;
-    }
-
-    if (ehRequest->resJSONPayloadLen >= (sizeof(OC_JSON_SEPARATOR) + 1))
-    {
-        *ehRequest->resJSONPayload = OC_JSON_SEPARATOR;
-        ehRequest->resJSONPayload++;
-        ehRequest->resJSONPayloadLen--;
+        strcpy((char*) bufferPtr, jsonStr);
+        *remaining -= jsonLen;
+        bufferPtr += jsonLen;
         ret = OC_STACK_OK;
     }
 
@@ -200,112 +219,168 @@ static OCStackResult BuildRootResourceJSON(OCResource *resource, OCEntityHandler
 
 
 static OCStackResult
-BuildCollectionJSONResponse(OCResource *resource, OCEntityHandlerRequest *ehRequest,
+HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
                        uint8_t filterOn, char *filterValue)
 {
     OCStackResult ret = OC_STACK_ERROR;
-    ret = BuildRootResourceJSON(resource, ehRequest);
+    unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
+    size_t jsonbufferLength = 0;
+    uint16_t remaining = 0;
+    unsigned char * ptr = NULL;
+    OCResource * collResource = (OCResource *) ehRequest->resource;
+
+    ptr = jsonbuffer;
+    remaining = MAX_RESPONSE_LENGTH;
+
+    ret = BuildRootResourceJSON(collResource, ptr, &remaining);
+    ptr += strlen((char*)ptr);
+
+    if (ret == OC_STACK_OK && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1))
+    {
+        *ptr = OC_JSON_SEPARATOR;
+        ptr++;
+        remaining--;
+    }
+    else
+    {
+        ret = OC_STACK_ERROR;
+    }
+    *(ptr + 1) = '\0';
 
-    unsigned char* buffer = ehRequest->resJSONPayload;
-    uint16_t remaining = ehRequest->resJSONPayloadLen;
     if (ret == OC_STACK_OK)
     {
         for  (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
         {
-            OCResource* temp = resource->rsrcResources[i];
+            OCResource* temp = collResource->rsrcResources[i];
             if (temp)
             {
-                ret = BuildVirtualResourceResponse(temp, filterOn, filterValue, (char*)buffer, &remaining);
+                ret = BuildVirtualResourceResponse(temp, filterOn, filterValue, (char*)ptr, &remaining);
                 if (ret != OC_STACK_OK)
                 {
                     break;
                 }
-
-                buffer += strlen((char*)buffer);
-                if (resource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
+                ptr += strlen((char*)ptr);
+                if (collResource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
                 {
-                    *buffer = OC_JSON_SEPARATOR;
-                    buffer++;
+                    *ptr = OC_JSON_SEPARATOR;
+                    ptr++;
                     remaining--;
                 }
+                *(ptr + 1) = '\0';
             }
             else
             {
                 break;
             }
         }
-        ehRequest->resJSONPayload = buffer;
-        ehRequest->resJSONPayloadLen = remaining;
     }
 
+    jsonbufferLength = strlen((const char *)jsonbuffer);
+    if(ret == OC_STACK_OK && jsonbufferLength)
+    {
+        OCEntityHandlerResponse response = {0};
+        response.ehResult = OC_EH_OK;
+        response.payload = jsonbuffer;
+        response.payloadSize = jsonbufferLength + 1;
+        response.persistentBufferFlag = 0;
+        response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
+        response.resourceHandle = (OCResourceHandle) collResource;
+        ret = OCDoResponse(&response);
+    }
     return ret;
 }
 
-
 static OCStackResult
-BuildCollectionBatchJSONResponse(OCEntityHandlerFlag flag,
-                OCResource *resource, OCEntityHandlerRequest *ehRequest)
+HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
 {
     OCStackResult stackRet = OC_STACK_ERROR;
-    OCEntityHandlerResult ehRet = OC_EH_ERROR;
+    OCEntityHandlerResult ehResult = OC_EH_ERROR;
+    unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
+    size_t jsonbufferLength = 0;
+    uint16_t remaining = 0;
+    unsigned char * ptr = NULL;
+    OCResource * collResource = (OCResource *) ehRequest->resource;
+
+    ptr = jsonbuffer;
+    remaining = MAX_RESPONSE_LENGTH;
+
+    stackRet = BuildRootResourceJSON(collResource, ptr, &remaining);
+    ptr += strlen((char*)ptr);
+    *(ptr + 1) = '\0';
+
+    jsonbufferLength = strlen((const char *)jsonbuffer);
+    if(jsonbufferLength)
+    {
+        OCEntityHandlerResponse response = {0};
+        response.ehResult = OC_EH_OK;
+        response.payload = jsonbuffer;
+        response.payloadSize = jsonbufferLength + 1;
+        response.persistentBufferFlag = 0;
+        response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
+        response.resourceHandle = (OCResourceHandle) collResource;
+        stackRet = OCDoResponse(&response);
+    }
 
-    stackRet = BuildRootResourceJSON(resource, ehRequest);
     if (stackRet == OC_STACK_OK)
     {
-        OCResourceHandle origResourceHandle = ehRequest->resource;
-
         for  (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
         {
-            OCResource* temp = resource->rsrcResources[i];
+            OCResource* temp = collResource->rsrcResources[i];
             if (temp)
             {
+                // Note that all entity handlers called through a collection
+                // will get the same pointer to ehRequest, the only difference
+                // is ehRequest->resource
                 ehRequest->resource = (OCResourceHandle) temp;
 
-                ehRet = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
-                stackRet = EntityHandlerCodeToOCStackCode(ehRet);
+                ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
 
-                if(ehRet == OC_EH_OK)
+                // The default collection handler is returning as OK
+                if(stackRet != OC_STACK_SLOW_RESOURCE)
                 {
-                    unsigned char* buffer = ehRequest->resJSONPayload;
-                    ehRequest->resJSONPayloadLen =
-                            ehRequest->resJSONPayloadLen - strlen((char*)buffer);
-
-                    buffer += strlen((char*)buffer);
-                    ehRequest->resJSONPayload = buffer;
-                    if ( resource->rsrcResources[i+1] &&
-                         ehRequest->resJSONPayloadLen > sizeof(OC_JSON_SEPARATOR) )
-                    {
-                        * buffer = OC_JSON_SEPARATOR;
-                        buffer++;
-                        ehRequest->resJSONPayload = buffer;
-                        ehRequest->resJSONPayloadLen = ehRequest->resJSONPayloadLen - 1;
-                    }
+                    stackRet = OC_STACK_OK;
                 }
-                else
+                // if a single resource is slow, then entire response will be treated
+                // as slow response
+                if(ehResult == OC_EH_SLOW)
                 {
-                    break;
+                    OC_LOG(INFO, TAG, PCF("This is a slow resource"));
+                    ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
+                    stackRet = EntityHandlerCodeToOCStackCode(ehResult);
                 }
             }
             else
             {
-               break;
+                break;
             }
         }
-
-        ehRequest->resource = origResourceHandle;
+        ehRequest->resource = (OCResourceHandle) collResource;
     }
     return stackRet;
 }
 
+uint8_t GetNumOfResourcesInCollection (OCResource *resource)
+{
+    uint8_t num = 0;
+    for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
+    {
+        if (resource->rsrcResources[i])
+        {
+            num++;
+        }
+    }
+    return num;
+}
+
 
 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
                                               OCEntityHandlerRequest *ehRequest)
 {
-    OCStackResult result;
-    OCStackIfTypes ifQueryParam;
-    char *rtQueryParam;
+    OCStackResult result = OC_STACK_ERROR;
+    OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
+    char *rtQueryParam = NULL;
 
-    OC_LOG(INFO, TAG, PCF("DefaultCollectionEntityHandler"));
+    OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
 
     if (flag != OC_REQUEST_FLAG)
         return OC_STACK_ERROR;
@@ -316,8 +391,10 @@ OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
     if (result != OC_STACK_OK)
         return result;
 
-    if ((ehRequest->method != OC_REST_GET) &&
-        (ehRequest->method != OC_REST_PUT))
+  
+    if(!((ehRequest->method == OC_REST_GET) || 
+        (ehRequest->method == OC_REST_PUT) ||
+        (ehRequest->method == OC_REST_POST)))
         return OC_STACK_ERROR;
 
     if (ehRequest->method == OC_REST_GET)
@@ -328,20 +405,24 @@ OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
                 // Get attributes of collection resource and properties of contined resource
                 // M1 release does not support attributes for collection resource, so the GET
                 // operation is same as the GET on LL interface.
-
                 OC_LOG(INFO, TAG, PCF("STACK_IF_DEFAULT"));
-                return BuildCollectionJSONResponse( (OCResource *)ehRequest->resource,
-                             ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
+                return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
 
             case STACK_IF_LL:
                 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
-                return BuildCollectionJSONResponse( (OCResource *)ehRequest->resource,
-                             ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
+                return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
 
             case STACK_IF_BATCH:
                 OC_LOG(INFO, TAG, PCF("STACK_IF_BATCH"));
-                return BuildCollectionBatchJSONResponse(flag, (OCResource *)ehRequest->resource, ehRequest);
-
+                ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
+                ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
+                        GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
+                return HandleBatchInterface(ehRequest);
+#ifdef WITH_GROUPACTION
+            case STACK_IF_GROUP:
+                return BuildCollectionGroupActionJSONResponse(OC_REST_GET/*flag*/, (OCResource *)ehRequest->resource,
+                                ehRequest);
+#endif  // WITH_GROUPACTION
             default:
                 return OC_STACK_ERROR;
         }
@@ -357,12 +438,40 @@ OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
                 return OC_STACK_ERROR;
 
             case STACK_IF_BATCH:
-                return BuildCollectionBatchJSONResponse(flag, (OCResource *)ehRequest->resource, ehRequest);
+                ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
+                ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
+                        GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
+                return HandleBatchInterface(ehRequest);
+
 
+#ifdef WITH_GROUPACTION
+            case STACK_IF_GROUP:
+            {
+                OC_LOG_V(INFO, TAG, "IF_COLLECTION PUT with request ::\n%s\n ", ehRequest->reqJSONPayload);
+                printf("PUT ::\n%s\n", ehRequest->reqJSONPayload);
+                return BuildCollectionGroupActionJSONResponse(OC_REST_PUT/*flag*/, (OCResource *)ehRequest->resource, ehRequest);
+            }
+#endif // WITH_GROUPACTION
+            default:
+                return OC_STACK_ERROR;
+        }
+    }
+#ifdef WITH_GROUPACTION
+    else if(ehRequest->method == OC_REST_POST) {
+
+        switch(ifQueryParam)
+        {
+            case STACK_IF_GROUP:
+            {
+                OC_LOG_V(INFO, TAG, "IF_COLLECTION POST with request :: \n%s\n ", ehRequest->reqJSONPayload);
+                printf("POST ::\n%s\n", ehRequest->reqJSONPayload);
+                return BuildCollectionGroupActionJSONResponse(OC_REST_POST/*flag*/, (OCResource *)ehRequest->resource, ehRequest);
+            }
             default:
                 return OC_STACK_ERROR;
         }
     }
+#endif // WITH_GROUPACTION
     return result;
 }