List child resource eps instead of parent.
[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 // 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 "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, const OCEntityHandlerRequest *ehRequest,
99     const OCResource* collResource, 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     response.resourceHandle = (OCResourceHandle) collResource;
107     return OCDoResponse(&response);
108 }
109
110 uint8_t GetNumOfResourcesInCollection(const OCResource *collResource)
111 {
112     uint8_t size = 0;
113     for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
114         tempChildResource; tempChildResource = tempChildResource->next)
115     {
116         size++;
117     }
118     return size;
119 }
120
121 static OCStackResult HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest, char *ifQueryParam)
122 {
123     if (!ehRequest)
124     {
125         return OC_STACK_INVALID_PARAM;
126     }
127
128     OCResource *collResource = (OCResource *)ehRequest->resource;
129     if (!collResource)
130     {
131         return OC_STACK_INVALID_PARAM;
132     }
133
134     uint8_t size = GetNumOfResourcesInCollection(collResource);
135     OCRepPayload *colPayload = NULL;
136     OCEntityHandlerResult ehResult = OC_EH_ERROR;
137     OCStackResult ret = OC_STACK_OK;
138     size_t dim[MAX_REP_ARRAY_DEPTH] = {size, 0, 0};
139     OCRepPayload **linkArr = NULL;
140
141     if (!(linkArr = OCLinksPayloadArrayCreate(collResource->uri, ehRequest, NULL)))
142     {
143         OIC_LOG_V(ERROR, TAG, "Failed getting LinksPayloadArray");
144         ret = OC_STACK_ERROR;
145         goto exit;
146     }
147
148     if (size < 1)
149     {
150         ret = OC_STACK_NO_RESOURCE;
151         goto exit;
152     }
153
154     bool isOCFContentFormat = true;
155     OCRequestIsOCFContentFormat(ehRequest, &isOCFContentFormat);
156     // from the OCF1.0 linklist specification, ll has array of links
157     if ((0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL) && isOCFContentFormat))
158     {
159         for (int n = 0; n < (int)size - 1; n++)
160         {
161             linkArr[n]->next = linkArr[n + 1];
162         }
163         colPayload = linkArr[0];
164         OICFree(linkArr);
165         goto exit;
166     }
167     else
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     }
191 exit:
192     if (ret == OC_STACK_OK)
193     {
194         ehResult = OC_EH_OK;
195     }
196     else
197     {
198         ehResult = (ret == OC_STACK_NO_RESOURCE) ? OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR;
199     }
200     ret = SendResponse(colPayload, ehRequest, collResource, ehResult);
201     OIC_LOG_V(INFO, TAG, "Send Response result from HandleLinkedListInterface = %d", (int)ret);
202     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)colPayload);
203     OCRepPayloadDestroy(colPayload);
204
205     return ret;
206 }
207
208 static OCStackResult HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
209 {
210     if (!ehRequest)
211     {
212         return OC_STACK_INVALID_PARAM;
213     }
214
215     OCStackResult stackRet = OC_STACK_OK;
216     char *storeQuery = NULL;
217     OCResource *collResource = (OCResource *)ehRequest->resource;
218
219     if (stackRet == OC_STACK_OK)
220     {
221
222         if (collResource->rsrcChildResourcesHead)
223         {
224             storeQuery = ehRequest->query;
225             ehRequest->query = NULL;
226             OIC_LOG_V(DEBUG, TAG, "Query : %s", ehRequest->query);
227         }
228
229         uint8_t numRes = 0;
230         for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
231             tempChildResource; tempChildResource = tempChildResource->next, numRes++)
232         {
233             OCResource* tempRsrcResource = tempChildResource->rsrcResource;
234             if (tempRsrcResource)
235             {
236                 // Note that all entity handlers called through a collection
237                 // will get the same pointer to ehRequest, the only difference
238                 // is ehRequest->resource
239                 ehRequest->resource = (OCResourceHandle) tempRsrcResource;
240                 OCEntityHandlerResult ehResult = tempRsrcResource->entityHandler(OC_REQUEST_FLAG,
241                                            ehRequest, tempRsrcResource->entityHandlerCallbackParam);
242
243                 // The default collection handler is returning as OK
244                 if (stackRet != OC_STACK_SLOW_RESOURCE)
245                 {
246                     stackRet = OC_STACK_OK;
247                 }
248                 // if a single resource is slow, then entire response will be treated
249                 // as slow response
250                 if (ehResult == OC_EH_SLOW)
251                 {
252                     OIC_LOG(INFO, TAG, "This is a slow resource");
253                     ((OCServerRequest *)ehRequest->requestHandle)->slowFlag = 1;
254                     stackRet = EntityHandlerCodeToOCStackCode(ehResult);
255                 }
256             }
257             else
258             {
259                 break;
260             }
261         }
262         ehRequest->resource = (OCResourceHandle) collResource;
263     }
264     ehRequest->query = storeQuery;
265     return stackRet;
266 }
267
268 OCStackResult DefaultCollectionEntityHandler(OCEntityHandlerFlag flag, OCEntityHandlerRequest *ehRequest)
269 {
270     if (!ehRequest || !ehRequest->query)
271     {
272         return OC_STACK_INVALID_PARAM;
273     }
274     // Delete is not supported for any interface query method.
275     if (ehRequest->method == OC_REST_DELETE || flag != OC_REQUEST_FLAG)
276     {
277         return OC_STACK_ERROR;
278     }
279     OIC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
280
281     char *ifQueryParam = NULL;
282     char *rtQueryParam = NULL;
283     OCStackResult result = ExtractFiltersFromQuery(ehRequest->query, &ifQueryParam, &rtQueryParam);
284     if (result != OC_STACK_OK)
285     {
286         result = OC_STACK_NO_RESOURCE;
287         goto exit;
288     }
289     if (!ifQueryParam)
290     {
291         ifQueryParam = OICStrdup(OC_RSRVD_INTERFACE_LL);
292     }
293
294     VERIFY_PARAM_NON_NULL(TAG, ifQueryParam, "Invalid Parameter ifQueryParam");
295
296     if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL) || 0 == strcmp (ifQueryParam, OC_RSRVD_INTERFACE_DEFAULT))
297     {
298         if (ehRequest->method == OC_REST_PUT || ehRequest->method == OC_REST_POST)
299         {
300             result =  OC_STACK_ERROR;
301         }
302         else
303         {
304             result = HandleLinkedListInterface(ehRequest, ifQueryParam);
305         }
306     }
307     else if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_BATCH))
308     {
309         OCServerRequest *request = GetServerRequestUsingHandle((OCServerRequest *)ehRequest->requestHandle);
310         if (request)
311         {
312             request->numResponses = GetNumOfResourcesInCollection((OCResource *)ehRequest->resource);
313             request->ehResponseHandler = HandleAggregateResponse;
314             result = HandleBatchInterface(ehRequest);
315         }
316     }
317     else if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_GROUP))
318     {
319         OIC_LOG_V(INFO, TAG, "IF_COLLECTION %d with request ::\n", ehRequest->method);
320         OIC_LOG_PAYLOAD(INFO, ehRequest->payload);
321         result = BuildCollectionGroupActionCBORResponse(ehRequest->method, (OCResource *) ehRequest->resource, ehRequest);
322     }
323 exit:
324     if (result != OC_STACK_OK)
325     {
326         result = SendResponse(NULL, ehRequest, (OCResource *)ehRequest->resource, OC_EH_BAD_REQ);
327     }
328     OICFree(ifQueryParam);
329     OICFree(rtQueryParam);
330     return result;
331 }
332
333 static bool addPolicyPayload(OCResourceHandle* resourceHandle, OCDevAddr* devAddr,
334                              bool isOCFContentFormat, OCRepPayload** outPolicy)
335 {
336     if (resourceHandle == NULL || devAddr == NULL || outPolicy == NULL) return false;
337
338     OCResourceProperty p = OCGetResourceProperties(resourceHandle);
339     OCRepPayload* policy = OCRepPayloadCreate();
340     if (policy)
341     {
342         OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE)));
343         if (!isOCFContentFormat)
344         {
345             OCRepPayloadSetPropBool(policy, OC_RSRVD_SECURE, p & OC_SECURE);
346
347             if (p & OC_SECURE)
348             {
349                 uint16_t securePort = 0;
350                 if (devAddr)
351                 {
352                     if (devAddr->adapter == OC_ADAPTER_IP)
353                     {
354                         if (devAddr->flags & OC_IP_USE_V6)
355                         {
356                             securePort = caglobals.ip.u6s.port;
357                         }
358                         else if (devAddr->flags & OC_IP_USE_V4)
359                         {
360                             securePort = caglobals.ip.u4s.port;
361                         }
362                     }
363                 }
364                 OCRepPayloadSetPropInt(policy, OC_RSRVD_HOSTING_PORT, securePort);
365
366 #if defined(TCP_ADAPTER) && defined(__WITH_TLS__)
367                 // tls
368                 if (devAddr)
369                 {
370                     uint16_t tlsPort = 0;
371                     GetTCPPortInfo(devAddr, &tlsPort, true);
372                     OCRepPayloadSetPropInt(policy, OC_RSRVD_TLS_PORT, tlsPort);
373                 }
374 #endif
375             }
376 #ifdef TCP_ADAPTER
377 #ifdef  __WITH_TLS__
378             if (!(p & OC_SECURE))
379             {
380 #endif
381                 // tcp
382                 if (devAddr)
383                 {
384                     uint16_t tcpPort = 0;
385                     GetTCPPortInfo(devAddr, &tcpPort, false);
386                     OCRepPayloadSetPropInt(policy, OC_RSRVD_TCP_PORT, tcpPort);
387                 }
388 #ifdef  __WITH_TLS__
389             }
390 #endif
391 #endif
392         }
393     }
394     else
395     {
396         return false;
397     }
398
399     *outPolicy = policy;
400     return true;
401 }
402
403 static bool translateEndpointsPayload(OCEndpointPayload* epPayloadOrg,
404                                       size_t size, OCRepPayload*** outArrayPayload)
405 {
406     bool result = false;
407     OCRepPayload** arrayPayload = (OCRepPayload**)OICMalloc(sizeof(OCRepPayload*) * (size));
408     VERIFY_PARAM_NON_NULL(TAG, arrayPayload, "Failed creating arrayPayload");
409     VERIFY_PARAM_NON_NULL(TAG, epPayloadOrg, "Invalid Parameter epPayload");
410     VERIFY_PARAM_NON_NULL(TAG, outArrayPayload, "Invalid Parameter outArrayPayload");
411     OCEndpointPayload* epPayload = epPayloadOrg;
412
413     for (size_t i = 0; (i < size) && (epPayload != NULL) ; i++)
414     {
415         arrayPayload[i] = OCRepPayloadCreate();
416         if (!arrayPayload[i])
417         {
418             for (size_t j = 0; j < i; j++)
419             {
420                 OCRepPayloadDestroy(arrayPayload[j]);
421             }
422             result = false;
423             goto exit;
424         }
425         char* createdEPStr = OCCreateEndpointString(epPayload);
426         OIC_LOG_V(DEBUG, TAG, " OCCreateEndpointString() = %s", createdEPStr);
427         OCRepPayloadSetPropString(arrayPayload[i], OC_RSRVD_ENDPOINT, createdEPStr);
428
429         // in case of pri as 1, skip set property
430         if (epPayload->pri != 1 )
431             OCRepPayloadSetPropInt(arrayPayload[i], OC_RSRVD_PRIORITY, epPayload->pri);
432
433         epPayload = epPayload->next;
434         result = true;
435     }
436     *outArrayPayload = arrayPayload;
437 exit:
438     OCEndpointPayloadDestroy(epPayloadOrg);
439     if (result == false) OICFree(arrayPayload);
440     return result;
441 }
442
443 OCRepPayload** BuildCollectionLinksPayloadArray(const char* resourceUri,
444     bool isOCFContentFormat, OCDevAddr* devAddr, size_t* createdArraySize)
445 {
446     bool result = false;
447     OCRepPayload** arrayPayload = NULL;
448     size_t childCount = 0;
449
450     const OCResourceHandle colResourceHandle = OCGetResourceHandleAtUri(resourceUri);
451     VERIFY_PARAM_NON_NULL(TAG, colResourceHandle, "Failed geting colResourceHandle");
452
453     const OCChildResource* childResource = ((OCResource*)colResourceHandle)->rsrcChildResourcesHead;
454     VERIFY_PARAM_NON_NULL(TAG, childResource, "Failed geting childResource");
455
456     //children resources count calculation
457     const OCChildResource* childCountResource = childResource;
458     do {
459         childCount++;
460         childCountResource = childCountResource->next;
461     } while (childCountResource);
462     arrayPayload = (OCRepPayload**)OICMalloc(sizeof(OCRepPayload*) * (childCount));
463     VERIFY_PARAM_NON_NULL(TAG, arrayPayload, "Failed creating arrayPayload");
464
465     OCResource* iterResource = childResource->rsrcResource;
466     for (size_t i = 0; i < childCount; i++)
467     {
468         arrayPayload[i] = OCRepPayloadCreate();
469         if (!arrayPayload[i])
470         {
471             for (size_t j = 0; j < i; j++)
472             {
473                 OCRepPayloadDestroy(arrayPayload[j]);
474             }
475             result = false;
476             goto exit;
477         }
478
479         OCRepPayloadSetUri(arrayPayload[i], iterResource->uri);
480
481         for (OCResourceType* resType = iterResource->rsrcType; resType;
482             resType = resType->next)
483         {
484             OCRepPayloadAddResourceType(arrayPayload[i], resType->resourcetypename);
485         }
486
487         for (OCResourceInterface* resInterface = iterResource->rsrcInterface; resInterface;
488                                   resInterface = resInterface->next)
489         {
490             OCRepPayloadAddInterface(arrayPayload[i], resInterface->name);
491         }
492
493         OCRepPayload* outPolicy = NULL;
494         //Policy Map will have tls and tcp properties for legacy support,
495         // in case contents format is cbor instead of vnd.ocf/cbor
496         if (!addPolicyPayload((OCResourceHandle*)iterResource, devAddr, isOCFContentFormat,
497                                &outPolicy) ||
498             !OCRepPayloadSetPropObjectAsOwner(arrayPayload[i], OC_RSRVD_POLICY, outPolicy))
499         {
500             OCRepPayloadDestroy(outPolicy);
501             for (size_t j = 0; j <= i; j++)
502             {
503                 OCRepPayloadDestroy(arrayPayload[j]);
504             }
505             result = false;
506             goto exit;
507         }
508
509         //EP is added in case contents format is vnd.ocf/cbor
510         if (isOCFContentFormat)
511         {
512             CAEndpoint_t *info = NULL;
513             size_t networkSize = 0;
514             size_t epSize = 0;
515             CAGetNetworkInformation(&info, &networkSize);
516             OIC_LOG_V(DEBUG, TAG, "Network Information size = %d", (int) networkSize);
517
518             OCEndpointPayload *listHead = NULL;
519             CreateEndpointPayloadList(iterResource,
520                 devAddr, info, networkSize, &listHead, &epSize, NULL);
521             OICFree(info);
522             OIC_LOG_V(DEBUG, TAG, "Result of CreateEndpointPayloadList() = %s",
523                                   listHead ? "true":"false");
524
525             OCRepPayload** epArrayPayload = NULL;
526             size_t epsDim[MAX_REP_ARRAY_DEPTH] = { epSize, 0, 0 };
527
528             if (!translateEndpointsPayload(listHead, epSize, &epArrayPayload) ||
529                 !OCRepPayloadSetPropObjectArrayAsOwner(arrayPayload[i],
530                             OC_RSRVD_ENDPOINTS, epArrayPayload, epsDim))
531             {
532                 if (epArrayPayload)
533                 {
534                     for (size_t j = 0; j < epSize; j++)
535                     {
536                         OCRepPayloadDestroy(epArrayPayload[j]);
537                     }
538                     OICFree(epArrayPayload);
539                 }
540
541                 for (size_t j = 0; j <= i; j++)
542                 {
543                     OCRepPayloadDestroy(arrayPayload[j]);
544                 }
545                 result = false;
546                 goto exit;
547             }
548         }
549
550         childResource = childResource->next;
551         if (childResource)
552         {
553             iterResource = childResource->rsrcResource;
554         }
555         result = true;
556     }
557
558 exit:
559     if (!result && (arrayPayload != NULL))
560     {
561         OICFree(arrayPayload);
562         arrayPayload = NULL;
563     }
564
565     if (arrayPayload != NULL && createdArraySize != NULL)
566         *createdArraySize = childCount;
567     else if (createdArraySize != NULL)
568         *createdArraySize = 0;
569
570     return arrayPayload;
571 }