081f10c626d16ce2dc857e1bcff050bd861d5328
[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 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2001 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2001 base specification,
26 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
27 #define _POSIX_C_SOURCE 200112L
28
29 #include "occollection.h"
30 #include "ocpayload.h"
31 #include "ocendpoint.h"
32 #include "ocstack.h"
33 #include "ocstackinternal.h"
34 #include "oicgroup.h"
35 #include "oic_string.h"
36 #include "experimental/payload_logging.h"
37 #include "cainterface.h"
38 #define TAG "OIC_RI_COLLECTION"
39
40 static bool AddRTSBaselinePayload(OCRepPayload **linkArray, int size, OCRepPayload **colPayload)
41 {
42     size_t arraySize = 0;
43     for (int j = 0; j < size; j++)
44     {
45         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {0};
46         char **rt = NULL;
47         OCRepPayloadGetStringArray(linkArray[j], OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
48         arraySize += rtDim[0];
49         for (size_t l = 0; l < rtDim[0]; l++)
50         {
51             OICFree(rt[l]);
52         }
53         OICFree(rt);
54     }
55
56     for (OCStringLL *rsrcType = (*colPayload)->types; rsrcType; rsrcType = rsrcType->next, arraySize++);
57
58     OIC_LOG_V(DEBUG, TAG, "Number of RTS elements : %zd", arraySize);
59     size_t dim[MAX_REP_ARRAY_DEPTH] = {arraySize, 0, 0};
60     char **rts = (char **)OICMalloc(sizeof(char *) * arraySize);
61     if (!rts)
62     {
63         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
64         return OC_STACK_NO_MEMORY;
65     }
66     int k = 0;
67     for (int j = 0; j < size; j++)
68     {
69         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {0};
70         char **rt = NULL;
71         OCRepPayloadGetStringArray(linkArray[j], OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
72         for (size_t l = 0; l < rtDim[0]; l++)
73         {
74             rts[k++] = OICStrdup(rt[l]);
75             OICFree(rt[l]);
76         }
77         OICFree(rt);
78     }
79     for (OCStringLL *rsrcType = (*colPayload)->types; rsrcType; rsrcType = rsrcType->next, size++)
80     {
81         rts[k++] = OICStrdup(rsrcType->value);
82     }
83
84     bool b = OCRepPayloadSetStringArrayAsOwner(*colPayload, OC_RSRVD_RTS, rts, dim);
85
86     if (!b)
87     {
88         for (size_t j = 0; j < arraySize; j++)
89         {
90             OICFree(rts[j]);
91         }
92         OICFree(rts);
93     }
94
95     return b;
96 }
97
98 static OCStackResult SendResponse(const OCRepPayload *payload,
99                         const OCEntityHandlerRequest *ehRequest, OCEntityHandlerResult ehResult)
100 {
101     OCEntityHandlerResponse response = {0};
102     response.ehResult = ehResult;
103     response.payload = (OCPayload*)payload;
104     response.persistentBufferFlag = 0;
105     response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
106     return OCDoResponse(&response);
107 }
108
109 uint8_t GetNumOfResourcesInCollection(const OCResource *collResource)
110 {
111     uint8_t size = 0;
112     for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
113         tempChildResource; tempChildResource = tempChildResource->next)
114     {
115         size++;
116     }
117     return size;
118 }
119
120 static OCStackResult HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest, char *ifQueryParam)
121 {
122     if (!ehRequest)
123     {
124         return OC_STACK_INVALID_PARAM;
125     }
126
127     OCResource *collResource = (OCResource *)ehRequest->resource;
128     if (!collResource)
129     {
130         return OC_STACK_INVALID_PARAM;
131     }
132
133     uint8_t size = GetNumOfResourcesInCollection(collResource);
134     OCRepPayload *colPayload = NULL;
135     OCEntityHandlerResult ehResult = OC_EH_ERROR;
136     OCStackResult ret = OC_STACK_ERROR;
137     size_t dim[MAX_REP_ARRAY_DEPTH] = {size, 0, 0};
138     OCRepPayload **linkArr = NULL;
139
140     if (!(linkArr = OCLinksPayloadArrayCreate(collResource->uri, ehRequest, false, NULL)))
141     {
142         OIC_LOG_V(ERROR, TAG, "Failed getting LinksPayloadArray");
143         ret = OC_STACK_ERROR;
144         goto exit;
145     }
146
147     if (size < 1)
148     {
149         ret = OC_STACK_NO_RESOURCE;
150         goto exit;
151     }
152
153     OCPayloadFormat contentFormat = OC_FORMAT_UNDEFINED;
154     OCGetRequestPayloadVersion(ehRequest, &contentFormat, NULL);
155     // from the OCF1.0 linklist specification, ll has array of links
156     if ((0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL)) && (contentFormat == OC_FORMAT_VND_OCF_CBOR))
157     {
158         for (int n = 0; n < (int)size - 1; n++)
159         {
160             linkArr[n]->next = linkArr[n + 1];
161         }
162         colPayload = linkArr[0];
163         OICFree(linkArr);
164         ret = OC_STACK_OK;
165         goto exit;
166     }
167     else if ((contentFormat == OC_FORMAT_VND_OCF_CBOR || contentFormat == OC_FORMAT_CBOR))
168     {
169         colPayload = OCRepPayloadCreate();
170         VERIFY_PARAM_NON_NULL(TAG, linkArr, "Failed creating LinksPayloadArray");
171         if (0 == strcmp(OC_RSRVD_INTERFACE_DEFAULT, ifQueryParam))
172         {
173             //TODO : Add resource type filtering once collections
174             // start supporting queries.
175             OCRepPayloadAddResourceType(colPayload, OC_RSRVD_RESOURCE_TYPE_COLLECTION);
176             for (OCResourceType *types = collResource->rsrcType; types; types = types->next)
177             {
178                 if (0 != strcmp(OC_RSRVD_RESOURCE_TYPE_COLLECTION, types->resourcetypename))
179                 {
180                     OCRepPayloadAddResourceType(colPayload, types->resourcetypename);
181                 }
182             }
183             for (OCResourceInterface *itf = collResource->rsrcInterface; itf; itf = itf->next)
184             {
185                 OCRepPayloadAddInterface(colPayload, itf->name);
186             }
187             AddRTSBaselinePayload(linkArr, size, &colPayload);
188         }
189         OCRepPayloadSetPropObjectArrayAsOwner(colPayload, OC_RSRVD_LINKS, linkArr, dim);
190         ret = OC_STACK_OK;
191     }
192 exit:
193     if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL))
194     {
195         OCRepPayloadSetPayloadRepType(colPayload, PAYLOAD_REP_ARRAY);
196     }
197     else
198     {
199         OCRepPayloadSetPayloadRepType(colPayload, PAYLOAD_REP_OBJECT_ARRAY);
200     }
201
202     if (ret == OC_STACK_OK)
203     {
204         ehResult = OC_EH_OK;
205     }
206     else
207     {
208         ehResult = (ret == OC_STACK_NO_RESOURCE) ? OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR;
209     }
210     ret = SendResponse(colPayload, ehRequest, ehResult);
211     OIC_LOG_V(INFO, TAG, "Send Response result from HandleLinkedListInterface = %d", (int)ret);
212     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)colPayload);
213     OCRepPayloadDestroy(colPayload);
214
215     return ret;
216 }
217
218 static OCStackResult HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
219 {
220     if (!ehRequest)
221     {
222         return OC_STACK_INVALID_PARAM;
223     }
224
225     OCStackResult stackRet = OC_STACK_OK;
226     char *storeQuery = NULL;
227     OCResource *collResource = (OCResource *)ehRequest->resource;
228
229     if (stackRet == OC_STACK_OK)
230     {
231
232         if (collResource->rsrcChildResourcesHead)
233         {
234             storeQuery = ehRequest->query;
235             ehRequest->query = NULL;
236             OIC_LOG_V(DEBUG, TAG, "Query : %s", ehRequest->query);
237         }
238
239         uint8_t numRes = 0;
240         for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
241             tempChildResource; tempChildResource = tempChildResource->next, numRes++)
242         {
243             OCResource* tempRsrcResource = tempChildResource->rsrcResource;
244             if (tempRsrcResource)
245             {
246                 // Note that all entity handlers called through a collection
247                 // will get the same pointer to ehRequest, the only difference
248                 // is ehRequest->resource
249                 ehRequest->resource = (OCResourceHandle) tempRsrcResource;
250                 OCEntityHandlerResult ehResult = tempRsrcResource->entityHandler(OC_REQUEST_FLAG,
251                                            ehRequest, tempRsrcResource->entityHandlerCallbackParam);
252
253                 // The default collection handler is returning as OK
254                 if (stackRet != OC_STACK_SLOW_RESOURCE)
255                 {
256                     stackRet = OC_STACK_OK;
257                 }
258                 // if a single resource is slow, then entire response will be treated
259                 // as slow response
260                 if (ehResult == OC_EH_SLOW)
261                 {
262                     OIC_LOG(INFO, TAG, "This is a slow resource");
263                     ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
264                     stackRet = EntityHandlerCodeToOCStackCode(ehResult);
265                 }
266             }
267             else
268             {
269                 break;
270             }
271         }
272         ehRequest->resource = (OCResourceHandle) collResource;
273     }
274     ehRequest->query = storeQuery;
275     return stackRet;
276 }
277
278 OCStackResult DefaultCollectionEntityHandler(OCEntityHandlerFlag flag, OCEntityHandlerRequest *ehRequest)
279 {
280     if (!ehRequest || !ehRequest->query)
281     {
282         return OC_STACK_INVALID_PARAM;
283     }
284     // Delete is not supported for any interface query method.
285     if (ehRequest->method == OC_REST_DELETE || flag != OC_REQUEST_FLAG)
286     {
287         return OC_STACK_ERROR;
288     }
289     OIC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
290
291     char *ifQueryParam = NULL;
292     char *rtQueryParam = NULL;
293     OCStackResult result = ExtractFiltersFromQuery(ehRequest->query, &ifQueryParam, &rtQueryParam);
294     if (result != OC_STACK_OK)
295     {
296         result = OC_STACK_NO_RESOURCE;
297         goto exit;
298     }
299     if (!ifQueryParam)
300     {
301         ifQueryParam = OICStrdup(OC_RSRVD_INTERFACE_LL);
302     }
303
304     VERIFY_PARAM_NON_NULL(TAG, ifQueryParam, "Invalid Parameter ifQueryParam");
305
306     if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL) || 0 == strcmp (ifQueryParam, OC_RSRVD_INTERFACE_DEFAULT))
307     {
308         if (ehRequest->method == OC_REST_PUT || ehRequest->method == OC_REST_POST)
309         {
310             result =  OC_STACK_ERROR;
311         }
312         else
313         {
314             result = HandleLinkedListInterface(ehRequest, ifQueryParam);
315         }
316     }
317     else if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_BATCH))
318     {
319         OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;
320         if (request)
321         {
322             request->numResponses = GetNumOfResourcesInCollection((OCResource *)ehRequest->resource);
323             request->ehResponseHandler = HandleAggregateResponse;
324             result = HandleBatchInterface(ehRequest);
325         }
326     }
327     else if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_GROUP))
328     {
329         OIC_LOG_V(INFO, TAG, "IF_COLLECTION %d with request ::\n", ehRequest->method);
330         OIC_LOG_PAYLOAD(INFO, ehRequest->payload);
331         result = BuildCollectionGroupActionCBORResponse(ehRequest->method, (OCResource *) ehRequest->resource, ehRequest);
332     }
333 exit:
334     if (result != OC_STACK_OK)
335     {
336         result = SendResponse(NULL, ehRequest, OC_EH_BAD_REQ);
337     }
338     OICFree(ifQueryParam);
339     OICFree(rtQueryParam);
340     return result;
341 }
342
343 static bool addPolicyPayload(OCResourceHandle* resourceHandle, OCDevAddr* devAddr,
344                              bool isOCFContentFormat, OCRepPayload** outPolicy)
345 {
346     if (resourceHandle == NULL || devAddr == NULL || outPolicy == NULL)
347     {
348         return false;
349     }
350
351     OCResourceProperty p = OCGetResourceProperties(resourceHandle);
352     OCRepPayload* policy = OCRepPayloadCreate();
353     if (policy)
354     {
355         OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE)));
356         if (!isOCFContentFormat)
357         {
358             OCRepPayloadSetPropBool(policy, OC_RSRVD_SECURE, p & OC_SECURE);
359
360             if (p & OC_SECURE)
361             {
362                 uint16_t securePort = 0;
363                 if (devAddr)
364                 {
365                     if (devAddr->adapter == OC_ADAPTER_IP)
366                     {
367                         if (devAddr->flags & OC_IP_USE_V6)
368                         {
369                             securePort = caglobals.ip.u6s.port;
370                         }
371                         else if (devAddr->flags & OC_IP_USE_V4)
372                         {
373                             securePort = caglobals.ip.u4s.port;
374                         }
375                     }
376                 }
377                 OCRepPayloadSetPropInt(policy, OC_RSRVD_HOSTING_PORT, securePort);
378
379 #if defined(TCP_ADAPTER) && defined(__WITH_TLS__)
380                 // tls
381                 if (devAddr)
382                 {
383                     uint16_t tlsPort = 0;
384                     GetTCPPortInfo(devAddr, &tlsPort, true);
385                     OCRepPayloadSetPropInt(policy, OC_RSRVD_TLS_PORT, tlsPort);
386                 }
387 #endif
388             }
389 #ifdef TCP_ADAPTER
390 #ifdef  __WITH_TLS__
391             if (!(p & OC_SECURE))
392             {
393 #endif
394                 // tcp
395                 if (devAddr)
396                 {
397                     uint16_t tcpPort = 0;
398                     GetTCPPortInfo(devAddr, &tcpPort, false);
399                     OCRepPayloadSetPropInt(policy, OC_RSRVD_TCP_PORT, tcpPort);
400                 }
401 #ifdef  __WITH_TLS__
402             }
403 #endif
404 #endif
405         }
406     }
407     else
408     {
409         return false;
410     }
411
412     *outPolicy = policy;
413     return true;
414 }
415
416 static bool translateEndpointsPayload(OCEndpointPayload* epPayloadOrg,
417                                       size_t size, OCRepPayload*** outArrayPayload)
418 {
419     bool result = false;
420     OCRepPayload** arrayPayload = (OCRepPayload**)OICMalloc(sizeof(OCRepPayload*) * (size));
421     VERIFY_PARAM_NON_NULL(TAG, arrayPayload, "Failed creating arrayPayload");
422     VERIFY_PARAM_NON_NULL(TAG, epPayloadOrg, "Invalid Parameter epPayload");
423     VERIFY_PARAM_NON_NULL(TAG, outArrayPayload, "Invalid Parameter outArrayPayload");
424     OCEndpointPayload* epPayload = epPayloadOrg;
425
426     for (size_t i = 0; (i < size) && (epPayload != NULL) ; i++)
427     {
428         arrayPayload[i] = OCRepPayloadCreate();
429         if (!arrayPayload[i])
430         {
431             for (size_t j = 0; j < i; j++)
432             {
433                 OCRepPayloadDestroy(arrayPayload[j]);
434             }
435             result = false;
436             goto exit;
437         }
438         char* createdEPStr = OCCreateEndpointString(epPayload);
439         OIC_LOG_V(DEBUG, TAG, " OCCreateEndpointString() = %s", createdEPStr);
440         OCRepPayloadSetPropString(arrayPayload[i], OC_RSRVD_ENDPOINT, createdEPStr);
441         OICFree(createdEPStr);
442
443         // in case of pri as 1, skip set property
444         if (epPayload->pri != 1 )
445             OCRepPayloadSetPropInt(arrayPayload[i], OC_RSRVD_PRIORITY, epPayload->pri);
446
447         epPayload = epPayload->next;
448         result = true;
449     }
450     *outArrayPayload = arrayPayload;
451 exit:
452     OCEndpointPayloadDestroy(epPayloadOrg);
453     if (result == false)
454     {
455         OICFree(arrayPayload);
456     }
457     return result;
458 }
459
460 OCRepPayload** BuildCollectionLinksPayloadArray(const char* resourceUri,
461     bool isOCFContentFormat, OCDevAddr* devAddr, bool insertSelfLink, size_t* createdArraySize)
462 {
463     bool result = false;
464     OCRepPayload** arrayPayload = NULL;
465     size_t childCount = 0;
466
467     const OCResourceHandle colResourceHandle = OCGetResourceHandleAtUri(resourceUri);
468     VERIFY_PARAM_NON_NULL(TAG, colResourceHandle, "Failed geting colResourceHandle");
469
470     const OCChildResource* childResource = ((OCResource*)colResourceHandle)->rsrcChildResourcesHead;
471     VERIFY_PARAM_NON_NULL(TAG, childResource, "Failed geting childResource");
472
473     //children resources count calculation
474     const OCChildResource* childCountResource = childResource;
475     do {
476         childCount++;
477         childCountResource = childCountResource->next;
478     } while (childCountResource);
479
480     if (insertSelfLink)
481     {
482         childCount++;
483     }
484
485     arrayPayload = (OCRepPayload**)OICMalloc(sizeof(OCRepPayload*) * (childCount));
486     VERIFY_PARAM_NON_NULL(TAG, arrayPayload, "Failed creating arrayPayload");
487
488     OCResource* iterResource = childResource->rsrcResource;
489     for (size_t i = 0; i < childCount; i++)
490     {
491         arrayPayload[i] = OCRepPayloadCreate();
492         if (!arrayPayload[i])
493         {
494             for (size_t j = 0; j < i; j++)
495             {
496                 OCRepPayloadDestroy(arrayPayload[j]);
497             }
498             result = false;
499             goto exit;
500         }
501
502         OCRepPayloadSetUri(arrayPayload[i], iterResource->uri);
503
504         for (OCResourceType* resType = iterResource->rsrcType; resType;
505             resType = resType->next)
506         {
507             OCRepPayloadAddResourceType(arrayPayload[i], resType->resourcetypename);
508         }
509
510         for (OCResourceInterface* resInterface = iterResource->rsrcInterface; resInterface;
511                                   resInterface = resInterface->next)
512         {
513             OCRepPayloadAddInterface(arrayPayload[i], resInterface->name);
514         }
515
516         OCRepPayload* outPolicy = NULL;
517         //Policy Map will have tls and tcp properties for legacy support,
518         // in case contents format is cbor instead of vnd.ocf/cbor
519         if (!addPolicyPayload((OCResourceHandle*)iterResource, devAddr, isOCFContentFormat,
520                                &outPolicy) ||
521             !OCRepPayloadSetPropObjectAsOwner(arrayPayload[i], OC_RSRVD_POLICY, outPolicy))
522         {
523             OCRepPayloadDestroy(outPolicy);
524             for (size_t j = 0; j <= i; j++)
525             {
526                 OCRepPayloadDestroy(arrayPayload[j]);
527             }
528             result = false;
529             goto exit;
530         }
531
532         //EP is added in case contents format is vnd.ocf/cbor
533         if (isOCFContentFormat)
534         {
535             CAEndpoint_t *info = NULL;
536             size_t networkSize = 0;
537             size_t epSize = 0;
538             CAGetNetworkInformation(&info, &networkSize);
539             OIC_LOG_V(DEBUG, TAG, "Network Information size = %d", (int) networkSize);
540
541             OCEndpointPayload *listHead = NULL;
542             CreateEndpointPayloadList(iterResource,
543                 devAddr, info, networkSize, &listHead, &epSize, NULL);
544             OICFree(info);
545             OIC_LOG_V(DEBUG, TAG, "Result of CreateEndpointPayloadList() = %s",
546                                   listHead ? "true":"false");
547
548             OCRepPayload** epArrayPayload = NULL;
549             size_t epsDim[MAX_REP_ARRAY_DEPTH] = { epSize, 0, 0 };
550
551             if (!translateEndpointsPayload(listHead, epSize, &epArrayPayload) ||
552                 !OCRepPayloadSetPropObjectArrayAsOwner(arrayPayload[i],
553                             OC_RSRVD_ENDPOINTS, epArrayPayload, epsDim))
554             {
555                 if (epArrayPayload)
556                 {
557                     for (size_t j = 0; j < epSize; j++)
558                     {
559                         OCRepPayloadDestroy(epArrayPayload[j]);
560                     }
561                     OICFree(epArrayPayload);
562                 }
563
564                 for (size_t j = 0; j <= i; j++)
565                 {
566                     OCRepPayloadDestroy(arrayPayload[j]);
567                 }
568                 result = false;
569                 goto exit;
570             }
571         }
572
573         if (iterResource != colResourceHandle)
574         {
575             childResource = childResource->next;
576             if (childResource)
577             {
578                 iterResource = childResource->rsrcResource;
579             }
580             else if (insertSelfLink)
581             {
582                 iterResource = colResourceHandle;
583             }
584         }
585         else // handling selfLink case
586         {
587             OIC_LOG(INFO, TAG, "adding rel for self link");
588             const char* relArray[2] = { "self", "item" };
589             size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 2, 0, 0 };
590             if (!OCRepPayloadSetStringArray(arrayPayload[i], OC_RSRVD_REL, relArray, dimensions))
591             {
592                 OIC_LOG(ERROR, TAG, "Failed setting rel property");
593                 result = false;
594                 goto exit;
595             }
596         }
597         result = true;
598     }
599
600 exit:
601     if (!result && (arrayPayload != NULL))
602     {
603         OICFree(arrayPayload);
604         arrayPayload = NULL;
605     }
606
607     if (arrayPayload != NULL && createdArraySize != NULL)
608         *createdArraySize = childCount;
609     else if (createdArraySize != NULL)
610         *createdArraySize = 0;
611
612     return arrayPayload;
613 }