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