RD query handling
[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 "oic_malloc.h"
34 #include "oic_string.h"
35 #include "logger.h"
36 #include "cJSON.h"
37 #include "ocpayload.h"
38
39 #include "cacommon.h"
40 #include "cainterface.h"
41
42 #ifdef WITH_RD
43 #include "rd_server.h"
44 #endif
45
46 /// Module Name
47 #define TAG PCF("ocresource")
48 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
49             {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
50
51 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
52              TAG, PCF(#arg " is NULL")); return (retVal); } }
53
54 extern OCResource *headResource;
55 static OCPlatformInfo savedPlatformInfo = {0};
56 static OCDeviceInfo savedDeviceInfo = {0};
57
58 //-----------------------------------------------------------------------------
59 // Default resource entity handler function
60 //-----------------------------------------------------------------------------
61 OCEntityHandlerResult defaultResourceEHandler(OCEntityHandlerFlag flag,
62         OCEntityHandlerRequest * request, void* callbackParam)
63 {
64     //TODO ("Implement me!!!!");
65     // TODO:  remove silence unused param warnings
66     (void) flag;
67     (void) request;
68     (void) callbackParam;
69     return  OC_EH_OK; // Making sure that the Default EH and the Vendor EH have matching signatures
70 }
71
72 /* This method will retrieve the port at which the secure resource is hosted */
73 static OCStackResult GetSecurePortInfo(OCDevAddr *endpoint, uint16_t *port)
74 {
75     uint16_t p = 0;
76
77     if (endpoint->adapter == OC_ADAPTER_IP)
78     {
79         if (endpoint->flags & OC_IP_USE_V6)
80         {
81             p = caglobals.ip.u6s.port;
82         }
83         else if (endpoint->flags & OC_IP_USE_V4)
84         {
85             p = caglobals.ip.u4s.port;
86         }
87     }
88
89     *port = p;
90     return OC_STACK_OK;
91 }
92
93 /*
94  * Function will extract 0, 1 or 2 filters from query.
95  * More than 2 filters or unsupported filters will result in error.
96  * If both filters are of the same supported type, the 2nd one will be picked.
97  * Resource and device filters in the SAME query are NOT validated
98  * and resources will likely not clear filters.
99  */
100 static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char **filterTwo)
101 {
102
103     char *key = NULL;
104     char *value = NULL;
105     char *restOfQuery = NULL;
106     int numKeyValuePairsParsed = 0;
107
108     *filterOne = NULL;
109     *filterTwo = NULL;
110
111     OC_LOG_V(INFO, TAG, "Extracting params from %s", query);
112
113     char *keyValuePair = strtok_r (query, OC_QUERY_SEPARATOR, &restOfQuery);
114
115     while(keyValuePair)
116     {
117         if (numKeyValuePairsParsed >= 2)
118         {
119             OC_LOG(ERROR, TAG, PCF("More than 2 queries params in URI."));
120             return OC_STACK_INVALID_QUERY;
121         }
122
123         key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
124
125         if (!key || !value)
126         {
127             return OC_STACK_INVALID_QUERY;
128         }
129         else if (strcmp (key, OC_RSRVD_INTERFACE) == 0)
130         {
131             *filterOne = value;     // if
132         }
133         else if (strcmp (key, OC_RSRVD_RESOURCE_TYPE) == 0)
134         {
135             *filterTwo = value;     // rt
136         }
137         else
138         {
139             OC_LOG_V(ERROR, TAG, "Unsupported query key: %s", key);
140             return OC_STACK_INVALID_QUERY;
141         }
142         ++numKeyValuePairsParsed;
143
144         keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
145     }
146
147     OC_LOG_V(INFO, TAG, "Extracted params %s and %s.", *filterOne, *filterTwo);
148     return OC_STACK_OK;
149 }
150
151 static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
152 {
153     if (strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_URI) == 0)
154     {
155         return OC_WELL_KNOWN_URI;
156     }
157     else if (strcmp(uriInRequest, OC_RSRVD_DEVICE_URI) == 0)
158     {
159         return OC_DEVICE_URI;
160     }
161     else if (strcmp(uriInRequest, OC_RSRVD_PLATFORM_URI) == 0)
162     {
163         return OC_PLATFORM_URI;
164     }
165     else if (strcmp(uriInRequest, OC_RSRVD_RESOURCE_TYPES_URI) == 0)
166     {
167         return OC_RESOURCE_TYPES_URI;
168     }
169 #ifdef WITH_PRESENCE
170     else if (strcmp(uriInRequest, OC_RSRVD_PRESENCE_URI) == 0)
171     {
172         return OC_PRESENCE;
173     }
174 #endif //WITH_PRESENCE
175     return OC_UNKNOWN_URI;
176 }
177
178 static OCStackResult getQueryParamsForFiltering (OCVirtualResources uri, char *query,
179                                             char **filterOne, char **filterTwo)
180 {
181     if(!filterOne || !filterTwo)
182     {
183         return OC_STACK_INVALID_PARAM;
184     }
185
186     *filterOne = NULL;
187     *filterTwo = NULL;
188
189     #ifdef WITH_PRESENCE
190     if (uri == OC_PRESENCE)
191     {
192         //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
193         OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request for virtual resource."));
194         return OC_STACK_OK;
195     }
196     #endif
197
198     OCStackResult result = OC_STACK_OK;
199
200     if (query && *query)
201     {
202         result = ExtractFiltersFromQuery(query, filterOne, filterTwo);
203     }
204
205     return result;
206 }
207
208 OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
209                     OCRepPayload** payload)
210 {
211     OCRepPayload *tempPayload = OCRepPayloadCreate();
212
213     if (!resourcePtr)
214     {
215         OCRepPayloadDestroy(tempPayload);
216         return OC_STACK_INVALID_PARAM;
217     }
218
219     if(!tempPayload)
220     {
221         return OC_STACK_NO_MEMORY;
222     }
223
224     OCRepPayloadSetUri(tempPayload, resourcePtr->uri);
225
226     OCResourceType *resType = resourcePtr->rsrcType;
227     while(resType)
228     {
229         OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename);
230         resType = resType->next;
231     }
232
233     OCResourceInterface *resInterface = resourcePtr->rsrcInterface;
234     while(resInterface)
235     {
236         OCRepPayloadAddInterface(tempPayload, resInterface->name);
237         resInterface = resInterface->next;
238     }
239
240     OCAttribute *resAttrib = resourcePtr->rsrcAttributes;
241     while(resAttrib)
242     {
243         OCRepPayloadSetPropString(tempPayload, resAttrib->attrName,
244                                 resAttrib->attrValue);
245         resAttrib = resAttrib->next;
246     }
247
248     if(!*payload)
249     {
250         *payload = tempPayload;
251     }
252     else
253     {
254         OCRepPayloadAppend(*payload, tempPayload);
255     }
256
257     return OC_STACK_OK;
258 }
259
260 OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
261                         OCDiscoveryPayload *payload, OCDevAddr *devAddr)
262 {
263     if (!resourcePtr || !payload)
264     {
265         return OC_STACK_INVALID_PARAM;
266     }
267     uint16_t port = 0;
268     if (resourcePtr->resourceProperties & OC_SECURE)
269     {
270        if (GetSecurePortInfo(devAddr, &port) != OC_STACK_OK)
271        {
272            port = 0;
273        }
274     }
275
276     OCDiscoveryPayloadAddResource(payload, resourcePtr, port);
277     return OC_STACK_OK;
278 }
279
280
281 uint8_t IsCollectionResource (OCResource *resource)
282 {
283     if(!resource)
284     {
285         return 0;
286     }
287
288     for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
289     {
290         if (resource->rsrcResources[i])
291         {
292             return 1;
293         }
294     }
295     return 0;
296 }
297
298 OCResource *FindResourceByUri(const char* resourceUri)
299 {
300     if(!resourceUri)
301     {
302         return NULL;
303     }
304
305     OCResource * pointer = headResource;
306     while (pointer)
307     {
308         if (strcmp(resourceUri, pointer->uri) == 0)
309         {
310             return pointer;
311         }
312         pointer = pointer->next;
313     }
314     OC_LOG_V(INFO, TAG, "Resource %s not found", resourceUri);
315     return NULL;
316 }
317
318
319 OCStackResult DetermineResourceHandling (const OCServerRequest *request,
320                                          ResourceHandling *handling,
321                                          OCResource **resource)
322 {
323     if(!request || !handling || !resource)
324     {
325         return OC_STACK_INVALID_PARAM;
326     }
327
328     OC_LOG_V(INFO, TAG, "DetermineResourceHandling for %s", request->resourceUrl);
329
330     // Check if virtual resource
331     if (GetTypeOfVirtualURI(request->resourceUrl) != OC_UNKNOWN_URI)
332     {
333         OC_LOG_V (INFO, TAG, "%s is virtual", request->resourceUrl);
334         *handling = OC_RESOURCE_VIRTUAL;
335         *resource = headResource;
336         return OC_STACK_OK;
337     }
338     if (strlen((const char*)(request->resourceUrl)) == 0)
339     {
340         // Resource URL not specified
341         *handling = OC_RESOURCE_NOT_SPECIFIED;
342         return OC_STACK_NO_RESOURCE;
343     }
344     else
345     {
346         OCResource *resourcePtr = NULL;
347         resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
348         *resource = resourcePtr;
349         if (!resourcePtr)
350         {
351             if(defaultDeviceHandler)
352             {
353                 *handling = OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER;
354                 return OC_STACK_OK;
355             }
356
357             // Resource does not exist
358             // and default device handler does not exist
359             *handling = OC_RESOURCE_NOT_SPECIFIED;
360             return OC_STACK_NO_RESOURCE;
361         }
362
363         if (IsCollectionResource (resourcePtr))
364         {
365             // Collection resource
366             if (resourcePtr->entityHandler != defaultResourceEHandler)
367             {
368                 *handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
369                 return OC_STACK_OK;
370             }
371             else
372             {
373                 *handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
374                 return OC_STACK_OK;
375             }
376         }
377         else
378         {
379             // Resource not a collection
380             if (resourcePtr->entityHandler != defaultResourceEHandler)
381             {
382                 *handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
383                 return OC_STACK_OK;
384             }
385             else
386             {
387                 *handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
388                 return OC_STACK_OK;
389             }
390         }
391     }
392 }
393
394 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
395 {
396     OCStackResult result;
397
398     switch (ehResult)
399     {
400         case OC_EH_OK:
401             result = OC_STACK_OK;
402             break;
403         case OC_EH_SLOW:
404             result = OC_STACK_SLOW_RESOURCE;
405             break;
406         case OC_EH_ERROR:
407             result = OC_STACK_ERROR;
408             break;
409         case OC_EH_FORBIDDEN:
410             result = OC_STACK_RESOURCE_ERROR;
411             break;
412         case OC_EH_RESOURCE_CREATED:
413             result = OC_STACK_RESOURCE_CREATED;
414             break;
415         case OC_EH_RESOURCE_DELETED:
416             result = OC_STACK_RESOURCE_DELETED;
417             break;
418         case OC_EH_RESOURCE_NOT_FOUND:
419             result = OC_STACK_NO_RESOURCE;
420             break;
421         default:
422             result = OC_STACK_ERROR;
423     }
424
425     return result;
426 }
427
428 static bool resourceMatchesRTFilter(OCResource *resource, char *resourceTypeFilter)
429 {
430     if (!resource)
431     {
432         return false;
433     }
434
435     // Null or empty is analogous to no filter.
436     if (resourceTypeFilter == NULL || *resourceTypeFilter == 0)
437     {
438         return true;
439     }
440
441     OCResourceType *resourceTypePtr = resource->rsrcType;
442
443     while (resourceTypePtr)
444     {
445         if (strcmp (resourceTypePtr->resourcetypename, resourceTypeFilter) == 0)
446         {
447             return true;
448         }
449         resourceTypePtr = resourceTypePtr->next;
450     }
451
452     OC_LOG_V(INFO, TAG, PCF("%s does not contain rt=%s."), resource->uri, resourceTypeFilter);
453     return false;
454 }
455
456 static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter)
457 {
458     if (!resource)
459     {
460         return false;
461     }
462
463     // Null or empty is analogous to no filter.
464     if (interfaceFilter == NULL || *interfaceFilter == 0)
465     {
466         return true;
467     }
468
469     OCResourceInterface *interfacePtr = resource->rsrcInterface;
470
471     while (interfacePtr)
472     {
473         if (strcmp (interfacePtr->name, interfaceFilter) == 0)
474         {
475             return true;
476         }
477         interfacePtr = interfacePtr->next;
478     }
479
480     OC_LOG_V(INFO, TAG, PCF("%s does not contain if=%s."), resource->uri, interfaceFilter);
481     return false;
482 }
483
484 /*
485  * If the filters are null, they will be assumed to NOT be present
486  * and the resource will not be matched against them.
487  * Function will return true if all non null AND non empty filters passed in find a match.
488  */
489 static bool includeThisResourceInResponse(OCResource *resource,
490                                                  char *interfaceFilter,
491                                                  char *resourceTypeFilter)
492 {
493     if (!resource)
494     {
495         OC_LOG(ERROR, TAG, PCF("Invalid resource"));
496         return false;
497     }
498
499     if ( resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
500     {
501         /*
502          * At least one valid filter should be available to
503          * include the resource in discovery response
504          */
505         if (!((interfaceFilter && *interfaceFilter ) ||
506               (resourceTypeFilter && *resourceTypeFilter)))
507         {
508             OC_LOG_V(INFO, TAG, PCF("%s no query string for EXPLICIT_DISCOVERABLE \
509                 resource"), resource->uri);
510             return false;
511         }
512     }
513     else if ( !(resource->resourceProperties & OC_ACTIVE) ||
514          !(resource->resourceProperties & OC_DISCOVERABLE))
515     {
516         OC_LOG_V(INFO, TAG, PCF("%s not ACTIVE or DISCOVERABLE"), resource->uri);
517         return false;
518     }
519
520     return resourceMatchesIFFilter(resource, interfaceFilter) &&
521            resourceMatchesRTFilter(resource, resourceTypeFilter);
522
523 }
524
525 OCStackResult SendNonPersistantDiscoveryResponse(OCServerRequest *request, OCResource *resource,
526                                 OCPayload *discoveryPayload, OCEntityHandlerResult ehResult)
527 {
528     OCEntityHandlerResponse response = {0};
529
530     response.ehResult = ehResult;
531     response.payload = discoveryPayload;
532     response.persistentBufferFlag = 0;
533     response.requestHandle = (OCRequestHandle) request;
534     response.resourceHandle = (OCResourceHandle) resource;
535
536     return OCDoResponse(&response);
537 }
538
539 #ifdef WITH_RD
540 static OCStackResult checkResourceExistsAtRD(const char *interfaceType, const char *resourceType, OCRepPayload **repPayload)
541 {
542     char *uri = NULL;
543     char *rt = NULL;
544     char *itf = NULL;
545
546     if (OCRDCheckPublishedResource(interfaceType, resourceType, &uri, &rt, &itf) == OC_STACK_OK)
547     {
548         if (!uri || !rt || !itf)
549         {
550             OC_LOG_V(ERROR, TAG, "Failed allocating memory.");
551             // if any of the parameter has memory allocated free each one of them.
552             OICFree(uri);
553             OICFree(rt);
554             OICFree(itf);
555             return OC_STACK_NO_MEMORY;
556         }
557
558         OCRepPayload *rdResource = OICCalloc(1, sizeof(OCRepPayload));
559         if (!rdResource)
560         {
561             OC_LOG_V(ERROR, TAG, "Failed allocating memory.");
562             OICFree(uri);
563             OICFree(rt);
564             OICFree(itf);
565             return OC_STACK_NO_MEMORY;
566         }
567
568         rdResource->uri = uri;
569
570         rdResource->types = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
571         if(!rdResource->types)
572         {
573             OC_LOG_V(ERROR, TAG, "Failed allocating memory.");
574             OICFree(uri);
575             OICFree(rt);
576             OICFree(itf);
577             OICFree(rdResource);
578             return OC_STACK_NO_MEMORY;
579         }
580         rdResource->types->value = rt;
581
582         rdResource->interfaces = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
583         if(!rdResource->interfaces)
584         {
585             OC_LOG_V(ERROR, TAG, "Failed allocating memory.");
586             OICFree(uri);
587             OICFree(rt);
588             OICFree(itf);
589             OICFree(rdResource);
590             return OC_STACK_NO_MEMORY;
591         }
592         rdResource->interfaces->value = itf;
593
594         *repPayload = rdResource;
595
596         return OC_STACK_OK;
597     }
598     else
599     {
600         OC_LOG_V(ERROR, TAG, "The resource type or interface type doe not exist \
601                              on the resource directory");
602     }
603     return OC_STACK_ERROR;
604 }
605 #endif
606
607 static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource)
608 {
609     if (!request || !resource)
610     {
611         return OC_STACK_INVALID_PARAM;
612     }
613
614     OCStackResult discoveryResult = OC_STACK_ERROR;
615
616     bool bMulticast    = false;     // Was the discovery request a multicast request?
617     OCPayload* payload = NULL;
618
619     OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
620
621     OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
622
623     // Step 1: Generate the response to discovery request
624     if (virtualUriInRequest == OC_WELL_KNOWN_URI)
625     {
626         char *filterOne = NULL;
627         char *filterTwo = NULL;
628
629         discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
630                 &filterOne, &filterTwo);
631
632         if (discoveryResult == OC_STACK_OK)
633         {
634             payload = (OCPayload*)OCDiscoveryPayloadCreate();
635
636             if(payload)
637             {
638                 for(;resource && discoveryResult == OC_STACK_OK; resource = resource->next)
639                 {
640                     bool foundResourceAtRD = false;
641 #ifdef WITH_RD
642                     if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0)
643                     {
644                         OCRepPayload *repPayload = NULL;
645                         discoveryResult = checkResourceExistsAtRD(filterOne, filterTwo, &repPayload);
646                         if (discoveryResult != OC_STACK_OK)
647                         {
648                              break;
649                         }
650                         discoveryResult = BuildVirtualResourceResponse((OCResource *)repPayload,
651                                     (OCDiscoveryPayload*)payload,
652                                     &request->devAddr);
653                         foundResourceAtRD = true;
654                     }
655 #endif
656                     if(!foundResourceAtRD && includeThisResourceInResponse(resource, filterOne, filterTwo))
657                     {
658                         discoveryResult = BuildVirtualResourceResponse(resource,
659                                 (OCDiscoveryPayload*)payload,
660                                 &request->devAddr);
661                     }
662                 }
663                 // Set discoveryResult appropriately if no 'valid' resources are available.
664                 if (((OCDiscoveryPayload*)payload)->resources == NULL)
665                 {
666                     discoveryResult = OC_STACK_NO_RESOURCE;
667                 }
668             }
669             else
670             {
671                 discoveryResult = OC_STACK_NO_MEMORY;
672             }
673         }
674         else
675         {
676             OC_LOG_V(ERROR, TAG, "Error (%d) parsing query.", discoveryResult);
677         }
678     }
679     else if (virtualUriInRequest == OC_DEVICE_URI)
680     {
681         payload = (OCPayload*)OCDevicePayloadCreate(OC_RSRVD_DEVICE_URI,
682                 OCGetServerInstanceID(), savedDeviceInfo.deviceName,
683                 OC_SPEC_VERSION, OC_DATA_MODEL_VERSION);
684         if (!payload)
685         {
686             discoveryResult = OC_STACK_NO_MEMORY;
687         }
688         else
689         {
690             discoveryResult = OC_STACK_OK;
691         }
692     }
693     else if (virtualUriInRequest == OC_PLATFORM_URI)
694     {
695         payload = (OCPayload*)OCPlatformPayloadCreate(
696                 OC_RSRVD_PLATFORM_URI,
697                 &savedPlatformInfo);
698         if (!payload)
699         {
700             discoveryResult = OC_STACK_NO_MEMORY;
701         }
702         else
703         {
704             discoveryResult = OC_STACK_OK;
705         }
706     }
707
708     /**
709      * Step 2: Send the discovery response
710      *
711      * Iotivity should respond to discovery requests in below manner:
712      * 1)If query filter matching fails and discovery request is multicast,
713      *   it should NOT send any response.
714      * 2)If query filter matching fails and discovery request is unicast,
715      *   it should send an error(RESOURCE_NOT_FOUND - 404) response.
716      * 3)If Server does not have any 'DISCOVERABLE' resources and discovery
717      *   request is multicast, it should NOT send any response.
718      * 4)If Server does not have any 'DISCOVERABLE' resources and discovery
719      *   request is unicast, it should send an error(RESOURCE_NOT_FOUND - 404) response.
720      */
721
722     #ifdef WITH_PRESENCE
723     if ((virtualUriInRequest == OC_PRESENCE) &&
724         (resource->resourceProperties & OC_ACTIVE))
725     {
726         // Presence uses observer notification api to respond via SendPresenceNotification.
727         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
728     }
729     else
730     #endif
731     {
732         if(discoveryResult == OC_STACK_OK)
733         {
734             SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
735         }
736         else if(bMulticast == false)
737         {
738             OC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d)  \
739                 discovery request", discoveryResult, virtualUriInRequest);
740             SendNonPersistantDiscoveryResponse(request, resource, NULL,
741                 (discoveryResult == OC_STACK_NO_RESOURCE) ? OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
742         }
743         else
744         {
745             // Ignoring the discovery request as per RFC 7252, Section #8.2
746             OC_LOG_V(INFO, TAG, "Silently ignoring the request since device does not have \
747                 any useful data to send");
748         }
749     }
750
751     OCPayloadDestroy(payload);
752
753     return OC_STACK_OK;
754 }
755
756 static OCStackResult
757 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
758 {
759     if(!request)
760     {
761         return OC_STACK_INVALID_PARAM;
762     }
763
764     OCStackResult result = OC_STACK_OK;
765     OCEntityHandlerResult ehResult = OC_EH_ERROR;
766     OCEntityHandlerRequest ehRequest = {0};
767
768     OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithDefaultDeviceEntityHandler"));
769     result = FormOCEntityHandlerRequest(&ehRequest,
770                                         (OCRequestHandle) request,
771                                         request->method,
772                                         &request->devAddr,
773                                         (OCResourceHandle) NULL, request->query,
774                                         request->payload,
775                                         request->payloadSize,
776                                         request->numRcvdVendorSpecificHeaderOptions,
777                                         request->rcvdVendorSpecificHeaderOptions,
778                                         (OCObserveAction)request->observationOption,
779                                         (OCObservationId)0);
780     VERIFY_SUCCESS(result, OC_STACK_OK);
781
782     // At this point we know for sure that defaultDeviceHandler exists
783     ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
784                                   (char*) request->resourceUrl, defaultDeviceHandlerCallbackParameter);
785     if(ehResult == OC_EH_SLOW)
786     {
787         OC_LOG(INFO, TAG, PCF("This is a slow resource"));
788         request->slowFlag = 1;
789     }
790     else if(ehResult == OC_EH_ERROR)
791     {
792         FindAndDeleteServerRequest(request);
793     }
794     result = EntityHandlerCodeToOCStackCode(ehResult);
795 exit:
796     OCPayloadDestroy(ehRequest.payload);
797     return result;
798 }
799
800 static OCStackResult
801 HandleResourceWithEntityHandler (OCServerRequest *request,
802                                  OCResource *resource,
803                                  uint8_t collectionResource)
804 {
805     if(!request || ! resource)
806     {
807         return OC_STACK_INVALID_PARAM;
808     }
809
810     OCStackResult result = OC_STACK_ERROR;
811     OCEntityHandlerResult ehResult = OC_EH_ERROR;
812     OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
813     ResourceObserver *resObs = NULL;
814
815     OCEntityHandlerRequest ehRequest = {0};
816
817     OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithEntityHandler"));
818
819     result = FormOCEntityHandlerRequest(&ehRequest,
820                                         (OCRequestHandle)request,
821                                         request->method,
822                                         &request->devAddr,
823                                         (OCResourceHandle)resource,
824                                         request->query,
825                                         request->payload,
826                                         request->payloadSize,
827                                         request->numRcvdVendorSpecificHeaderOptions,
828                                         request->rcvdVendorSpecificHeaderOptions,
829                                         (OCObserveAction)request->observationOption,
830                                         0);
831     VERIFY_SUCCESS(result, OC_STACK_OK);
832
833     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
834     {
835         OC_LOG(INFO, TAG, PCF("No observation requested"));
836         ehFlag = OC_REQUEST_FLAG;
837     }
838     else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER && !collectionResource)
839     {
840         OC_LOG(INFO, TAG, PCF("Observation registration requested"));
841
842         result = GenerateObserverId(&ehRequest.obsInfo.obsId);
843         VERIFY_SUCCESS(result, OC_STACK_OK);
844
845         result = AddObserver ((const char*)(request->resourceUrl),
846                 (const char *)(request->query),
847                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
848                 resource, request->qos,
849                 &request->devAddr);
850
851         if(result == OC_STACK_OK)
852         {
853             OC_LOG(INFO, TAG, PCF("Added observer successfully"));
854             request->observeResult = OC_STACK_OK;
855             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
856         }
857         else
858         {
859             result = OC_STACK_OK;
860
861             // The error in observeResult for the request will be used when responding to this
862             // request by omitting the observation option/sequence number.
863             request->observeResult = OC_STACK_ERROR;
864             OC_LOG(ERROR, TAG, PCF("Observer Addition failed"));
865             ehFlag = OC_REQUEST_FLAG;
866         }
867
868     }
869     else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER &&
870             !collectionResource)
871     {
872         OC_LOG(INFO, TAG, PCF("Deregistering observation requested"));
873
874         resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
875
876         if (NULL == resObs)
877         {
878             // Stack does not contain this observation request
879             // Either token is incorrect or observation list is corrupted
880             result = OC_STACK_ERROR;
881             goto exit;
882         }
883         ehRequest.obsInfo.obsId = resObs->observeId;
884         ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
885
886         result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
887
888         if(result == OC_STACK_OK)
889         {
890             OC_LOG(INFO, TAG, PCF("Removed observer successfully"));
891             request->observeResult = OC_STACK_OK;
892         }
893         else
894         {
895             result = OC_STACK_OK;
896             request->observeResult = OC_STACK_ERROR;
897             OC_LOG(ERROR, TAG, PCF("Observer Removal failed"));
898         }
899     }
900     else
901     {
902         result = OC_STACK_ERROR;
903         goto exit;
904     }
905
906     ehResult = resource->entityHandler(ehFlag, &ehRequest, resource->entityHandlerCallbackParam);
907     if(ehResult == OC_EH_SLOW)
908     {
909         OC_LOG(INFO, TAG, PCF("This is a slow resource"));
910         request->slowFlag = 1;
911     }
912     else if(ehResult == OC_EH_ERROR)
913     {
914         FindAndDeleteServerRequest(request);
915     }
916     result = EntityHandlerCodeToOCStackCode(ehResult);
917 exit:
918     OCPayloadDestroy(ehRequest.payload);
919     return result;
920 }
921
922 static OCStackResult
923 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
924                                               OCResource *resource)
925 {
926     if(!request || !resource)
927     {
928         return OC_STACK_INVALID_PARAM;
929     }
930
931     OCStackResult result = OC_STACK_ERROR;
932     OCEntityHandlerRequest ehRequest = {0};
933
934     result = FormOCEntityHandlerRequest(&ehRequest,
935                                         (OCRequestHandle)request,
936                                         request->method,
937                                         &request->devAddr,
938                                         (OCResourceHandle)resource,
939                                         request->query,
940                                         request->payload,
941                                         request->payloadSize,
942                                         request->numRcvdVendorSpecificHeaderOptions,
943                                         request->rcvdVendorSpecificHeaderOptions,
944                                         (OCObserveAction)request->observationOption,
945                                         (OCObservationId)0);
946     if(result == OC_STACK_OK)
947     {
948         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
949     }
950
951     OCPayloadDestroy(ehRequest.payload);
952     return result;
953 }
954
955 OCStackResult
956 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
957 {
958     OCStackResult ret = OC_STACK_OK;
959
960     switch (resHandling)
961     {
962         case OC_RESOURCE_VIRTUAL:
963         {
964             ret = HandleVirtualResource (request, resource);
965             break;
966         }
967         case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
968         {
969             ret = HandleDefaultDeviceEntityHandler(request);
970             break;
971         }
972         case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
973         {
974             OC_LOG(INFO, TAG, PCF("OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER"));
975             return OC_STACK_ERROR;
976         }
977         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
978         {
979             ret = HandleResourceWithEntityHandler (request, resource, 0);
980             break;
981         }
982         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
983         {
984             ret = HandleResourceWithEntityHandler (request, resource, 1);
985             break;
986         }
987         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
988         {
989             ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
990             break;
991         }
992         case OC_RESOURCE_NOT_SPECIFIED:
993         {
994             ret = OC_STACK_NO_RESOURCE;
995             break;
996         }
997         default:
998         {
999             OC_LOG(INFO, TAG, PCF("Invalid Resource Determination"));
1000             return OC_STACK_ERROR;
1001         }
1002     }
1003     return ret;
1004 }
1005
1006 void DeletePlatformInfo()
1007 {
1008     OC_LOG(INFO, TAG, PCF("Deleting platform info."));
1009
1010     OICFree(savedPlatformInfo.platformID);
1011     savedPlatformInfo.platformID = NULL;
1012
1013     OICFree(savedPlatformInfo.manufacturerName);
1014     savedPlatformInfo.manufacturerName = NULL;
1015
1016     OICFree(savedPlatformInfo.manufacturerUrl);
1017     savedPlatformInfo.manufacturerUrl = NULL;
1018
1019     OICFree(savedPlatformInfo.modelNumber);
1020     savedPlatformInfo.modelNumber = NULL;
1021
1022     OICFree(savedPlatformInfo.dateOfManufacture);
1023     savedPlatformInfo.dateOfManufacture = NULL;
1024
1025     OICFree(savedPlatformInfo.platformVersion);
1026     savedPlatformInfo.platformVersion = NULL;
1027
1028     OICFree(savedPlatformInfo.operatingSystemVersion);
1029     savedPlatformInfo.operatingSystemVersion = NULL;
1030
1031     OICFree(savedPlatformInfo.hardwareVersion);
1032     savedPlatformInfo.hardwareVersion = NULL;
1033
1034     OICFree(savedPlatformInfo.firmwareVersion);
1035     savedPlatformInfo.firmwareVersion = NULL;
1036
1037     OICFree(savedPlatformInfo.supportUrl);
1038     savedPlatformInfo.supportUrl = NULL;
1039
1040     OICFree(savedPlatformInfo.systemTime);
1041     savedPlatformInfo.systemTime = NULL;
1042 }
1043
1044 static OCStackResult DeepCopyPlatFormInfo(OCPlatformInfo info)
1045 {
1046     savedPlatformInfo.platformID = OICStrdup(info.platformID);
1047     savedPlatformInfo.manufacturerName = OICStrdup(info.manufacturerName);
1048     savedPlatformInfo.manufacturerUrl = OICStrdup(info.manufacturerUrl);
1049     savedPlatformInfo.modelNumber = OICStrdup(info.modelNumber);
1050     savedPlatformInfo.dateOfManufacture = OICStrdup(info.dateOfManufacture);
1051     savedPlatformInfo.platformVersion = OICStrdup(info.platformVersion);
1052     savedPlatformInfo.operatingSystemVersion = OICStrdup(info.operatingSystemVersion);
1053     savedPlatformInfo.hardwareVersion = OICStrdup(info.hardwareVersion);
1054     savedPlatformInfo.firmwareVersion = OICStrdup(info.firmwareVersion);
1055     savedPlatformInfo.supportUrl = OICStrdup(info.supportUrl);
1056     savedPlatformInfo.systemTime = OICStrdup(info.systemTime);
1057
1058     if ((!savedPlatformInfo.platformID && info.platformID)||
1059         (!savedPlatformInfo.manufacturerName && info.manufacturerName)||
1060         (!savedPlatformInfo.manufacturerUrl && info.manufacturerUrl)||
1061         (!savedPlatformInfo.modelNumber && info.modelNumber)||
1062         (!savedPlatformInfo.dateOfManufacture && info.dateOfManufacture)||
1063         (!savedPlatformInfo.platformVersion && info.platformVersion)||
1064         (!savedPlatformInfo.operatingSystemVersion && info.operatingSystemVersion)||
1065         (!savedPlatformInfo.hardwareVersion && info.hardwareVersion)||
1066         (!savedPlatformInfo.firmwareVersion && info.firmwareVersion)||
1067         (!savedPlatformInfo.supportUrl && info.supportUrl)||
1068         (!savedPlatformInfo.systemTime && info.systemTime))
1069     {
1070         DeletePlatformInfo();
1071         return OC_STACK_INVALID_PARAM;
1072     }
1073
1074     return OC_STACK_OK;
1075
1076 }
1077
1078 OCStackResult SavePlatformInfo(OCPlatformInfo info)
1079 {
1080     DeletePlatformInfo();
1081
1082     OCStackResult res = DeepCopyPlatFormInfo(info);
1083
1084     if (res != OC_STACK_OK)
1085     {
1086         OC_LOG_V(ERROR, TAG, PCF("Failed to save platform info. errno(%d)"), res);
1087     }
1088     else
1089     {
1090         OC_LOG(ERROR, TAG, PCF("Platform info saved."));
1091     }
1092
1093     return res;
1094 }
1095
1096 void DeleteDeviceInfo()
1097 {
1098     OC_LOG(INFO, TAG, PCF("Deleting device info."));
1099
1100     OICFree(savedDeviceInfo.deviceName);
1101     savedDeviceInfo.deviceName = NULL;
1102 }
1103
1104 static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
1105 {
1106     savedDeviceInfo.deviceName = OICStrdup(info.deviceName);
1107
1108     if(!savedDeviceInfo.deviceName && info.deviceName)
1109     {
1110         DeleteDeviceInfo();
1111         return OC_STACK_NO_MEMORY;
1112     }
1113
1114     return OC_STACK_OK;
1115 }
1116
1117 OCStackResult SaveDeviceInfo(OCDeviceInfo info)
1118 {
1119     OCStackResult res = OC_STACK_OK;
1120
1121     DeleteDeviceInfo();
1122
1123     res = DeepCopyDeviceInfo(info);
1124
1125     VERIFY_SUCCESS(res, OC_STACK_OK);
1126
1127     if(OCGetServerInstanceID() == NULL)
1128     {
1129         OC_LOG(INFO, TAG, PCF("Device ID generation failed"));
1130         res =  OC_STACK_ERROR;
1131         goto exit;
1132     }
1133
1134     OC_LOG(INFO, TAG, PCF("Device initialized successfully."));
1135     return OC_STACK_OK;
1136
1137     exit:
1138         DeleteDeviceInfo();
1139         return res;
1140
1141 }