aafb5ab51295553d9fe7af813d37066b7496a6ed
[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 "ocstack.h"
32 #include "oicgroup.h"
33 #include "oic_string.h"
34 #include "payload_logging.h"
35
36 #define TAG "OIC_RI_COLLECTION"
37
38 static bool AddRTSBaslinePayload(OCRepPayload **linkArray, int size, OCRepPayload **colPayload)
39 {
40     size_t arraySize = 0;
41     for (int j = 0; j < size; j++)
42     {
43         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {0};
44         char **rt = NULL;
45         OCRepPayloadGetStringArray(linkArray[j], OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
46         arraySize += rtDim[0];
47         for (size_t l = 0; l < rtDim[0]; l++)
48         {
49             OICFree(rt[l]);
50         }
51     }
52
53     for (OCStringLL *rsrcType = (*colPayload)->types; rsrcType; rsrcType = rsrcType->next, arraySize++);
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 (int j = 0; j < size; j++)
65     {
66         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {0};
67         char **rt = NULL;
68         OCRepPayloadGetStringArray(linkArray[j], OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
69         for (size_t l = 0; l < rtDim[0]; l++)
70         {
71             rts[k++] = OICStrdup(rt[l]);
72             OICFree(rt[l]);
73         }
74     }
75     for (OCStringLL *rsrcType = (*colPayload)->types; rsrcType; rsrcType = rsrcType->next, size++)
76     {
77         rts[k++] = OICStrdup(rsrcType->value);
78     }
79
80     return OCRepPayloadSetStringArrayAsOwner(*colPayload, OC_RSRVD_RTS, rts, dim);
81 }
82
83 static OCStackResult SendResponse(const OCRepPayload *payload, const OCEntityHandlerRequest *ehRequest,
84     const OCResource* collResource, OCEntityHandlerResult ehResult)
85 {
86     OCEntityHandlerResponse response = {0};
87     response.ehResult = ehResult;
88     response.payload = (OCPayload*)payload;
89     response.persistentBufferFlag = 0;
90     response.requestHandle = (OCRequestHandle) ehRequest->requestHandle;
91     response.resourceHandle = (OCResourceHandle) collResource;
92     return OCDoResponse(&response);
93 }
94
95 uint8_t GetNumOfResourcesInCollection(const OCResource *collResource)
96 {
97     uint8_t size = 0;
98     for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
99         tempChildResource; tempChildResource = tempChildResource->next)
100     {
101         size++;
102     }
103     return size;
104 }
105
106 static OCStackResult HandleLinkedListInterface(OCEntityHandlerRequest *ehRequest, char *ifQueryParam)
107 {
108     if (!ehRequest)
109     {
110         return OC_STACK_INVALID_PARAM;
111     }
112
113     OCResource *collResource = (OCResource *)ehRequest->resource;
114     if (!collResource)
115     {
116         return OC_STACK_INVALID_PARAM;
117     }
118
119     uint8_t size = GetNumOfResourcesInCollection(collResource);
120     OCRepPayload *colPayload = NULL;
121     OCEntityHandlerResult ehResult = OC_EH_ERROR;
122     int i = 0;
123     OCStackResult ret = OC_STACK_OK;
124     size_t dim[MAX_REP_ARRAY_DEPTH] = {size, 0, 0};
125     OCRepPayload **linkArr = (OCRepPayload **)OICCalloc(size, sizeof(OCRepPayload *));
126     VERIFY_PARAM_NON_NULL(TAG, linkArr, "Failed creating LinkArray");
127
128     for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
129         tempChildResource && ret == OC_STACK_OK; tempChildResource = tempChildResource->next)
130     {
131         OCResource* temp = tempChildResource->rsrcResource;
132         if (temp)
133         {
134             ret = BuildResponseRepresentation(temp, &linkArr[i++], &ehRequest->devAddr);
135         }
136     }
137
138     if (ret == OC_STACK_OK)
139     {
140         colPayload = OCRepPayloadCreate();
141         if (colPayload)
142         {
143             if (0 == strcmp(OC_RSRVD_INTERFACE_DEFAULT, ifQueryParam))
144             {
145                 //TODO : Add resource type filtering once collections
146                 // start supporting queries.
147                 OCRepPayloadAddResourceType(colPayload, OC_RSRVD_RESOURCE_TYPE_COLLECTION);
148                 for (OCResourceType *types = collResource->rsrcType; types; types = types->next)
149                 {
150                     if (0 != strcmp(OC_RSRVD_RESOURCE_TYPE_COLLECTION, types->resourcetypename))
151                     {
152                         OCRepPayloadAddResourceType(colPayload, types->resourcetypename);
153                     }
154                 }
155                 for (OCResourceInterface *itf = collResource->rsrcInterface; itf; itf = itf->next)
156                 {
157                     OCRepPayloadAddInterface(colPayload, itf->name);
158                 }
159                 AddRTSBaslinePayload(linkArr, i, &colPayload);
160             }
161             OCRepPayloadSetPropObjectArrayAsOwner(colPayload, OC_RSRVD_LINKS, linkArr, dim);
162         }
163     }
164
165 exit:
166     if (ret == OC_STACK_OK)
167     {
168         ehResult = OC_EH_OK;
169     }
170     else
171     {
172         ehResult = (ret == OC_STACK_NO_RESOURCE) ? OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR;
173     }
174     ret = SendResponse(colPayload, ehRequest, collResource, ehResult);
175     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)colPayload);
176
177     return ret;
178 }
179
180 static OCStackResult HandleBatchInterface(OCEntityHandlerRequest *ehRequest)
181 {
182     if (!ehRequest)
183     {
184         return OC_STACK_INVALID_PARAM;
185     }
186
187     OCStackResult stackRet = OC_STACK_OK;
188     char *storeQuery = NULL;
189     OCRepPayload *payload = OCRepPayloadCreate();
190     OCResource *collResource = (OCResource *)ehRequest->resource;
191     VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating RepPayload");
192
193     if (stackRet == OC_STACK_OK)
194     {
195
196         if (collResource->rsrcChildResourcesHead)
197         {
198             storeQuery = OICStrdup(ehRequest->query);
199             ehRequest->query = NULL;
200             OIC_LOG_V(DEBUG, TAG, "Query : %s", ehRequest->query);
201         }
202
203         uint8_t numRes = 0;
204         for (OCChildResource *tempChildResource = collResource->rsrcChildResourcesHead;
205             tempChildResource; tempChildResource = tempChildResource->next, numRes++)
206         {
207             OCResource* tempRsrcResource = tempChildResource->rsrcResource;
208             if (tempRsrcResource)
209             {
210                 // Note that all entity handlers called through a collection
211                 // will get the same pointer to ehRequest, the only difference
212                 // is ehRequest->resource
213                 ehRequest->resource = (OCResourceHandle) tempRsrcResource;
214                 OCEntityHandlerResult ehResult = tempRsrcResource->entityHandler(OC_REQUEST_FLAG,
215                                            ehRequest, tempRsrcResource->entityHandlerCallbackParam);
216
217                 // The default collection handler is returning as OK
218                 if (stackRet != OC_STACK_SLOW_RESOURCE)
219                 {
220                     stackRet = OC_STACK_OK;
221                 }
222                 // if a single resource is slow, then entire response will be treated
223                 // as slow response
224                 if (ehResult == OC_EH_SLOW)
225                 {
226                     OIC_LOG(INFO, TAG, "This is a slow resource");
227                     OCServerRequest *request =
228                             GetServerRequestUsingHandle(ehRequest->requestHandle);
229                     if (request)
230                     {
231                         request->slowFlag = 1;
232                     }
233                     stackRet = EntityHandlerCodeToOCStackCode(ehResult);
234                 }
235             }
236             else
237             {
238                 break;
239             }
240         }
241         ehRequest->resource = (OCResourceHandle) collResource;
242     }
243     ehRequest->query = OICStrdup(storeQuery);
244     OICFree(storeQuery);
245     return stackRet;
246 exit:
247     OICFree(storeQuery);
248     return OC_STACK_NO_MEMORY;
249 }
250
251 OCStackResult DefaultCollectionEntityHandler(OCEntityHandlerFlag flag, OCEntityHandlerRequest *ehRequest)
252 {
253     if (!ehRequest || !ehRequest->query)
254     {
255         return OC_STACK_INVALID_PARAM;
256     }
257     // Delete is not supported for any interface query method.
258     if (ehRequest->method == OC_REST_DELETE || flag != OC_REQUEST_FLAG)
259     {
260         return OC_STACK_ERROR;
261     }
262     OIC_LOG_V(INFO, TAG, "DefaultCollectionEntityHandler with query %s", ehRequest->query);
263
264     char *ifQueryParam = NULL;
265     char *rtQueryParam = NULL;
266     OCStackResult result = ExtractFiltersFromQuery(ehRequest->query, &ifQueryParam, &rtQueryParam);
267     if (result != OC_STACK_OK)
268     {
269         result = OC_STACK_NO_RESOURCE;
270         goto exit;
271     }
272     if (!ifQueryParam)
273     {
274         ifQueryParam = OICStrdup(OC_RSRVD_INTERFACE_LL);
275     }
276     if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_LL) || 0 == strcmp (ifQueryParam, OC_RSRVD_INTERFACE_DEFAULT))
277     {
278         if (ehRequest->method == OC_REST_PUT || ehRequest->method == OC_REST_POST)
279         {
280             result =  OC_STACK_ERROR;
281         }
282         else
283         {
284             result = HandleLinkedListInterface(ehRequest, ifQueryParam);
285         }
286     }
287     else if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_BATCH))
288     {
289         OCServerRequest *request = GetServerRequestUsingHandle(ehRequest->requestHandle);
290         if (request)
291         {
292             request->numResponses = GetNumOfResourcesInCollection((OCResource *)ehRequest->resource);
293             request->ehResponseHandler = HandleAggregateResponse;
294             result = HandleBatchInterface(ehRequest);
295         }
296     }
297     else if (0 == strcmp(ifQueryParam, OC_RSRVD_INTERFACE_GROUP))
298     {
299         OIC_LOG_V(INFO, TAG, "IF_COLLECTION %d with request ::\n", ehRequest->method);
300         OIC_LOG_PAYLOAD(INFO, ehRequest->payload);
301         result = BuildCollectionGroupActionCBORResponse(ehRequest->method, (OCResource *) ehRequest->resource, ehRequest);
302     }
303 exit:
304     if (result != OC_STACK_OK)
305     {
306         result = SendResponse(NULL, ehRequest, (OCResource *)ehRequest->resource, OC_EH_BAD_REQ);
307     }
308     OICFree(ifQueryParam);
309     OICFree(rtQueryParam);
310     return result;
311 }