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