Imported Upstream version 0.9.1
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocresource.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 #include "ocresource.h"
29 #include <string.h>
30 #include "ocresourcehandler.h"
31 #include "ocobserve.h"
32 #include "occollection.h"
33 #include "ocmalloc.h"
34 #include "logger.h"
35 #include "cJSON.h"
36
37 #include "cacommon.h"
38 #include "cainterface.h"
39
40
41 /// Module Name
42 #define TAG PCF("ocresource")
43 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
44             {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
45
46 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
47              TAG, PCF(#arg " is NULL")); return (retVal); } }
48
49 extern OCResource *headResource;
50 static OCPlatformInfo savedPlatformInfo = {};
51 static cJSON *savedDeviceInfo = NULL;
52 static const char * VIRTUAL_RSRCS[] =
53 {
54        "/oc/core",
55        "/oc/core/d",
56        "/oic/p",
57        "/oc/core/types/d",
58        #ifdef WITH_PRESENCE
59        "/oic/ad"
60        #endif
61 };
62
63 //-----------------------------------------------------------------------------
64 // Default resource entity handler function
65 //-----------------------------------------------------------------------------
66 OCEntityHandlerResult defaultResourceEHandler(OCEntityHandlerFlag flag,
67         OCEntityHandlerRequest * request)
68 {
69     //TODO ("Implement me!!!!");
70     // TODO:  remove silence unused param warnings
71     (void) flag;
72     (void) request;
73     return  OC_EH_OK; // Making sure that the Default EH and the Vendor EH have matching signatures
74 }
75
76 /* This method will retrieve the port at which the secure resource is hosted */
77 static OCStackResult GetSecurePortInfo(CATransportType_t connType, uint16_t *port)
78 {
79     CALocalConnectivity_t* info = NULL;
80     uint32_t size = 0;
81     OCStackResult ret = OC_STACK_ERROR;
82
83     CAResult_t caResult = CAGetNetworkInformation(&info, &size);
84     if ((caResult == CA_STATUS_OK) && info && size)
85     {
86         while (size--)
87         {
88             if (info[size].isSecured && info[size].type == connType)
89             {
90                 if (info[size].type == CA_IPV4)
91                 {
92                     *port = info[size].addressInfo.IP.port;
93                     ret = OC_STACK_OK;
94                     break;
95                 }
96             }
97         }
98     }
99
100     OCFree(info);
101     return ret;
102 }
103
104 static char* GetJSONStringFromPlatformInfo(OCPlatformInfo info)
105 {
106     cJSON *rootObj = cJSON_CreateObject();
107
108     if (!rootObj)
109     {
110         return NULL;
111     }
112
113     cJSON *repObj = NULL;
114     char *jsonEncodedInfo = NULL;
115
116     cJSON_AddItemToObject (rootObj, OC_RSRVD_HREF,
117             cJSON_CreateString(GetVirtualResourceUri(OC_PLATFORM_URI)));
118
119     cJSON_AddItemToObject (rootObj, OC_RSRVD_REPRESENTATION, repObj = cJSON_CreateObject());
120
121     cJSON_AddItemToObject (repObj, OC_RSRVD_PLATFORM_ID, cJSON_CreateString(info.platformID));
122     cJSON_AddItemToObject (repObj, OC_RSRVD_MFG_NAME, cJSON_CreateString(info.manufacturerName));
123     if (info.manufacturerUrl)
124     {
125         cJSON_AddItemToObject (repObj, OC_RSRVD_MFG_URL,
126                 cJSON_CreateString(info.manufacturerUrl));
127     }
128
129     if (info.modelNumber)
130     {
131         cJSON_AddItemToObject (repObj, OC_RSRVD_MODEL_NUM,
132                 cJSON_CreateString(info.modelNumber));
133     }
134
135     if (info.dateOfManufacture)
136     {
137         cJSON_AddItemToObject (repObj, OC_RSRVD_MFG_DATE,
138                 cJSON_CreateString(info.dateOfManufacture));
139     }
140
141     if (info.platformVersion)
142     {
143         cJSON_AddItemToObject (repObj, OC_RSRVD_PLATFORM_VERSION,
144                 cJSON_CreateString(info.platformVersion));
145     }
146
147     if (info.operatingSystemVersion)
148     {
149         cJSON_AddItemToObject (repObj, OC_RSRVD_OS_VERSION,
150                 cJSON_CreateString(info.operatingSystemVersion));
151     }
152
153     if (info.hardwareVersion)
154     {
155         cJSON_AddItemToObject (repObj, OC_RSRVD_HARDWARE_VERSION,
156                 cJSON_CreateString(info.hardwareVersion));
157     }
158
159     if (info.firmwareVersion)
160     {
161         cJSON_AddItemToObject (repObj, OC_RSRVD_FIRMWARE_VERSION,
162                 cJSON_CreateString(info.firmwareVersion));
163     }
164
165     if (info.supportUrl)
166     {
167         cJSON_AddItemToObject (repObj, OC_RSRVD_SUPPORT_URL,
168                 cJSON_CreateString(info.supportUrl));
169     }
170
171     if (info.systemTime)
172     {
173         cJSON_AddItemToObject (repObj, OC_RSRVD_SYSTEM_TIME,
174                 cJSON_CreateString(info.systemTime));
175     }
176
177     jsonEncodedInfo = cJSON_PrintUnformatted (rootObj);
178
179     cJSON_Delete(rootObj);
180
181     return jsonEncodedInfo;
182 }
183
184 static OCStackResult ValidateUrlQuery (char *url, char *query,
185                                 uint8_t *filterOn, char **filterValue)
186 {
187     if(!filterOn || !filterValue)
188     {
189         return OC_STACK_INVALID_PARAM;
190     }
191
192     char *filterParam = NULL;
193
194     OC_LOG(INFO, TAG, PCF("Entering ValidateUrlQuery"));
195     if (!url)
196     {
197         return OC_STACK_INVALID_URI;
198     }
199
200     if (strcmp ((char *)url, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0 ||
201                 strcmp ((char *)url, GetVirtualResourceUri(OC_DEVICE_URI)) == 0 ||
202                 strcmp((char *)url, GetVirtualResourceUri(OC_PLATFORM_URI)) == 0)
203     {
204         *filterOn = STACK_RES_DISCOVERY_NOFILTER;
205         if (query && *query)
206         {
207             char* strTokPtr = NULL;
208             filterParam = strtok_r((char *)query, "=", &strTokPtr);
209             *filterValue = strtok_r(NULL, " ", &strTokPtr);
210
211             if (!(*filterValue) || ! filterParam)
212             {
213                 return OC_STACK_INVALID_QUERY;
214             }
215             else if (strcmp (filterParam, OC_RSRVD_INTERFACE) == 0)
216             {
217                 // Resource discovery with interface filter
218                 *filterOn = STACK_RES_DISCOVERY_IF_FILTER;
219             }
220             else if (strcmp (filterParam, OC_RSRVD_RESOURCE_TYPE) == 0)
221             {
222                 // Resource discovery with resource type filter
223                 *filterOn = STACK_RES_DISCOVERY_RT_FILTER;
224             }
225             else if (strcmp (filterParam, OC_RSRVD_DEVICE_ID) == 0)
226             {
227                 //Device ID filter
228                 *filterOn = STACK_DEVICE_DISCOVERY_DI_FILTER;
229             }
230             else if (strcmp (filterParam, OC_RSRVD_DEVICE_NAME) == 0)
231             {
232                 //Device Name filter
233                 *filterOn = STACK_DEVICE_DISCOVERY_DN_FILTER;
234             }
235             else
236             {
237                 // Other filter types not supported
238                 return OC_STACK_INVALID_QUERY;
239             }
240         }
241     }
242     #ifdef WITH_PRESENCE
243     else if (strcmp((char *)url, GetVirtualResourceUri(OC_PRESENCE)) == 0)
244     {
245         //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
246         OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request"));
247         *filterOn = STACK_RES_DISCOVERY_NOFILTER;
248     }
249     #endif
250     else
251     {
252         // Other URIs not yet supported
253         return OC_STACK_INVALID_URI;
254     }
255     OC_LOG(INFO, TAG, PCF("Exiting ValidateUrlQuery"));
256     return OC_STACK_OK;
257 }
258
259
260 OCStackResult
261 BuildVirtualResourceResponse(const OCResource *resourcePtr, uint8_t filterOn,
262                        const char *filterValue, char *out, uint16_t *remaining,
263                        CATransportType_t connType )
264 {
265     if(!resourcePtr || !out  || !remaining)
266     {
267         return OC_STACK_INVALID_PARAM;
268     }
269
270     OCResourceType *resourceTypePtr = NULL;
271     OCResourceInterface *interfacePtr = NULL;
272     cJSON *resObj = NULL;
273     cJSON *propObj = NULL;
274     cJSON *rtArray = NULL;
275     char *jsonStr = NULL;
276     uint8_t encodeRes = 0;
277     OCStackResult ret = OC_STACK_OK;
278     uint16_t jsonLen = 0;
279
280     OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponse"));
281     resObj = cJSON_CreateObject();
282
283     if (resourcePtr)
284     {
285         encodeRes = 0;
286         if ((filterOn == STACK_RES_DISCOVERY_RT_FILTER) && filterValue)
287         {
288             resourceTypePtr = resourcePtr->rsrcType;
289             while (resourceTypePtr)
290             {
291                 if (strcmp (resourceTypePtr->resourcetypename, filterValue) == 0)
292                 {
293                     encodeRes = 1;
294                     break;
295                 }
296                 resourceTypePtr = resourceTypePtr->next;
297             }
298         }
299         else if ((filterOn == STACK_RES_DISCOVERY_IF_FILTER) && filterValue)
300         {
301             interfacePtr = resourcePtr->rsrcInterface;
302             while (interfacePtr)
303             {
304                 if (strcmp (interfacePtr->name, filterValue) == 0)
305                 {
306                     encodeRes = 1;
307                     break;
308                 }
309                 interfacePtr = interfacePtr->next;
310             }
311         }
312         else if (filterOn == STACK_RES_DISCOVERY_NOFILTER)
313         {
314             encodeRes = 1;
315         }
316         else
317         {
318             //TODO: Unsupported query filter
319             return OC_STACK_INVALID_QUERY;
320         }
321
322         if (encodeRes)
323         {
324             // Add URIs
325             cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resourcePtr->uri));
326
327             // Add server instance id
328             cJSON_AddItemToObject (resObj,
329                                    OC_RSRVD_SERVER_INSTANCE_ID,
330                                    cJSON_CreateString(OCGetServerInstanceIDString()));
331
332             cJSON_AddItemToObject (resObj, OC_RSRVD_PROPERTY, propObj = cJSON_CreateObject());
333             // Add resource types
334             cJSON_AddItemToObject (propObj, OC_RSRVD_RESOURCE_TYPE, rtArray = cJSON_CreateArray());
335             resourceTypePtr = resourcePtr->rsrcType;
336             while (resourceTypePtr)
337             {
338                 cJSON_AddItemToArray (rtArray,
339                                       cJSON_CreateString(resourceTypePtr->resourcetypename));
340                 resourceTypePtr = resourceTypePtr->next;
341             }
342             // Add interface types
343             cJSON_AddItemToObject (propObj, OC_RSRVD_INTERFACE, rtArray = cJSON_CreateArray());
344             interfacePtr = resourcePtr->rsrcInterface;
345             while (interfacePtr)
346             {
347                 cJSON_AddItemToArray (rtArray, cJSON_CreateString(interfacePtr->name));
348                 interfacePtr = interfacePtr->next;
349             }
350             // If resource is observable, set observability flag.
351             // Resources that are not observable will not have the flag.
352             if (resourcePtr->resourceProperties & OC_OBSERVABLE)
353             {
354                 cJSON_AddItemToObject (propObj, OC_RSRVD_OBSERVABLE,
355                                        cJSON_CreateNumber(OC_RESOURCE_OBSERVABLE));
356             }
357             // Set secure flag for secure resources
358             if (resourcePtr->resourceProperties & OC_SECURE)
359             {
360                 cJSON_AddNumberToObject (propObj, OC_RSRVD_SECURE, OC_RESOURCE_SECURE);
361                 //Set the IP port also as secure resources are hosted on a different port
362                 uint16_t port = 0;
363                 if (GetSecurePortInfo (connType, &port) == OC_STACK_OK)
364                 {
365                     cJSON_AddNumberToObject (propObj, OC_RSRVD_HOSTING_PORT, port);
366                 }
367             }
368
369         }
370     }
371     jsonStr = cJSON_PrintUnformatted (resObj);
372
373     if(!jsonStr)
374     {
375         cJSON_Delete(resObj);
376         return OC_STACK_NO_MEMORY;
377     }
378
379     jsonLen = strlen(jsonStr);
380     if (jsonLen < *remaining)
381     {
382         strcpy(out, jsonStr);
383         *remaining = *remaining - jsonLen;
384     }
385     else
386     {
387         ret = OC_STACK_ERROR;
388     }
389     cJSON_Delete (resObj);
390     OCFree (jsonStr);
391
392     OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponse"));
393     return ret;
394 }
395
396 OCStackResult BuildVirtualResourceResponseForDevice(uint8_t filterOn, char *filterValue,
397                                                     char *out, uint16_t *remaining)
398 {
399     if(!out || !remaining)
400     {
401         return OC_STACK_INVALID_PARAM;
402     }
403
404     OCStackResult ret = OC_STACK_ERROR;
405
406     if (savedDeviceInfo != NULL)
407     {
408         char *jsonStr = NULL;
409         uint16_t jsonLen = 0;
410         cJSON *repObj = cJSON_GetObjectItem(savedDeviceInfo, OC_RSRVD_REPRESENTATION);
411
412         OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponseForDevice"));
413
414         if ((filterOn == STACK_DEVICE_DISCOVERY_DI_FILTER) && filterValue)
415         {
416             if((cJSON_GetObjectItem(repObj,OC_RSRVD_DEVICE_ID) != NULL) &&
417                     strcmp(cJSON_GetObjectItem(repObj,OC_RSRVD_DEVICE_ID)->valuestring, filterValue)
418                     == 0)
419             {
420                 ret = OC_STACK_OK;
421             }
422         }
423         else if ((filterOn == STACK_DEVICE_DISCOVERY_DN_FILTER) && filterValue)
424         {
425             if((cJSON_GetObjectItem(repObj,OC_RSRVD_DEVICE_NAME) != NULL) &&
426                     strcmp(cJSON_GetObjectItem(repObj,OC_RSRVD_DEVICE_NAME)->valuestring,
427                         filterValue) == 0)
428             {
429                 ret = OC_STACK_OK;
430             }
431         }
432         else if (filterOn == STACK_RES_DISCOVERY_NOFILTER)
433         {
434             ret = OC_STACK_OK;
435         }
436         else
437         {
438             ret = OC_STACK_INVALID_QUERY;
439         }
440
441         if (ret == OC_STACK_OK)
442         {
443             jsonStr = cJSON_PrintUnformatted (savedDeviceInfo);
444
445             if(jsonStr)
446             {
447                 jsonLen = strlen(jsonStr);
448
449                 if (jsonLen < *remaining)
450                 {
451                     strncpy(out, jsonStr, (jsonLen + 1));
452                     *remaining = *remaining - jsonLen;
453                     ret = OC_STACK_OK;
454                 }
455                 else
456                 {
457                     ret = OC_STACK_ERROR;
458                 }
459
460                 OCFree(jsonStr);
461             }
462             else
463             {
464                 ret = OC_STACK_ERROR;
465             }
466         }
467         else
468         {
469             ret = OC_STACK_INVALID_DEVICE_INFO;
470         }
471     }
472     else
473     {
474         OC_LOG(ERROR, TAG, PCF("No device info found."));
475         //error so that stack won't respond with empty payload
476         ret = OC_STACK_INVALID_DEVICE_INFO;
477     }
478
479     OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponseForDevice"));
480     return ret;
481 }
482
483 OCStackResult BuildVirtualResourceResponseForPlatform(char *out, uint16_t *remaining)
484 {
485     OCStackResult ret = OC_STACK_OK;
486
487     char *jsonStr = GetJSONStringFromPlatformInfo(savedPlatformInfo);
488
489     if(jsonStr)
490     {
491         size_t jsonLen = strlen(jsonStr);
492
493         if (jsonLen < *remaining)
494         {
495             strncpy(out, jsonStr, (jsonLen + 1));
496             *remaining = *remaining - jsonLen;
497             ret = OC_STACK_OK;
498         }
499         else
500         {
501             OC_LOG_V(ERROR, TAG, PCF("Platform info string too big. len: %u"), jsonLen);
502             ret = OC_STACK_ERROR;
503         }
504         OCFree(jsonStr);
505     }
506     else
507     {
508         OC_LOG(ERROR, TAG, PCF("Error encoding save platform info."));
509         ret = OC_STACK_ERROR;
510     }
511
512
513     return ret;
514
515 }
516 const char * GetVirtualResourceUri( OCVirtualResources resource)
517 {
518     if (resource < OC_MAX_VIRTUAL_RESOURCES)
519     {
520         return VIRTUAL_RSRCS[resource];
521     }
522
523     return NULL;
524 }
525
526 bool IsVirtualResource(const char* resourceUri)
527 {
528     if(!resourceUri)
529     {
530         return false;
531     }
532
533     for (int i = 0; i < OC_MAX_VIRTUAL_RESOURCES; i++)
534     {
535         if (strcmp(resourceUri, GetVirtualResourceUri((OCVirtualResources)i)) == 0)
536         {
537             return true;
538         }
539     }
540     return false;
541 }
542
543 uint8_t IsCollectionResource (OCResource *resource)
544 {
545     if(!resource)
546     {
547         return 0;
548     }
549
550     for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
551     {
552         if (resource->rsrcResources[i])
553         {
554             return 1;
555         }
556     }
557     return 0;
558 }
559
560 OCResource *FindResourceByUri(const char* resourceUri)
561 {
562     if(!resourceUri)
563     {
564         return NULL;
565     }
566
567     OCResource * pointer = headResource;
568     while (pointer)
569     {
570         if (strcmp(resourceUri, pointer->uri) == 0)
571         {
572             return pointer;
573         }
574         pointer = pointer->next;
575     }
576     OC_LOG(INFO, TAG, PCF("Resource not found"));
577     return NULL;
578 }
579
580
581 OCStackResult DetermineResourceHandling (const OCServerRequest *request,
582                                          ResourceHandling *handling,
583                                          OCResource **resource)
584 {
585     if(!request || !handling || !resource)
586     {
587         return OC_STACK_INVALID_PARAM;
588     }
589
590     OC_LOG(INFO, TAG, PCF("Entering DetermineResourceHandling"));
591
592     // Check if virtual resource
593     if (IsVirtualResource((const char*)request->resourceUrl))
594     {
595         *handling = OC_RESOURCE_VIRTUAL;
596         *resource = headResource;
597         return OC_STACK_OK;
598     }
599     if (NULL == request->resourceUrl || (strlen((const char*)(request->resourceUrl)) == 0))
600     {
601         // Resource URL not specified
602         *handling = OC_RESOURCE_NOT_SPECIFIED;
603         return OC_STACK_NO_RESOURCE;
604     }
605     else
606     {
607         OCResource *resourcePtr = NULL;
608         resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
609         *resource = resourcePtr;
610         if (!resourcePtr)
611         {
612             if(defaultDeviceHandler)
613             {
614                 *handling = OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER;
615                 return OC_STACK_OK;
616             }
617
618             // Resource does not exist
619             // and default device handler does not exist
620             *handling = OC_RESOURCE_NOT_SPECIFIED;
621             return OC_STACK_NO_RESOURCE;
622         }
623
624         // secure resource will entertain only authorized requests
625         if ((resourcePtr->resourceProperties & OC_SECURE) && (request->secured == 0))
626         {
627             OC_LOG(ERROR, TAG, PCF("Un-authorized request. Ignoring"));
628             return OC_STACK_RESOURCE_ERROR;
629         }
630
631         if (IsCollectionResource (resourcePtr))
632         {
633             // Collection resource
634             if (resourcePtr->entityHandler != defaultResourceEHandler)
635             {
636                 *handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
637                 return OC_STACK_OK;
638             }
639             else
640             {
641                 *handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
642                 return OC_STACK_OK;
643             }
644         }
645         else
646         {
647             // Resource not a collection
648             if (resourcePtr->entityHandler != defaultResourceEHandler)
649             {
650                 *handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
651                 return OC_STACK_OK;
652             }
653             else
654             {
655                 *handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
656                 return OC_STACK_OK;
657             }
658         }
659     }
660 }
661
662 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
663 {
664     OCStackResult result;
665
666     switch (ehResult)
667     {
668         case OC_EH_OK:
669             result = OC_STACK_OK;
670             break;
671         case OC_EH_SLOW:
672             result = OC_STACK_SLOW_RESOURCE;
673             break;
674         case OC_EH_ERROR:
675             result = OC_STACK_ERROR;
676             break;
677         case OC_EH_FORBIDDEN:
678             result = OC_STACK_RESOURCE_ERROR;
679             break;
680         case OC_EH_RESOURCE_CREATED:
681             result = OC_STACK_RESOURCE_CREATED;
682             break;
683         case OC_EH_RESOURCE_DELETED:
684             result = OC_STACK_RESOURCE_DELETED;
685             break;
686         case OC_EH_RESOURCE_NOT_FOUND:
687             result = OC_STACK_NO_RESOURCE;
688             break;
689         default:
690             result = OC_STACK_ERROR;
691     }
692
693     return result;
694 }
695
696 static OCStackResult
697 HandleVirtualResource (OCServerRequest *request, OCResource* resource)
698 {
699     if(!request || !resource)
700     {
701         return OC_STACK_INVALID_PARAM;
702     }
703
704     OCStackResult result = OC_STACK_ERROR;
705     char *filterValue = NULL;
706     uint8_t filterOn = 0;
707     uint16_t remaining = 0;
708     char * ptr = NULL;
709     uint8_t firstLoopDone = 0;
710     char discoveryResBuf[MAX_RESPONSE_LENGTH] = {};
711
712     OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
713
714     result = ValidateUrlQuery (request->resourceUrl,
715             request->query, &filterOn,
716             &filterValue);
717
718     if (result == OC_STACK_OK)
719     {
720         if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0)
721         {
722             ptr = discoveryResBuf;
723             remaining = MAX_RESPONSE_LENGTH;
724
725             // Check if valid resource and enough space in buffer for atleast
726             // the null character.
727             while(resource && (remaining > 1))
728             {
729                 if((resource->resourceProperties & OC_ACTIVE)
730                         && (resource->resourceProperties & OC_DISCOVERABLE))
731                 {
732                     // if there is data on the buffer, we have already added a response,
733                     // so we need to add a comma before we do anything
734                     if(firstLoopDone
735                             && remaining >= (sizeof(OC_JSON_SEPARATOR)+1))
736                     {
737                         *ptr = OC_JSON_SEPARATOR;
738                         ptr++;
739                         remaining--;
740                     }
741                     firstLoopDone = 1;
742                     result = BuildVirtualResourceResponse(resource, filterOn, filterValue,
743                             (char*)ptr, &remaining, request->connectivityType );
744
745                     if (result != OC_STACK_OK)
746                     {
747                         // if this failed, we need to remove the comma added above.
748                         if(!firstLoopDone)
749                         {
750                             ptr--;
751                             *ptr = '\0';
752                             remaining++;
753                         }
754                         break;
755                     }
756                     ptr += strlen((char *)ptr);
757                 }
758                 resource = resource->next;
759             }
760
761             if(strlen((const char *)discoveryResBuf) > 0)
762             {
763                 OCEntityHandlerResponse response = {};
764
765                 response.ehResult = OC_EH_OK;
766                 response.payload = discoveryResBuf;
767                 response.payloadSize = strlen((const char *)discoveryResBuf) + 1;
768                 response.persistentBufferFlag = 0;
769                 response.requestHandle = (OCRequestHandle) request;
770                 response.resourceHandle = (OCResourceHandle) resource;
771
772                 result = OCDoResponse(&response);
773             }
774         }
775         else if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_DEVICE_URI)) == 0)
776         {
777             remaining = MAX_RESPONSE_LENGTH;
778             ptr = discoveryResBuf;
779
780             result = BuildVirtualResourceResponseForDevice(filterOn, filterValue,
781                     (char*)ptr, &remaining);
782
783             if(result == OC_STACK_OK)
784             {
785                 ptr += strlen((char*)ptr);
786             }
787
788             if(remaining < MAX_RESPONSE_LENGTH)
789             {
790                 OCEntityHandlerResponse response = {0};
791
792                 response.ehResult = OC_EH_OK;
793                 response.payload = discoveryResBuf;
794                 response.payloadSize = strlen((const char *)discoveryResBuf) + 1;
795                 response.persistentBufferFlag = 0;
796                 response.requestHandle = (OCRequestHandle) request;
797                 response.resourceHandle = (OCResourceHandle) resource;
798
799                 result = OCDoResponse(&response);
800             }
801         }
802         else if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_PLATFORM_URI)) == 0)
803         {
804             remaining = MAX_RESPONSE_LENGTH;
805             ptr = discoveryResBuf;
806
807             result = BuildVirtualResourceResponseForPlatform((char*)ptr, &remaining);
808
809             if(result == OC_STACK_OK)
810             {
811                 ptr += strlen((char*)ptr);
812             }
813
814             if(remaining < MAX_RESPONSE_LENGTH)
815             {
816                 OCEntityHandlerResponse response = {0};
817
818                 response.ehResult = OC_EH_OK;
819                 response.payload = discoveryResBuf;
820                 response.payloadSize = strlen((const char *)discoveryResBuf) + 1;
821                 response.persistentBufferFlag = 0;
822                 response.requestHandle = (OCRequestHandle) request;
823                 response.resourceHandle = (OCResourceHandle) resource;
824
825                 result = OCDoResponse(&response);
826             }
827         }
828         #ifdef WITH_PRESENCE
829         else
830         {
831             if(resource->resourceProperties & OC_ACTIVE){
832                 SendPresenceNotification(NULL);
833             }
834         }
835         #endif
836     }
837     result = OC_STACK_OK;
838     return result;
839 }
840
841 static OCStackResult
842 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
843 {
844     if(!request)
845     {
846         return OC_STACK_INVALID_PARAM;
847     }
848
849     OCStackResult result = OC_STACK_OK;
850     OCEntityHandlerResult ehResult = OC_EH_ERROR;
851     OCEntityHandlerRequest ehRequest = {};
852
853     OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithDefaultDeviceEntityHandler"));
854     result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
855             request->method, (OCResourceHandle) NULL, request->query,
856             request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
857             request->rcvdVendorSpecificHeaderOptions,
858             (OCObserveAction)request->observationOption, (OCObservationId)0);
859     VERIFY_SUCCESS(result, OC_STACK_OK);
860
861     // At this point we know for sure that defaultDeviceHandler exists
862     ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
863                                   (char*) request->resourceUrl);
864     if(ehResult == OC_EH_SLOW)
865     {
866         OC_LOG(INFO, TAG, PCF("This is a slow resource"));
867         request->slowFlag = 1;
868     }
869     else if(ehResult == OC_EH_ERROR)
870     {
871         FindAndDeleteServerRequest(request);
872     }
873     result = EntityHandlerCodeToOCStackCode(ehResult);
874 exit:
875     return result;
876 }
877
878 static OCStackResult
879 HandleResourceWithEntityHandler (OCServerRequest *request,
880                                  OCResource *resource,
881                                  uint8_t collectionResource)
882 {
883     if(!request || ! resource)
884     {
885         return OC_STACK_INVALID_PARAM;
886     }
887
888     OCStackResult result = OC_STACK_ERROR;
889     OCEntityHandlerResult ehResult = OC_EH_ERROR;
890     OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
891     ResourceObserver *resObs = NULL;
892
893     OCEntityHandlerRequest ehRequest = {};
894
895     OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithEntityHandler"));
896     result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
897             request->method, (OCResourceHandle) resource, request->query,
898             request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
899             request->rcvdVendorSpecificHeaderOptions,
900             (OCObserveAction)request->observationOption, 0);
901     VERIFY_SUCCESS(result, OC_STACK_OK);
902
903     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
904     {
905         OC_LOG(INFO, TAG, PCF("No observation requested"));
906         ehFlag = OC_REQUEST_FLAG;
907     }
908     else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER &&
909             !collectionResource)
910     {
911         OC_LOG(INFO, TAG, PCF("Registering observation requested"));
912         result = GenerateObserverId(&ehRequest.obsInfo.obsId);
913         VERIFY_SUCCESS(result, OC_STACK_OK);
914
915         result = AddObserver ((const char*)(request->resourceUrl),
916                 (const char *)(request->query),
917                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
918                 resource, request->qos,
919                 &request->addressInfo, request->connectivityType);
920
921         if(result == OC_STACK_OK)
922         {
923             OC_LOG(INFO, TAG, PCF("Added observer successfully"));
924             request->observeResult = OC_STACK_OK;
925             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
926         }
927         else
928         {
929             result = OC_STACK_OK;
930             // The error in observeResult for the request will be
931             // used when responding to this request by omitting
932             // the observation option/sequence number.
933             request->observeResult = OC_STACK_ERROR;
934             OC_LOG(ERROR, TAG, PCF("Observer Addition failed"));
935             ehFlag = OC_REQUEST_FLAG;
936         }
937
938     }
939     else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER &&
940             !collectionResource)
941     {
942         OC_LOG(INFO, TAG, PCF("Deregistering observation requested"));
943
944         resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
945
946         if (NULL == resObs)
947         {
948             // Stack does not contain this observation request
949             // Either token is incorrect or observation list is corrupted
950             result = OC_STACK_ERROR;
951             goto exit;
952         }
953         ehRequest.obsInfo.obsId = resObs->observeId;
954         ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
955
956         result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
957
958         if(result == OC_STACK_OK)
959         {
960             OC_LOG(INFO, TAG, PCF("Removed observer successfully"));
961             request->observeResult = OC_STACK_OK;
962         }
963         else
964         {
965             result = OC_STACK_OK;
966             request->observeResult = OC_STACK_ERROR;
967             OC_LOG(ERROR, TAG, PCF("Observer Removal failed"));
968         }
969     }
970     else
971     {
972         result = OC_STACK_ERROR;
973         goto exit;
974     }
975
976     ehResult = resource->entityHandler(ehFlag, &ehRequest);
977     if(ehResult == OC_EH_SLOW)
978     {
979         OC_LOG(INFO, TAG, PCF("This is a slow resource"));
980         request->slowFlag = 1;
981     }
982     else if(ehResult == OC_EH_ERROR)
983     {
984         FindAndDeleteServerRequest(request);
985     }
986     result = EntityHandlerCodeToOCStackCode(ehResult);
987 exit:
988     return result;
989 }
990
991 static OCStackResult
992 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
993                                               OCResource *resource)
994 {
995     if(!request || !resource)
996     {
997         return OC_STACK_INVALID_PARAM;
998     }
999
1000     OCStackResult result = OC_STACK_ERROR;
1001     OCEntityHandlerRequest ehRequest = {};
1002
1003     result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
1004             request->method, (OCResourceHandle) resource, request->query,
1005             request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
1006             request->rcvdVendorSpecificHeaderOptions,
1007             (OCObserveAction)request->observationOption, (OCObservationId) 0);
1008     if(result != OC_STACK_OK)
1009     {
1010         return result;
1011     }
1012
1013     return (DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest));
1014 }
1015
1016 OCStackResult
1017 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
1018 {
1019     OCStackResult ret = OC_STACK_OK;
1020
1021     switch (resHandling)
1022     {
1023         case OC_RESOURCE_VIRTUAL:
1024         {
1025             ret = HandleVirtualResource (request, resource);
1026             break;
1027         }
1028         case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
1029         {
1030             ret = HandleDefaultDeviceEntityHandler(request);
1031             break;
1032         }
1033         case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
1034         {
1035             OC_LOG(INFO, TAG, PCF("OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER"));
1036             return OC_STACK_ERROR;
1037         }
1038         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
1039         {
1040             ret = HandleResourceWithEntityHandler (request, resource, 0);
1041             break;
1042         }
1043         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
1044         {
1045             ret = HandleResourceWithEntityHandler (request, resource, 1);
1046             break;
1047         }
1048         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
1049         {
1050             ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
1051             break;
1052         }
1053         case OC_RESOURCE_NOT_SPECIFIED:
1054         {
1055             ret = OC_STACK_NO_RESOURCE;
1056             break;
1057         }
1058         default:
1059         {
1060             OC_LOG(INFO, TAG, PCF("Invalid Resource Determination"));
1061             return OC_STACK_ERROR;
1062         }
1063     }
1064     return ret;
1065 }
1066
1067 void DeleteDeviceInfo()
1068 {
1069     if(savedDeviceInfo)
1070     {
1071         cJSON_Delete(savedDeviceInfo);
1072     }
1073 }
1074
1075 void DeletePlatformInfo()
1076 {
1077     OC_LOG(INFO, TAG, PCF("Deleting platform info."));
1078
1079     OCFree(savedPlatformInfo.platformID);
1080     savedPlatformInfo.platformID = NULL;
1081
1082     OCFree(savedPlatformInfo.manufacturerName);
1083     savedPlatformInfo.manufacturerName = NULL;
1084
1085     OCFree(savedPlatformInfo.manufacturerUrl);
1086     savedPlatformInfo.manufacturerUrl = NULL;
1087
1088     OCFree(savedPlatformInfo.modelNumber);
1089     savedPlatformInfo.modelNumber = NULL;
1090
1091     OCFree(savedPlatformInfo.dateOfManufacture);
1092     savedPlatformInfo.dateOfManufacture = NULL;
1093
1094     OCFree(savedPlatformInfo.platformVersion);
1095     savedPlatformInfo.platformVersion = NULL;
1096
1097     OCFree(savedPlatformInfo.operatingSystemVersion);
1098     savedPlatformInfo.operatingSystemVersion = NULL;
1099
1100     OCFree(savedPlatformInfo.hardwareVersion);
1101     savedPlatformInfo.hardwareVersion = NULL;
1102
1103     OCFree(savedPlatformInfo.firmwareVersion);
1104     savedPlatformInfo.firmwareVersion = NULL;
1105
1106     OCFree(savedPlatformInfo.supportUrl);
1107     savedPlatformInfo.supportUrl = NULL;
1108
1109     OCFree(savedPlatformInfo.systemTime);
1110     savedPlatformInfo.systemTime = NULL;
1111 }
1112
1113 static OCStackResult CloneStringIfNonNull(char **dest, char *src)
1114 {
1115     if (src)
1116     {
1117         *dest = (char*) OCMalloc(strlen(src) + 1);
1118         if (!*dest)
1119         {
1120             return OC_STACK_NO_MEMORY;
1121         }
1122         strcpy(*dest, src);
1123     }
1124     else
1125     {
1126         *dest = NULL;
1127     }
1128     return OC_STACK_OK;
1129 }
1130 static OCStackResult DeepCopyPlatFormInfo(OCPlatformInfo info)
1131 {
1132     DeletePlatformInfo();
1133
1134     OCStackResult ret = OC_STACK_OK;
1135     ret = CloneStringIfNonNull(&(savedPlatformInfo.platformID), info.platformID);
1136     VERIFY_SUCCESS(ret, OC_STACK_OK);
1137
1138     ret = CloneStringIfNonNull(&(savedPlatformInfo.manufacturerName), info.manufacturerName);
1139     VERIFY_SUCCESS(ret, OC_STACK_OK);
1140
1141     ret = CloneStringIfNonNull(&(savedPlatformInfo.manufacturerUrl), info.manufacturerUrl);
1142     VERIFY_SUCCESS(ret, OC_STACK_OK);
1143
1144     ret = CloneStringIfNonNull(&(savedPlatformInfo.modelNumber), info.modelNumber);
1145     VERIFY_SUCCESS(ret, OC_STACK_OK);
1146
1147     ret = CloneStringIfNonNull(&(savedPlatformInfo.dateOfManufacture), info.dateOfManufacture);
1148     VERIFY_SUCCESS(ret, OC_STACK_OK);
1149
1150     ret = CloneStringIfNonNull(&(savedPlatformInfo.platformVersion), info.platformVersion);
1151     VERIFY_SUCCESS(ret, OC_STACK_OK);
1152
1153     ret = CloneStringIfNonNull(&(savedPlatformInfo.operatingSystemVersion), info.operatingSystemVersion);
1154     VERIFY_SUCCESS(ret, OC_STACK_OK);
1155
1156     ret = CloneStringIfNonNull(&(savedPlatformInfo.hardwareVersion), info.hardwareVersion);
1157     VERIFY_SUCCESS(ret, OC_STACK_OK);
1158
1159     ret = CloneStringIfNonNull(&(savedPlatformInfo.firmwareVersion), info.firmwareVersion);
1160     VERIFY_SUCCESS(ret, OC_STACK_OK);
1161
1162     ret = CloneStringIfNonNull(&(savedPlatformInfo.supportUrl), info.supportUrl);
1163     VERIFY_SUCCESS(ret, OC_STACK_OK);
1164
1165     ret = CloneStringIfNonNull(&(savedPlatformInfo.systemTime), info.systemTime);
1166     VERIFY_SUCCESS(ret, OC_STACK_OK);
1167
1168     return OC_STACK_OK;
1169
1170     exit:
1171         DeletePlatformInfo();
1172         return ret;
1173
1174 }
1175
1176 OCStackResult SavePlatformInfo(OCPlatformInfo info)
1177 {
1178     OCStackResult res = DeepCopyPlatFormInfo(info);
1179
1180     if (res != OC_STACK_OK)
1181     {
1182         OC_LOG_V(ERROR, TAG, PCF("Failed to save platform info. errno(%d)"), res);
1183     }
1184     else
1185     {
1186         OC_LOG(ERROR, TAG, PCF("Platform info saved."));
1187     }
1188
1189     return res;
1190 }