Merge "Remove the dead code" into connectivity-abstraction
[platform/upstream/iotivity.git] / resource / csdk / stack / src / occollection.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #define _POSIX_C_SOURCE 200112L
22 #include <string.h>
23 #include "ocstack.h"
24 #include "ocstackinternal.h"
25 #include "ocresourcehandler.h"
26 #include "logger.h"
27 #include "debug.h"
28 #include "cJSON.h"
29 /// Module Name
30 #include <stdio.h>
31
32 #define WITH_GROUPACTION 1
33
34 #include "oicgroup.h"
35
36 #define TAG PCF("occollection")
37
38 #define NUM_PARAM_IN_QUERY  2
39
40 static OCStackResult CheckRTParamSupport(const OCResource* resource, const char* rtPtr)
41 {
42     OCResourceType* rTPointer = resource->rsrcType;
43     while (rTPointer)
44     {
45         if( strcmp (rTPointer->resourcetypename, rtPtr) == 0)
46             return OC_STACK_OK;
47
48         rTPointer = rTPointer->next;
49     }
50     return OC_STACK_ERROR;
51 }
52
53 static OCStackResult CheckIFParamSupport(const OCResource* resource, const char* ifPtr)
54 {
55     OCResourceInterface* iFPointer = resource->rsrcInterface;
56     while (iFPointer)
57     {
58         if( strcmp (iFPointer->name, ifPtr) == 0)
59              return OC_STACK_OK;
60
61         iFPointer = iFPointer->next;
62     }
63     return OC_STACK_ERROR;
64 }
65
66 static OCStackResult
67 ValidateQuery (const unsigned char *query, OCResourceHandle resource,
68                              OCStackIfTypes *ifParam, char **rtParam)
69 {
70     uint8_t numFields = 0, numParam;
71
72     //TODO: Query and URL validation is being done for virtual resource case
73     // using ValidateUrlQuery function. We should be able to merge it with this
74     // function.
75     OC_LOG(INFO, TAG, PCF("Entering ValidateQuery"));
76
77     if (!query)
78         return OC_STACK_ERROR;
79
80     if (!(*query))
81     {
82         // Query string is empty
83         OC_LOG_V(INFO, TAG, PCF("Empty query string, use default IF and RT"));
84         *ifParam = STACK_IF_DEFAULT;
85         *rtParam = (char *) OCGetResourceTypeName (resource, 0);
86         return OC_STACK_OK;
87     }
88
89     // Break the query string to validate it and determine IF and RT parameters
90     // Validate there are atmost 2 parameters in string and that one is 'if' and other 'rt'
91     char *endStr, *ifPtr = NULL, *rtPtr = NULL;
92     char *token = strtok_r ((char *)query, "&", &endStr);
93
94     // External loop breaks query string into fields using the & separator
95     while (token != NULL)
96     {
97         numFields++;
98         char *endToken;
99         char *innerToken = strtok_r (token, "=", &endToken);
100         numParam = 0;
101
102         // Internal loop parses the field to extract values (parameters) assigned to each field
103         while (innerToken != NULL)
104         {
105             numParam++;
106             if (strcmp (innerToken, OC_RSRVD_INTERFACE) == 0)
107             {
108                 // Determine the value of IF parameter
109                 innerToken = strtok_r (NULL, "=", &endToken);
110                 ifPtr = innerToken;
111             } else if (strcmp (innerToken, OC_RSRVD_RESOURCE_TYPE) == 0) {
112                 // Determine the value of RT parameter
113                 innerToken = strtok_r (NULL, "=", &endToken);
114                 rtPtr = innerToken;
115             } else {
116                 innerToken = strtok_r (NULL, "=", &endToken);
117             }
118         }
119         if (numParam != 2)
120         {
121             // Query parameter should be of the form if=<string>. String should not have & or =
122             return OC_STACK_INVALID_QUERY;
123         }
124         token = strtok_r (NULL, "&", &endStr);
125     }
126     if (numFields > NUM_PARAM_IN_QUERY)
127     {
128         // M1 release supports one IF value, one RT value and no other params
129         return OC_STACK_INVALID_QUERY;
130     }
131
132     if (ifPtr)
133     {
134         if(CheckIFParamSupport((OCResource *)resource, ifPtr) != OC_STACK_OK)
135         {
136             return OC_STACK_INVALID_QUERY;
137         }
138         if (strcmp (ifPtr, OC_RSRVD_INTERFACE_DEFAULT) == 0)
139         {
140             *ifParam = STACK_IF_DEFAULT;
141         }
142         else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_LL) == 0)
143         {
144             *ifParam = STACK_IF_LL;
145         }
146         else if (strcmp (ifPtr, OC_RSRVD_INTERFACE_BATCH) == 0)
147         {
148             *ifParam = STACK_IF_BATCH;
149         }
150         else if(strcmp (ifPtr, OC_RSRVD_INTERFACE_GROUP) == 0)
151         {
152             *ifParam = STACK_IF_GROUP;
153         }
154         else
155         {
156             return OC_STACK_ERROR;
157         }
158     }
159     else
160     {
161         // IF not specified in query, use default IF
162         *ifParam = STACK_IF_DEFAULT;
163     }
164
165     if (rtPtr)
166     {
167         if (CheckRTParamSupport((OCResource *)resource, rtPtr) == OC_STACK_OK)
168         {
169             *rtParam = rtPtr;
170         }
171         else
172         {
173             return OC_STACK_INVALID_QUERY;
174         }
175     }
176     else
177     {
178         // RT not specified in query. Use the first resource type for the resource as default.
179         *rtParam = (char *) OCGetResourceTypeName (resource, 0);
180     }
181     OC_LOG_V(INFO, TAG, "Query params: IF = %d, RT = %s", *ifParam, *rtParam);
182
183     return OC_STACK_OK;
184 }
185
186
187 static OCStackResult BuildRootResourceJSON(OCResource *resource,
188         unsigned char * bufferPtr, uint16_t *remaining)
189 {
190     OCStackResult ret = OC_STACK_ERROR;
191     cJSON *resObj;
192     char *jsonStr;
193     uint16_t jsonLen;
194
195     OC_LOG(INFO, TAG, PCF("Entering BuildRootResourceJSON"));
196     resObj = cJSON_CreateObject();
197
198     if (resource)
199     {
200         cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resource->uri));
201     }
202     jsonStr = cJSON_PrintUnformatted (resObj);
203     jsonLen = strlen(jsonStr);
204     if (jsonLen < *remaining)
205     {
206         strcpy((char*) bufferPtr, jsonStr);
207         *remaining -= jsonLen;
208         bufferPtr += jsonLen;
209         ret = OC_STACK_OK;
210     }
211
212     cJSON_Delete (resObj);
213     free (jsonStr);
214
215     return ret;
216 }
217
218
219 static OCStackResult
220 HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest,
221                        uint8_t filterOn, char *filterValue)
222 {
223     OCStackResult ret = OC_STACK_ERROR;
224     unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
225     size_t jsonbufferLength = 0;
226     uint16_t remaining = 0;
227     unsigned char * ptr = NULL;
228     OCResource * collResource = (OCResource *) ehRequest->resource;
229
230     ptr = jsonbuffer;
231     remaining = MAX_RESPONSE_LENGTH;
232
233     ret = BuildRootResourceJSON(collResource, ptr, &remaining);
234     ptr += strlen((char*)ptr);
235
236     if (ret == OC_STACK_OK && remaining >= (sizeof(OC_JSON_SEPARATOR) + 1))
237     {
238         *ptr = OC_JSON_SEPARATOR;
239         ptr++;
240         remaining--;
241     }
242     else
243     {
244         ret = OC_STACK_ERROR;
245     }
246     *(ptr + 1) = '\0';
247
248     if (ret == OC_STACK_OK)
249     {
250         for  (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
251         {
252             OCResource* temp = collResource->rsrcResources[i];
253             if (temp)
254             {
255 #ifdef CA_INT
256                 //TODO : Update needed here to get correct connectivity type
257                 //from ServerRequest data structure
258                 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue,
259                          (char*)ptr, &remaining, CA_WIFI );
260 #else
261                 ret = BuildVirtualResourceResponse(temp, filterOn, filterValue,
262                          (char*)ptr, &remaining);
263 #endif
264                 if (ret != OC_STACK_OK)
265                 {
266                     break;
267                 }
268                 ptr += strlen((char*)ptr);
269                 if (collResource->rsrcResources[i+1] && remaining > sizeof(OC_JSON_SEPARATOR))
270                 {
271                     *ptr = OC_JSON_SEPARATOR;
272                     ptr++;
273                     remaining--;
274                 }
275                 *(ptr + 1) = '\0';
276             }
277             else
278             {
279                 break;
280             }
281         }
282     }
283
284     jsonbufferLength = strlen((const char *)jsonbuffer);
285     if(ret == OC_STACK_OK && jsonbufferLength)
286     {
287         OCEntityHandlerResponse response = {0};
288         response.ehResult = OC_EH_OK;
289         response.payload = jsonbuffer;
290         response.payloadSize = jsonbufferLength + 1;
291         response.persistentBufferFlag = 0;
292         response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
293         response.resourceHandle = (OCResourceHandle) collResource;
294         ret = OCDoResponse(&response);
295     }
296     return ret;
297 }
298
299 static OCStackResult
300 HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
301 {
302     OCStackResult stackRet = OC_STACK_ERROR;
303     OCEntityHandlerResult ehResult = OC_EH_ERROR;
304     unsigned char jsonbuffer[MAX_RESPONSE_LENGTH] = {0};
305     size_t jsonbufferLength = 0;
306     uint16_t remaining = 0;
307     unsigned char * ptr = NULL;
308     OCResource * collResource = (OCResource *) ehRequest->resource;
309
310     ptr = jsonbuffer;
311     remaining = MAX_RESPONSE_LENGTH;
312
313     stackRet = BuildRootResourceJSON(collResource, ptr, &remaining);
314     ptr += strlen((char*)ptr);
315     *(ptr + 1) = '\0';
316
317     jsonbufferLength = strlen((const char *)jsonbuffer);
318     if(jsonbufferLength)
319     {
320         OCEntityHandlerResponse response = {0};
321         response.ehResult = OC_EH_OK;
322         response.payload = jsonbuffer;
323         response.payloadSize = jsonbufferLength + 1;
324         response.persistentBufferFlag = 0;
325         response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
326         response.resourceHandle = (OCResourceHandle) collResource;
327         stackRet = OCDoResponse(&response);
328     }
329
330     if (stackRet == OC_STACK_OK)
331     {
332         for  (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
333         {
334             OCResource* temp = collResource->rsrcResources[i];
335             if (temp)
336             {
337                 // Note that all entity handlers called through a collection
338                 // will get the same pointer to ehRequest, the only difference
339                 // is ehRequest->resource
340                 ehRequest->resource = (OCResourceHandle) temp;
341
342                 ehResult = temp->entityHandler(OC_REQUEST_FLAG, ehRequest);
343
344                 // The default collection handler is returning as OK
345                 if(stackRet != OC_STACK_SLOW_RESOURCE)
346                 {
347                     stackRet = OC_STACK_OK;
348                 }
349                 // if a single resource is slow, then entire response will be treated
350                 // as slow response
351                 if(ehResult == OC_EH_SLOW)
352                 {
353                     OC_LOG(INFO, TAG, PCF("This is a slow resource"));
354                     ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
355                     stackRet = EntityHandlerCodeToOCStackCode(ehResult);
356                 }
357             }
358             else
359             {
360                 break;
361             }
362         }
363         ehRequest->resource = (OCResourceHandle) collResource;
364     }
365     return stackRet;
366 }
367
368 uint8_t GetNumOfResourcesInCollection (OCResource *resource)
369 {
370     uint8_t num = 0;
371     for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
372     {
373         if (resource->rsrcResources[i])
374         {
375             num++;
376         }
377     }
378     return num;
379 }
380
381
382 OCStackResult DefaultCollectionEntityHandler (OCEntityHandlerFlag flag,
383                                               OCEntityHandlerRequest *ehRequest)
384 {
385     OCStackResult result = OC_STACK_ERROR;
386     OCStackIfTypes ifQueryParam = STACK_IF_INVALID;
387     char *rtQueryParam = NULL;
388
389     OC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
390
391     if (flag != OC_REQUEST_FLAG)
392         return OC_STACK_ERROR;
393
394     result = ValidateQuery ((const unsigned char *)ehRequest->query,
395                             ehRequest->resource, &ifQueryParam, &rtQueryParam);
396
397     if (result != OC_STACK_OK)
398         return result;
399
400   
401     if(!((ehRequest->method == OC_REST_GET) || 
402         (ehRequest->method == OC_REST_PUT) ||
403         (ehRequest->method == OC_REST_POST)))
404         return OC_STACK_ERROR;
405
406     if (ehRequest->method == OC_REST_GET)
407     {
408         switch (ifQueryParam)
409         {
410             case STACK_IF_DEFAULT:
411                 // Get attributes of collection resource and properties of contined resource
412                 // M1 release does not support attributes for collection resource, so the GET
413                 // operation is same as the GET on LL interface.
414                 OC_LOG(INFO, TAG, PCF("STACK_IF_DEFAULT"));
415                 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
416
417             case STACK_IF_LL:
418                 OC_LOG(INFO, TAG, PCF("STACK_IF_LL"));
419                 return HandleLinkedListInterface(ehRequest, STACK_RES_DISCOVERY_NOFILTER, NULL);
420
421             case STACK_IF_BATCH:
422                 OC_LOG(INFO, TAG, PCF("STACK_IF_BATCH"));
423                 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
424                 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
425                         GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
426                 return HandleBatchInterface(ehRequest);
427             case STACK_IF_GROUP:
428                 return BuildCollectionGroupActionJSONResponse(OC_REST_GET/*flag*/,
429                         (OCResource *) ehRequest->resource, ehRequest);
430             default:
431                 return OC_STACK_ERROR;
432         }
433     } else if (ehRequest->method == OC_REST_PUT) {
434         switch (ifQueryParam)
435         {
436             case STACK_IF_DEFAULT:
437                 // M1 release does not support PUT on default interface
438                 return OC_STACK_ERROR;
439
440             case STACK_IF_LL:
441                 // LL interface only supports GET
442                 return OC_STACK_ERROR;
443
444             case STACK_IF_BATCH:
445                 ((OCServerRequest *)ehRequest->requestHandle)->ehResponseHandler = HandleAggregateResponse;
446                 ((OCServerRequest *)ehRequest->requestHandle)->numResponses =
447                         GetNumOfResourcesInCollection((OCResource *)ehRequest->resource) + 1;
448                 return HandleBatchInterface(ehRequest);
449
450             case STACK_IF_GROUP:
451             {
452                 OC_LOG_V(INFO, TAG, "IF_COLLECTION PUT with request ::\n%s\n ",
453                         ehRequest->reqJSONPayload);
454                 return BuildCollectionGroupActionJSONResponse(OC_REST_PUT/*flag*/,
455                         (OCResource *) ehRequest->resource, ehRequest);
456             }
457             default:
458                 return OC_STACK_ERROR;
459         }
460     }
461     else if (ehRequest->method == OC_REST_POST)
462     {
463
464         switch (ifQueryParam)
465         {
466             case STACK_IF_GROUP:
467             {
468                 OC_LOG_V(INFO, TAG, "IF_COLLECTION POST with request :: \n%s\n ",
469                         ehRequest->reqJSONPayload);
470                 return BuildCollectionGroupActionJSONResponse(OC_REST_POST/*flag*/,
471                         (OCResource *) ehRequest->resource, ehRequest);
472             }
473             default:
474                 return OC_STACK_ERROR;
475         }
476     }
477     return result;
478 }
479