[IOT-1608] Support PUT,POST,DELETE method type for /oic/ping
[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 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE
30 #endif
31
32 #include "iotivity_config.h"
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39
40 #include "ocresource.h"
41 #include "ocresourcehandler.h"
42 #include "ocobserve.h"
43 #include "occollection.h"
44 #include "oic_malloc.h"
45 #include "oic_string.h"
46 #include "logger.h"
47 #include "cJSON.h"
48 #include "ocpayload.h"
49 #include "secureresourcemanager.h"
50 #include "cacommon.h"
51 #include "cainterface.h"
52 #include "ocpayload.h"
53 #include "platform_features.h"
54 #include "payload_logging.h"
55 #ifdef ROUTING_GATEWAY
56 #include "routingmanager.h"
57 #endif
58
59 #ifdef RD_SERVER
60 #include "rd_database.h"
61 #endif
62
63 /// Module Name
64 #define TAG "OIC_RI_RESOURCE"
65
66 #define VERIFY_SUCCESS(op) { if (op != (OC_STACK_OK)) \
67             {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
68
69 extern OCResource *headResource;
70
71 /**
72  * Prepares a Payload for response.
73  */
74 static OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
75                                                   OCDiscoveryPayload* payload,
76                                                   OCDevAddr *endpoint);
77
78 //-----------------------------------------------------------------------------
79 // Default resource entity handler function
80 //-----------------------------------------------------------------------------
81 OCEntityHandlerResult defaultResourceEHandler(OCEntityHandlerFlag flag,
82         OCEntityHandlerRequest * request, void* callbackParam)
83 {
84     //TODO ("Implement me!!!!");
85     // TODO:  remove silence unused param warnings
86     (void) flag;
87     (void) request;
88     (void) callbackParam;
89     return  OC_EH_OK; // Making sure that the Default EH and the Vendor EH have matching signatures
90 }
91
92 /* This method will retrieve the port at which the secure resource is hosted */
93 static OCStackResult GetSecurePortInfo(OCDevAddr *endpoint, uint16_t *port)
94 {
95     uint16_t p = 0;
96
97     if (endpoint->adapter == OC_ADAPTER_IP)
98     {
99         if (endpoint->flags & OC_IP_USE_V6)
100         {
101             p = caglobals.ip.u6s.port;
102         }
103         else if (endpoint->flags & OC_IP_USE_V4)
104         {
105             p = caglobals.ip.u4s.port;
106         }
107     }
108
109     *port = p;
110     return OC_STACK_OK;
111 }
112
113 #ifdef TCP_ADAPTER
114 /* This method will retrieve the tcp port */
115 static OCStackResult GetTCPPortInfo(OCDevAddr *endpoint, uint16_t *port, bool secured)
116 {
117     uint16_t p = 0;
118
119     if (endpoint->adapter == OC_ADAPTER_IP)
120     {
121         if (endpoint->flags & OC_IP_USE_V4)
122         {
123             p = secured ? caglobals.tcp.ipv4s.port : caglobals.tcp.ipv4.port;
124         }
125         else if (endpoint->flags & OC_IP_USE_V6)
126         {
127             p = secured ? caglobals.tcp.ipv6s.port : caglobals.tcp.ipv6.port;
128         }
129     }
130
131     *port = p;
132     return OC_STACK_OK;
133 }
134 #endif
135
136 /*
137  * Function will extract 0, 1 or 2 filters from query.
138  * More than 2 filters or unsupported filters will result in error.
139  * If both filters are of the same supported type, the 2nd one will be picked.
140  * Resource and device filters in the SAME query are NOT validated
141  * and resources will likely not clear filters.
142  */
143 static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char **filterTwo)
144 {
145     char *key = NULL;
146     char *value = NULL;
147     char *queryDup = NULL;
148     char *restOfQuery = NULL;
149     char *keyValuePair = NULL;
150     int numKeyValuePairsParsed = 0;
151
152     *filterOne = NULL;
153     *filterTwo = NULL;
154
155     queryDup = OICStrdup(query);
156     if (NULL == queryDup)
157     {
158         OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
159         return OC_STACK_NO_MEMORY;
160     }
161
162     OIC_LOG_V(INFO, TAG, "Extracting params from %s", queryDup);
163
164     OCStackResult eCode = OC_STACK_INVALID_QUERY;
165     if (strnlen(queryDup, MAX_QUERY_LENGTH) >= MAX_QUERY_LENGTH)
166     {
167         OIC_LOG(ERROR, TAG, "Query exceeds maximum length.");
168         goto exit;
169     }
170
171     keyValuePair = strtok_r (queryDup, OC_QUERY_SEPARATOR, &restOfQuery);
172
173     while(keyValuePair)
174     {
175         if (numKeyValuePairsParsed >= 2)
176         {
177             OIC_LOG(ERROR, TAG, "More than 2 queries params in URI.");
178             goto exit;
179         }
180
181         key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
182
183         if (!key || !value)
184         {
185             goto exit;
186         }
187         else if (strncasecmp(key, OC_RSRVD_INTERFACE, sizeof(OC_RSRVD_INTERFACE) - 1) == 0)
188         {
189             *filterOne = value;     // if
190         }
191         else if (strncasecmp(key, OC_RSRVD_RESOURCE_TYPE, sizeof(OC_RSRVD_INTERFACE) - 1) == 0)
192         {
193             *filterTwo = value;     // rt
194         }
195         else
196         {
197             OIC_LOG_V(ERROR, TAG, "Unsupported query key: %s", key);
198             goto exit;
199         }
200         ++numKeyValuePairsParsed;
201
202         keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
203     }
204
205     if (*filterOne)
206     {
207         *filterOne = OICStrdup(*filterOne);
208         if (NULL == *filterOne)
209         {
210             OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
211             eCode = OC_STACK_NO_MEMORY;
212             goto exit;
213         }
214     }
215
216     if (*filterTwo)
217     {
218         *filterTwo = OICStrdup(*filterTwo);
219         if (NULL == *filterTwo)
220         {
221             OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
222             OICFree(*filterOne);
223             eCode = OC_STACK_NO_MEMORY;
224             goto exit;
225         }
226     }
227
228     OICFree(queryDup);
229     OIC_LOG_V(INFO, TAG, "Extracted params if: %s and rt: %s.", *filterOne, *filterTwo);
230     return OC_STACK_OK;
231
232 exit:
233     *filterOne = NULL;
234     *filterTwo = NULL;
235     OICFree(queryDup);
236     return eCode;
237 }
238
239 static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
240 {
241     if (strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_URI) == 0)
242     {
243         return OC_WELL_KNOWN_URI;
244     }
245     else if (strcmp(uriInRequest, OC_RSRVD_DEVICE_URI) == 0)
246     {
247         return OC_DEVICE_URI;
248     }
249     else if (strcmp(uriInRequest, OC_RSRVD_PLATFORM_URI) == 0)
250     {
251         return OC_PLATFORM_URI;
252     }
253     else if (strcmp(uriInRequest, OC_RSRVD_RESOURCE_TYPES_URI) == 0)
254     {
255         return OC_RESOURCE_TYPES_URI;
256     }
257 #ifdef ROUTING_GATEWAY
258     else if (0 == strcmp(uriInRequest, OC_RSRVD_GATEWAY_URI))
259     {
260         return OC_GATEWAY_URI;
261     }
262 #endif
263 #ifdef WITH_PRESENCE
264     else if (strcmp(uriInRequest, OC_RSRVD_PRESENCE_URI) == 0)
265     {
266         return OC_PRESENCE;
267     }
268 #endif //WITH_PRESENCE
269
270 #ifdef MQ_BROKER
271     else if (0 == strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_MQ_URI))
272     {
273         return OC_MQ_BROKER_URI;
274     }
275 #endif //MQ_BROKER
276
277 #ifdef TCP_ADAPTER
278     else if (strcmp(uriInRequest, OC_RSRVD_KEEPALIVE_URI) == 0)
279     {
280         return OC_KEEPALIVE_RESOURCE_URI;
281     }
282 #endif
283
284     return OC_UNKNOWN_URI;
285 }
286
287 static OCStackResult getQueryParamsForFiltering (OCVirtualResources uri, char *query,
288                                             char **filterOne, char **filterTwo)
289 {
290     if(!filterOne || !filterTwo)
291     {
292         return OC_STACK_INVALID_PARAM;
293     }
294
295     *filterOne = NULL;
296     *filterTwo = NULL;
297
298     #ifdef WITH_PRESENCE
299     if (uri == OC_PRESENCE)
300     {
301         //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
302         OIC_LOG(INFO, TAG, "OC_PRESENCE Request for virtual resource.");
303         return OC_STACK_OK;
304     }
305     #endif
306
307     OCStackResult result = OC_STACK_OK;
308
309     if (query && *query)
310     {
311         result = ExtractFiltersFromQuery(query, filterOne, filterTwo);
312     }
313
314     return result;
315 }
316
317 bool appendOCStringLL(OCRepPayload *device, OCStringLL *dmv)
318 {
319     int size = 0;
320     for (OCStringLL *ll = dmv; ll; ll = ll->next, size++);
321     size_t dim[MAX_REP_ARRAY_DEPTH] = {size, 0, 0};
322     char **dt = (char **)OICMalloc(sizeof(char *) * size);
323     int i = 0;
324     VERIFY_PARAM_NON_NULL(TAG, dt, "Data Model Version allocation failed.");
325     for (OCStringLL *ll = dmv; ll; ll = ll->next, i++)
326     {
327         dt[i] = OICStrdup(ll->value);
328         VERIFY_PARAM_NON_NULL(TAG, dt[i], "Data Model Version adding failed.");
329     }
330     if (!OCRepPayloadSetStringArrayAsOwner(device, OC_RSRVD_DATA_MODEL_VERSION, dt, dim))
331     {
332         goto exit;
333     }
334     return true;
335
336 exit:
337     for (int i = 0; i < size; i++)
338     {
339         OICFree(dt[i]);
340     }
341     OICFree(dt);
342     return false;
343 }
344
345 OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
346                     OCRepPayload** payload, OCDevAddr *devAddr, bool addDeviceId)
347 {
348     OCRepPayload *tempPayload = OCRepPayloadCreate();
349
350     if (!resourcePtr)
351     {
352         OCRepPayloadDestroy(tempPayload);
353         return OC_STACK_INVALID_PARAM;
354     }
355
356     if(!tempPayload)
357     {
358         return OC_STACK_NO_MEMORY;
359     }
360
361     OCRepPayloadSetUri(tempPayload, resourcePtr->uri);
362     if (addDeviceId)
363     {
364         const char *deviceId = OCGetServerInstanceIDString();
365         if (!deviceId)
366         {
367             OIC_LOG(ERROR, TAG, "Failed retrieving device id.");
368             return OC_STACK_ERROR;
369         }
370         OCRepPayloadSetPropString(tempPayload, OC_RSRVD_DEVICE_ID, deviceId);
371     }
372     OCResourceType *resType = resourcePtr->rsrcType;
373     while(resType)
374     {
375         OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename);
376         resType = resType->next;
377     }
378
379     OCResourceInterface *resInterface = resourcePtr->rsrcInterface;
380     while(resInterface)
381     {
382         OCRepPayloadAddInterface(tempPayload, resInterface->name);
383         resInterface = resInterface->next;
384     }
385
386     OCAttribute *resAttrib = resourcePtr->rsrcAttributes;
387     while(resAttrib)
388     {
389         if (resAttrib->attrName && resAttrib->attrValue)
390         {
391             if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, resAttrib->attrName))
392             {
393                 char *dmv = OCCreateString((OCStringLL *)resAttrib->attrValue);
394                 if (dmv)
395                 {
396                     OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, dmv);
397                     OICFree(dmv);
398                 }
399             }
400             else
401             {
402                 OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, (char *)resAttrib->attrValue);
403             }
404         }
405         resAttrib = resAttrib->next;
406     }
407
408     if (devAddr)
409     {
410         OCResourceProperty p = OCGetResourceProperties((OCResourceHandle *)resourcePtr);
411         OCRepPayload *policy = OCRepPayloadCreate();
412         if (!policy)
413         {
414             OCPayloadDestroy((OCPayload *)tempPayload);
415             return OC_STACK_NO_MEMORY;
416         }
417         OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE)));
418         if (p & OC_SECURE)
419         {
420             OCRepPayloadSetPropBool(policy, OC_RSRVD_SECURE, p & OC_SECURE);
421             uint16_t securePort = 0;
422             if (GetSecurePortInfo(devAddr, &securePort) != OC_STACK_OK)
423             {
424                 securePort = 0;
425             }
426             OCRepPayloadSetPropInt(policy, OC_RSRVD_HOSTING_PORT, securePort);
427         }
428         OCRepPayloadSetPropObjectAsOwner(tempPayload, OC_RSRVD_POLICY, policy);
429     }
430
431     if(!*payload)
432     {
433         *payload = tempPayload;
434     }
435     else
436     {
437         OCRepPayloadAppend(*payload, tempPayload);
438     }
439
440     return OC_STACK_OK;
441 }
442
443 OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
444                         OCDiscoveryPayload *payload, OCDevAddr *devAddr)
445 {
446     if (!resourcePtr || !payload)
447     {
448         return OC_STACK_INVALID_PARAM;
449     }
450     uint16_t securePort = 0;
451     if (resourcePtr->resourceProperties & OC_SECURE)
452     {
453        if (GetSecurePortInfo(devAddr, &securePort) != OC_STACK_OK)
454        {
455            securePort = 0;
456        }
457     }
458
459 #ifdef TCP_ADAPTER
460     uint16_t tcpPort = 0;
461     GetTCPPortInfo(devAddr, &tcpPort, (resourcePtr->resourceProperties & OC_SECURE));
462
463     OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort, tcpPort);
464 #else
465     OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort);
466 #endif
467
468     return OC_STACK_OK;
469 }
470
471 uint8_t IsCollectionResource (OCResource *resource)
472 {
473     if(!resource)
474     {
475         return 0;
476     }
477
478     if(resource->rsrcChildResourcesHead != NULL)
479     {
480         return 1;
481     }
482
483     return 0;
484 }
485
486 OCResource *FindResourceByUri(const char* resourceUri)
487 {
488     if(!resourceUri)
489     {
490         return NULL;
491     }
492
493     OCResource * pointer = headResource;
494     while (pointer)
495     {
496         if (strcmp(resourceUri, pointer->uri) == 0)
497         {
498             return pointer;
499         }
500         pointer = pointer->next;
501     }
502     OIC_LOG_V(INFO, TAG, "Resource %s not found", resourceUri);
503     return NULL;
504 }
505
506
507 OCStackResult DetermineResourceHandling (const OCServerRequest *request,
508                                          ResourceHandling *handling,
509                                          OCResource **resource)
510 {
511     if(!request || !handling || !resource)
512     {
513         return OC_STACK_INVALID_PARAM;
514     }
515
516     OIC_LOG_V(INFO, TAG, "DetermineResourceHandling for %s", request->resourceUrl);
517
518     // Check if virtual resource
519     if (GetTypeOfVirtualURI(request->resourceUrl) != OC_UNKNOWN_URI)
520     {
521         OIC_LOG_V (INFO, TAG, "%s is virtual", request->resourceUrl);
522         *handling = OC_RESOURCE_VIRTUAL;
523         *resource = headResource;
524         return OC_STACK_OK;
525     }
526     if (strlen((const char*)(request->resourceUrl)) == 0)
527     {
528         // Resource URL not specified
529         *handling = OC_RESOURCE_NOT_SPECIFIED;
530         return OC_STACK_NO_RESOURCE;
531     }
532     else
533     {
534         OCResource *resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
535         *resource = resourcePtr;
536         if (!resourcePtr)
537         {
538             if(defaultDeviceHandler)
539             {
540                 *handling = OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER;
541                 return OC_STACK_OK;
542             }
543
544             // Resource does not exist
545             // and default device handler does not exist
546             *handling = OC_RESOURCE_NOT_SPECIFIED;
547             return OC_STACK_NO_RESOURCE;
548         }
549
550         if (IsCollectionResource (resourcePtr))
551         {
552             // Collection resource
553             if (resourcePtr->entityHandler != defaultResourceEHandler)
554             {
555                 *handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
556                 return OC_STACK_OK;
557             }
558             else
559             {
560                 *handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
561                 return OC_STACK_OK;
562             }
563         }
564         else
565         {
566             // Resource not a collection
567             if (resourcePtr->entityHandler != defaultResourceEHandler)
568             {
569                 *handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
570                 return OC_STACK_OK;
571             }
572             else
573             {
574                 *handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
575                 return OC_STACK_OK;
576             }
577         }
578     }
579 }
580
581 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
582 {
583     OCStackResult result;
584
585     switch (ehResult)
586     {
587         case OC_EH_OK:
588         case OC_EH_CONTENT:
589         case OC_EH_VALID:
590             result = OC_STACK_OK;
591             break;
592         case OC_EH_SLOW:
593             result = OC_STACK_SLOW_RESOURCE;
594             break;
595         case OC_EH_ERROR:
596             result = OC_STACK_ERROR;
597             break;
598         case OC_EH_FORBIDDEN:
599             result = OC_STACK_FORBIDDEN_REQ;
600             break;
601         case OC_EH_INTERNAL_SERVER_ERROR:
602             result = OC_STACK_INTERNAL_SERVER_ERROR;
603             break;
604         case OC_EH_RESOURCE_CREATED:
605             result = OC_STACK_RESOURCE_CREATED;
606             break;
607         case OC_EH_RESOURCE_DELETED:
608             result = OC_STACK_RESOURCE_DELETED;
609             break;
610         case OC_EH_CHANGED:
611             result = OC_STACK_RESOURCE_CHANGED;
612             break;
613         case OC_EH_RESOURCE_NOT_FOUND:
614             result = OC_STACK_NO_RESOURCE;
615             break;
616         default:
617             result = OC_STACK_ERROR;
618     }
619
620     return result;
621 }
622
623 static bool resourceMatchesRTFilter(OCResource *resource, char *resourceTypeFilter)
624 {
625     if (!resource)
626     {
627         return false;
628     }
629
630     // Null or empty is analogous to no filter.
631     if (resourceTypeFilter == NULL || *resourceTypeFilter == 0)
632     {
633         return true;
634     }
635
636     OCResourceType *resourceTypePtr = resource->rsrcType;
637
638     while (resourceTypePtr)
639     {
640         if (strcmp (resourceTypePtr->resourcetypename, resourceTypeFilter) == 0)
641         {
642             return true;
643         }
644         resourceTypePtr = resourceTypePtr->next;
645     }
646
647     OIC_LOG_V(INFO, TAG, "%s does not contain rt=%s.", resource->uri, resourceTypeFilter);
648     return false;
649 }
650
651 static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter)
652 {
653     if (!resource)
654     {
655         return false;
656     }
657
658     // Null or empty is analogous to no filter.
659     if (interfaceFilter == NULL || *interfaceFilter == 0)
660     {
661         return true;
662     }
663
664     OCResourceInterface *interfacePtr = resource->rsrcInterface;
665
666     while (interfacePtr)
667     {
668         if (strcmp (interfacePtr->name, interfaceFilter) == 0 ||
669             strcmp (OC_RSRVD_INTERFACE_LL, interfaceFilter) == 0 ||
670             strcmp (OC_RSRVD_INTERFACE_DEFAULT, interfaceFilter) == 0)
671         {
672             return true;
673         }
674         interfacePtr = interfacePtr->next;
675     }
676
677     OIC_LOG_V(INFO, TAG, "%s does not contain if=%s.", resource->uri, interfaceFilter);
678     return false;
679 }
680
681 /*
682  * If the filters are null, they will be assumed to NOT be present
683  * and the resource will not be matched against them.
684  * Function will return true if all non null AND non empty filters passed in find a match.
685  */
686 static bool includeThisResourceInResponse(OCResource *resource,
687                                           char *interfaceFilter,
688                                           char *resourceTypeFilter)
689 {
690     if (!resource)
691     {
692         OIC_LOG(ERROR, TAG, "Invalid resource");
693         return false;
694     }
695
696     if (resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
697     {
698         /*
699          * At least one valid filter should be available to
700          * include the resource in discovery response
701          */
702         if (!(resourceTypeFilter && *resourceTypeFilter))
703         {
704             OIC_LOG_V(INFO, TAG, "%s no query string for EXPLICIT_DISCOVERABLE \
705                 resource", resource->uri);
706             return false;
707         }
708     }
709     else if ( !(resource->resourceProperties & OC_ACTIVE) ||
710          !(resource->resourceProperties & OC_DISCOVERABLE))
711     {
712         OIC_LOG_V(INFO, TAG, "%s not ACTIVE or DISCOVERABLE", resource->uri);
713         return false;
714     }
715
716     return resourceMatchesIFFilter(resource, interfaceFilter) &&
717            resourceMatchesRTFilter(resource, resourceTypeFilter);
718
719 }
720
721 OCStackResult SendNonPersistantDiscoveryResponse(OCServerRequest *request, OCResource *resource,
722                                 OCPayload *discoveryPayload, OCEntityHandlerResult ehResult)
723 {
724     OCEntityHandlerResponse response = {0};
725
726     response.ehResult = ehResult;
727     response.payload = discoveryPayload;
728     response.persistentBufferFlag = 0;
729     response.requestHandle = (OCRequestHandle) request->requestId;
730     response.resourceHandle = (OCResourceHandle) resource;
731
732     return OCDoResponse(&response);
733 }
734 #ifdef RD_SERVER
735 /**
736  * Find resource at the resource directory server. This resource is not local resource but a
737  * remote resource.
738  *
739  * @param resource The resource to check the matching resource URI.
740  * @param interfaceQuery The interface query parameter.
741  * @param resourceTypeQuery The resourceType query parameter.
742  * @param discPayload The payload that will be added with the resource information if found at RD.
743  *
744  * @return ::OC_STACK_OK if the resource is found else ::OC_STACK_NO_RESOURCE.
745  * In case if build is not with flag RD_SERVER, it returns ::OC_STACK_NO_RESOURCE.
746  */
747 static OCStackResult findResourceAtRD(const OCResource* resource, const char *interfaceQuery,
748     const char *resourceTypeQuery, OCDiscoveryPayload *discPayload)
749 {
750     if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0)
751     {
752         if (OC_STACK_OK == OCRDDatabaseCheckResources(interfaceQuery, resourceTypeQuery, discPayload))
753         {
754             return OC_STACK_OK;
755         }
756     }
757
758     return OC_STACK_NO_RESOURCE;
759 }
760 #endif
761
762 /**
763  * Creates a discovery payload and add device id information. This information is included in all
764  * /oic/res response.
765  *
766  * @param payload  payload that will have memory alllocated and device id information added.
767  *
768  * @return ::OC_STACK_OK if successful in allocating memory and adding ID information.
769  * ::OC_STACK_NO_MEMORY if failed allocating the memory.
770  */
771 static OCStackResult discoveryPayloadCreateAndAddDeviceId(OCPayload **payload)
772 {
773     if (*payload)
774     {
775         OIC_LOG_V(DEBUG, TAG, "Payload is already allocated");
776         return OC_STACK_OK;
777     }
778
779     *payload = (OCPayload *) OCDiscoveryPayloadCreate();
780     VERIFY_PARAM_NON_NULL(TAG, *payload, "Failed adding device id to discovery payload.");
781
782     {
783         OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)*payload;
784         discPayload->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
785         VERIFY_PARAM_NON_NULL(TAG, discPayload->sid, "Failed adding device id to discovery payload.");
786
787         const char* uid = OCGetServerInstanceIDString();
788         if (uid)
789         {
790             memcpy(discPayload->sid, uid, UUID_STRING_SIZE);
791         }
792
793     }
794     return OC_STACK_OK;
795 exit:
796     OCPayloadDestroy(*payload);
797     return OC_STACK_NO_MEMORY;
798 }
799
800 /**
801  * Add the common properties to the payload, they are only included in case of oic.if.baseline response.
802  *
803  * @param discPayload payload that will have the baseline information included.
804  *
805  * @return ::OC_STACK_OK if successful in adding all the information. ::OC_STACK_NO_MEMORY if failed
806  * allocating the memory for the baseline information.
807  */
808 static OCStackResult addDiscoveryBaselineCommonProperties(OCDiscoveryPayload *discPayload)
809 {
810     discPayload->uri = OICStrdup(OC_RSRVD_WELL_KNOWN_URI);
811     VERIFY_PARAM_NON_NULL(TAG, discPayload->uri, "Failed adding href to discovery payload.");
812
813     OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, "deviceName", (void **)&discPayload->name);
814
815     discPayload->type = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
816     VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt to discovery payload.");
817     discPayload->type->value = OICStrdup(OC_RSRVD_RESOURCE_TYPE_RES);
818     VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt value to discovery payload.");
819
820     OCResourcePayloadAddStringLL(&discPayload->iface, OC_RSRVD_INTERFACE_LL);
821     OCResourcePayloadAddStringLL(&discPayload->iface, OC_RSRVD_INTERFACE_DEFAULT);
822     VERIFY_PARAM_NON_NULL(TAG, discPayload->iface, "Failed adding if to discovery payload.");
823
824     return OC_STACK_OK;
825
826 exit:
827     return OC_STACK_NO_MEMORY;
828 }
829
830 static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource)
831 {
832     if (!request || !resource)
833     {
834         return OC_STACK_INVALID_PARAM;
835     }
836
837     OCPayload* payload = NULL;
838     char *interfaceQuery = NULL;
839     char *resourceTypeQuery = NULL;
840     char *dataModelVersions = NULL;
841
842     OIC_LOG(INFO, TAG, "Entering HandleVirtualResource");
843
844     OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
845
846 #ifdef TCP_ADAPTER
847     if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
848     {
849         // Received request for a keepalive
850         OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
851         return HandleKeepAliveRequest(request, resource);
852     }
853 #endif
854
855     OCStackResult discoveryResult = OC_STACK_ERROR;
856     if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
857         request->method == OC_REST_DELETE)
858     {
859         OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
860             request->resourceUrl, request->method);
861         return OC_STACK_UNAUTHORIZED_REQ;
862     }
863
864     // Step 1: Generate the response to discovery request
865     if (virtualUriInRequest == OC_WELL_KNOWN_URI
866 #ifdef MQ_BROKER
867             || virtualUriInRequest == OC_MQ_BROKER_URI
868 #endif
869             )
870     {
871         discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
872                 &interfaceQuery, &resourceTypeQuery);
873         VERIFY_SUCCESS(discoveryResult);
874         if (!interfaceQuery && !resourceTypeQuery)
875         {
876             // If no query is sent, default interface is used i.e. oic.if.ll.
877             interfaceQuery = OICStrdup(OC_RSRVD_INTERFACE_LL);
878         }
879
880         bool baselineQuery = false;
881         if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT))
882         {
883             baselineQuery = true;
884         }
885
886         discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload);
887         VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload.");
888         VERIFY_SUCCESS(discoveryResult);
889
890         OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
891         if (baselineQuery)
892         {
893             discoveryResult = addDiscoveryBaselineCommonProperties(discPayload);
894             VERIFY_SUCCESS(discoveryResult);
895         }
896         OCResourceProperty prop = OC_DISCOVERABLE;
897 #ifdef MQ_BROKER
898         prop = (OC_MQ_BROKER_URI == virtualUriInRequest) ? OC_MQ_BROKER : prop;
899 #endif
900         for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
901         {
902             discoveryResult = OC_STACK_NO_RESOURCE;
903 #ifdef RD_SERVER
904             discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery,
905                 discPayload);
906 #endif
907             if (OC_STACK_NO_RESOURCE == discoveryResult)
908             {
909                 // This case will handle when no resource type and it is oic.if.ll.
910                 if (!resourceTypeQuery && !baselineQuery && (resource->resourceProperties & prop))
911                 {
912                     discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
913                 }
914                 else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery))
915                 {
916                     discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
917                 }
918                 else
919                 {
920                     discoveryResult = OC_STACK_OK;
921                 }
922             }
923         }
924         if (discPayload->resources == NULL)
925         {
926             discoveryResult = OC_STACK_NO_RESOURCE;
927         }
928     }
929     else if (virtualUriInRequest == OC_DEVICE_URI)
930     {
931         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_DEVICE_URI);
932         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Device URI not found.");
933         discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, NULL, true);
934
935     }
936     else if (virtualUriInRequest == OC_PLATFORM_URI)
937     {
938         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
939         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Platform URI not found.");
940         discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, NULL, false);
941     }
942 #ifdef ROUTING_GATEWAY
943     else if (OC_GATEWAY_URI == virtualUriInRequest)
944     {
945         // Received request for a gateway
946         OIC_LOG(INFO, TAG, "Request is for Gateway Virtual Request");
947         discoveryResult = RMHandleGatewayRequest(request, resource);
948     }
949 #endif
950
951     /**
952      * Step 2: Send the discovery response
953      *
954      * Iotivity should respond to discovery requests in below manner:
955      * 1)If query filter matching fails and discovery request is multicast,
956      *   it should NOT send any response.
957      * 2)If query filter matching fails and discovery request is unicast,
958      *   it should send an error(RESOURCE_NOT_FOUND - 404) response.
959      * 3)If Server does not have any 'DISCOVERABLE' resources and discovery
960      *   request is multicast, it should NOT send any response.
961      * 4)If Server does not have any 'DISCOVERABLE' resources and discovery
962      *   request is unicast, it should send an error(RESOURCE_NOT_FOUND - 404) response.
963      */
964
965 #ifdef WITH_PRESENCE
966     if ((virtualUriInRequest == OC_PRESENCE) &&
967         (resource->resourceProperties & OC_ACTIVE))
968     {
969         // Need to send ACK when the request is CON.
970         if (request->qos == OC_HIGH_QOS)
971         {
972             CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
973             CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
974             SendDirectStackResponse(&endpoint, request->coapID, CA_EMPTY, CA_MSG_ACKNOWLEDGE,
975                                     0, NULL, NULL, 0, NULL, CA_RESPONSE_FOR_RES);
976         }
977         FindAndDeleteServerRequest(request);
978
979         // Presence uses observer notification api to respond via SendPresenceNotification.
980         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
981     }
982     else
983 #endif
984 #if ROUTING_GATEWAY
985     // Gateway uses the RMHandleGatewayRequest to respond to the request.
986     if (OC_GATEWAY_URI != virtualUriInRequest)
987 #endif
988     {
989         OIC_LOG_PAYLOAD(DEBUG, payload);
990         if(discoveryResult == OC_STACK_OK)
991         {
992             SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
993         }
994         else if(((request->devAddr.flags &  OC_MULTICAST) == false) &&
995             (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
996             (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
997         {
998             OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request",
999                 discoveryResult, virtualUriInRequest);
1000             SendNonPersistantDiscoveryResponse(request, resource, NULL,
1001                 (discoveryResult == OC_STACK_NO_RESOURCE) ?
1002                         OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
1003         }
1004         else
1005         {
1006             // Ignoring the discovery request as per RFC 7252, Section #8.2
1007             OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send.");
1008             // the request should be removed.
1009             // since it never remove and causes a big memory waste.
1010             FindAndDeleteServerRequest(request);
1011         }
1012     }
1013
1014 exit:
1015     if (interfaceQuery)
1016     {
1017         OICFree(interfaceQuery);
1018     }
1019
1020     if (resourceTypeQuery)
1021     {
1022         OICFree(resourceTypeQuery);
1023     }
1024     OCPayloadDestroy(payload);
1025     if (dataModelVersions)
1026     {
1027         OICFree(dataModelVersions);
1028     }
1029     return discoveryResult;
1030 }
1031
1032 static OCStackResult
1033 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
1034 {
1035     if(!request)
1036     {
1037         return OC_STACK_INVALID_PARAM;
1038     }
1039
1040     OCStackResult result = OC_STACK_OK;
1041     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1042     OCEntityHandlerRequest ehRequest = {0};
1043
1044     OIC_LOG(INFO, TAG, "Entering HandleResourceWithDefaultDeviceEntityHandler");
1045     result = FormOCEntityHandlerRequest(&ehRequest,
1046                                         (OCRequestHandle) request->requestId,
1047                                         request->method,
1048                                         &request->devAddr,
1049                                         (OCResourceHandle) NULL, request->query,
1050                                         PAYLOAD_TYPE_REPRESENTATION,
1051                                         request->payload,
1052                                         request->payloadSize,
1053                                         request->numRcvdVendorSpecificHeaderOptions,
1054                                         request->rcvdVendorSpecificHeaderOptions,
1055                                         (OCObserveAction)request->observationOption,
1056                                         (OCObservationId)0,
1057                                         request->coapID);
1058     VERIFY_SUCCESS(result);
1059
1060     // At this point we know for sure that defaultDeviceHandler exists
1061     ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
1062                                   (char*) request->resourceUrl, defaultDeviceHandlerCallbackParameter);
1063     if(ehResult == OC_EH_SLOW)
1064     {
1065         OIC_LOG(INFO, TAG, "This is a slow resource");
1066         request->slowFlag = 1;
1067     }
1068     else if(ehResult == OC_EH_ERROR)
1069     {
1070         FindAndDeleteServerRequest(request);
1071     }
1072     result = EntityHandlerCodeToOCStackCode(ehResult);
1073 exit:
1074     OCPayloadDestroy(ehRequest.payload);
1075     return result;
1076 }
1077
1078 static OCStackResult
1079 HandleResourceWithEntityHandler (OCServerRequest *request,
1080                                  OCResource *resource,
1081                                  uint8_t collectionResource)
1082 {
1083     OC_UNUSED(collectionResource);
1084
1085     if(!request || ! resource)
1086     {
1087         return OC_STACK_INVALID_PARAM;
1088     }
1089
1090     OCStackResult result = OC_STACK_ERROR;
1091     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1092     OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
1093     ResourceObserver *resObs = NULL;
1094
1095     OCEntityHandlerRequest ehRequest = {0};
1096
1097     OIC_LOG(INFO, TAG, "Entering HandleResourceWithEntityHandler");
1098     OCPayloadType type = PAYLOAD_TYPE_REPRESENTATION;
1099     // check the security resource
1100     if (request && request->resourceUrl && SRMIsSecurityResourceURI(request->resourceUrl))
1101     {
1102         type = PAYLOAD_TYPE_SECURITY;
1103     }
1104
1105     result = FormOCEntityHandlerRequest(&ehRequest,
1106                                         (OCRequestHandle)request->requestId,
1107                                         request->method,
1108                                         &request->devAddr,
1109                                         (OCResourceHandle)resource,
1110                                         request->query,
1111                                         type,
1112                                         request->payload,
1113                                         request->payloadSize,
1114                                         request->numRcvdVendorSpecificHeaderOptions,
1115                                         request->rcvdVendorSpecificHeaderOptions,
1116                                         (OCObserveAction)request->observationOption,
1117                                         0,
1118                                         request->coapID);
1119     VERIFY_SUCCESS(result);
1120
1121     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
1122     {
1123         OIC_LOG(INFO, TAG, "No observation requested");
1124         ehFlag = OC_REQUEST_FLAG;
1125     }
1126     else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER)
1127     {
1128         OIC_LOG(INFO, TAG, "Observation registration requested");
1129
1130         ResourceObserver *obs = GetObserverUsingToken (request->requestToken,
1131                                     request->tokenLength);
1132
1133         if (obs)
1134         {
1135             OIC_LOG (INFO, TAG, "Observer with this token already present");
1136             OIC_LOG (INFO, TAG, "Possibly re-transmitted CON OBS request");
1137             OIC_LOG (INFO, TAG, "Not adding observer. Not responding to client");
1138             OIC_LOG (INFO, TAG, "The first request for this token is already ACKED.");
1139
1140             // server requests are usually free'd when the response is sent out
1141             // for the request in ocserverrequest.c : HandleSingleResponse()
1142             // Since we are making an early return and not responding, the server request
1143             // needs to be deleted.
1144             FindAndDeleteServerRequest (request);
1145             return OC_STACK_OK;
1146         }
1147
1148         result = GenerateObserverId(&ehRequest.obsInfo.obsId);
1149         VERIFY_SUCCESS(result);
1150
1151         result = AddObserver ((const char*)(request->resourceUrl),
1152                 (const char *)(request->query),
1153                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
1154                 resource, request->qos, request->acceptFormat,
1155                 &request->devAddr);
1156
1157         if(result == OC_STACK_OK)
1158         {
1159             OIC_LOG(INFO, TAG, "Added observer successfully");
1160             request->observeResult = OC_STACK_OK;
1161             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
1162         }
1163         else if (result == OC_STACK_RESOURCE_ERROR)
1164         {
1165             OIC_LOG(INFO, TAG, "The Resource is not active, discoverable or observable");
1166             request->observeResult = OC_STACK_ERROR;
1167             ehFlag = OC_REQUEST_FLAG;
1168         }
1169         else
1170         {
1171             // The error in observeResult for the request will be used when responding to this
1172             // request by omitting the observation option/sequence number.
1173             request->observeResult = OC_STACK_ERROR;
1174             OIC_LOG(ERROR, TAG, "Observer Addition failed");
1175             ehFlag = OC_REQUEST_FLAG;
1176             FindAndDeleteServerRequest(request);
1177             goto exit;
1178         }
1179
1180     }
1181     else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER)
1182     {
1183         OIC_LOG(INFO, TAG, "Deregistering observation requested");
1184
1185         resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
1186
1187         if (NULL == resObs)
1188         {
1189             // Stack does not contain this observation request
1190             // Either token is incorrect or observation list is corrupted
1191             result = OC_STACK_ERROR;
1192             goto exit;
1193         }
1194         ehRequest.obsInfo.obsId = resObs->observeId;
1195         ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
1196
1197         result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
1198
1199         if(result == OC_STACK_OK)
1200         {
1201             OIC_LOG(INFO, TAG, "Removed observer successfully");
1202             request->observeResult = OC_STACK_OK;
1203             // There should be no observe option header for de-registration response.
1204             // Set as an invalid value here so we can detect it later and remove the field in response.
1205             request->observationOption = MAX_SEQUENCE_NUMBER + 1;
1206         }
1207         else
1208         {
1209             request->observeResult = OC_STACK_ERROR;
1210             OIC_LOG(ERROR, TAG, "Observer Removal failed");
1211             FindAndDeleteServerRequest(request);
1212             goto exit;
1213         }
1214     }
1215     else
1216     {
1217         result = OC_STACK_ERROR;
1218         goto exit;
1219     }
1220
1221     ehResult = resource->entityHandler(ehFlag, &ehRequest, resource->entityHandlerCallbackParam);
1222     if(ehResult == OC_EH_SLOW)
1223     {
1224         OIC_LOG(INFO, TAG, "This is a slow resource");
1225         request->slowFlag = 1;
1226     }
1227     else if(ehResult == OC_EH_ERROR)
1228     {
1229         FindAndDeleteServerRequest(request);
1230     }
1231     result = EntityHandlerCodeToOCStackCode(ehResult);
1232 exit:
1233     OCPayloadDestroy(ehRequest.payload);
1234     return result;
1235 }
1236
1237 static OCStackResult
1238 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
1239                                               OCResource *resource)
1240 {
1241     if(!request || !resource)
1242     {
1243         return OC_STACK_INVALID_PARAM;
1244     }
1245
1246     OCStackResult result = OC_STACK_ERROR;
1247     OCEntityHandlerRequest ehRequest = {0};
1248
1249     result = FormOCEntityHandlerRequest(&ehRequest,
1250                                         (OCRequestHandle)request->requestId,
1251                                         request->method,
1252                                         &request->devAddr,
1253                                         (OCResourceHandle)resource,
1254                                         request->query,
1255                                         PAYLOAD_TYPE_REPRESENTATION,
1256                                         request->payload,
1257                                         request->payloadSize,
1258                                         request->numRcvdVendorSpecificHeaderOptions,
1259                                         request->rcvdVendorSpecificHeaderOptions,
1260                                         (OCObserveAction)request->observationOption,
1261                                         (OCObservationId)0,
1262                                         request->coapID);
1263     if(result == OC_STACK_OK)
1264     {
1265         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
1266     }
1267
1268     OCPayloadDestroy(ehRequest.payload);
1269     return result;
1270 }
1271
1272 OCStackResult
1273 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
1274 {
1275     OCStackResult ret = OC_STACK_OK;
1276
1277     switch (resHandling)
1278     {
1279         case OC_RESOURCE_VIRTUAL:
1280         {
1281             ret = HandleVirtualResource (request, resource);
1282             break;
1283         }
1284         case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
1285         {
1286             ret = HandleDefaultDeviceEntityHandler(request);
1287             break;
1288         }
1289         case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
1290         {
1291             OIC_LOG(INFO, TAG, "OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER");
1292             return OC_STACK_ERROR;
1293         }
1294         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
1295         {
1296             ret = HandleResourceWithEntityHandler (request, resource, 0);
1297             break;
1298         }
1299         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
1300         {
1301             ret = HandleResourceWithEntityHandler (request, resource, 1);
1302             break;
1303         }
1304         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
1305         {
1306             ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
1307             break;
1308         }
1309         case OC_RESOURCE_NOT_SPECIFIED:
1310         {
1311             ret = OC_STACK_NO_RESOURCE;
1312             break;
1313         }
1314         default:
1315         {
1316             OIC_LOG(INFO, TAG, "Invalid Resource Determination");
1317             return OC_STACK_ERROR;
1318         }
1319     }
1320     return ret;
1321 }
1322
1323 OCStackResult OCSetPlatformInfo(OCPlatformInfo info)
1324 {
1325     OCResource *resource = NULL;
1326     if (!info.platformID || !info.manufacturerName)
1327     {
1328         OIC_LOG(ERROR, TAG, "No value specified.");
1329         goto exit;
1330     }
1331     if (0 == strlen(info.platformID) || 0 == strlen(info.manufacturerName))
1332     {
1333         OIC_LOG(ERROR, TAG, "The passed value cannot be empty");
1334         goto exit;
1335     }
1336     if ((info.manufacturerName && strlen(info.manufacturerName) > MAX_PLATFORM_NAME_LENGTH) ||
1337         (info.manufacturerUrl && strlen(info.manufacturerUrl) > MAX_PLATFORM_URL_LENGTH) ||
1338         (info.modelNumber && strlen(info.modelNumber) > MAX_PLATFORM_NAME_LENGTH) ||
1339         (info.platformVersion && strlen(info.platformVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1340         (info.operatingSystemVersion && strlen(info.operatingSystemVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1341         (info.hardwareVersion && strlen(info.hardwareVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1342         (info.firmwareVersion && strlen(info.firmwareVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1343         (info.supportUrl && strlen(info.supportUrl) > MAX_PLATFORM_URL_LENGTH))
1344     {
1345         OIC_LOG(ERROR, TAG, "The passed value is bigger than permitted.");
1346         goto exit;
1347     }
1348
1349     resource = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
1350     if (!resource)
1351     {
1352         OIC_LOG(ERROR, TAG, "Platform Resource does not exist.");
1353         goto exit;
1354     }
1355     OIC_LOG(INFO, TAG, "Entering OCSetPlatformInfo");
1356     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_PLATFORM_ID, info.platformID));
1357     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_NAME, info.manufacturerName));
1358     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_URL, info.manufacturerUrl);
1359     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MODEL_NUM, info.modelNumber);
1360     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_DATE, info.dateOfManufacture);
1361     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_PLATFORM_VERSION, info.platformVersion);
1362     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_OS_VERSION, info.operatingSystemVersion);
1363     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_HARDWARE_VERSION, info.hardwareVersion);
1364     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_FIRMWARE_VERSION, info.firmwareVersion);
1365     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_SUPPORT_URL, info.supportUrl);
1366     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_SYSTEM_TIME, info.systemTime);
1367     OIC_LOG(INFO, TAG, "Platform parameter initialized successfully.");
1368     return OC_STACK_OK;
1369
1370 exit:
1371     return OC_STACK_INVALID_PARAM;
1372 }
1373
1374 OCStackResult OCSetDeviceInfo(OCDeviceInfo info)
1375 {
1376     OCStringLL *dataModelVersion = NULL;
1377     OCResource *resource = FindResourceByUri(OC_RSRVD_DEVICE_URI);
1378     if (!resource)
1379     {
1380         OIC_LOG(ERROR, TAG, "Device Resource does not exist.");
1381         goto exit;
1382     }
1383     if (!info.deviceName || info.deviceName[0] == '\0')
1384     {
1385         OIC_LOG(ERROR, TAG, "Null or empty device name.");
1386        return OC_STACK_INVALID_PARAM;
1387     }
1388
1389     if (OCGetServerInstanceIDString() == NULL)
1390     {
1391         OIC_LOG(INFO, TAG, "Device ID generation failed");
1392         goto exit;
1393     }
1394
1395     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, info.deviceName));
1396     for (OCStringLL *temp = info.types; temp; temp = temp->next)
1397     {
1398         if (temp->value)
1399         {
1400             VERIFY_SUCCESS(OCBindResourceTypeToResource(resource, temp->value));
1401         }
1402     }
1403     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, info.specVersion ?
1404         info.specVersion: OC_SPEC_VERSION));
1405     if (info.dataModelVersions)
1406     {
1407         VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, info.dataModelVersions));
1408     }
1409     else
1410     {
1411         dataModelVersion = OCCreateOCStringLL(OC_DATA_MODEL_VERSION);
1412         VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, dataModelVersion));
1413     }
1414     OIC_LOG(INFO, TAG, "Device parameter initialized successfully.");
1415     return OC_STACK_OK;
1416
1417 exit:
1418     if (dataModelVersion)
1419     {
1420         OCFreeOCStringLL(dataModelVersion);
1421     }
1422     return OC_STACK_ERROR;
1423 }
1424
1425 OCStackResult OCGetAttribute(const OCResource *resource, const char *attribute, void **value)
1426 {
1427     if (!resource || !attribute)
1428     {
1429         return OC_STACK_INVALID_PARAM;
1430     }
1431     if (0 == strlen(attribute))
1432     {
1433         return OC_STACK_INVALID_PARAM;
1434     }
1435     for (OCAttribute *temp = resource->rsrcAttributes; temp; temp = temp->next)
1436     {
1437         if (0 == strcmp(attribute, temp->attrName))
1438         {
1439             // A special case as this type return OCStringLL
1440             if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
1441             {
1442                 *value = CloneOCStringLL((OCStringLL *)temp->attrValue);
1443                 return OC_STACK_OK;
1444             }
1445             else
1446             {
1447                 *value = OICStrdup((char *)temp->attrValue);
1448                 return OC_STACK_OK;
1449             }
1450         }
1451     }
1452     return OC_STACK_NO_RESOURCE;
1453 }
1454
1455 OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **value)
1456 {
1457     if (!prop || *value)
1458     {
1459         return OC_STACK_INVALID_PARAM;
1460     }
1461     if (strlen(prop) == 0)
1462     {
1463         return OC_STACK_INVALID_PARAM;
1464     }
1465     OCStackResult res =  OC_STACK_NO_RESOURCE;
1466     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
1467     {
1468         const char *pathType = (type == PAYLOAD_TYPE_DEVICE) ? OC_RSRVD_DEVICE_URI : OC_RSRVD_PLATFORM_URI;
1469         OCResource *resource = FindResourceByUri(pathType);
1470         if (!resource)
1471         {
1472             return OC_STACK_NO_RESOURCE;
1473         }
1474
1475         res = OCGetAttribute(resource, prop, value);
1476     }
1477     return res;
1478 }
1479
1480 OCStackResult OCSetAttribute(OCResource* resource, const char* attribute, const void* value)
1481 {
1482     OCAttribute *resAttrib = (OCAttribute *)OICCalloc(1, sizeof(OCAttribute));
1483     VERIFY_PARAM_NON_NULL(TAG, resAttrib, "Failed allocation OCAttribute");
1484     resAttrib->attrName = OICStrdup(attribute);
1485     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrName, "Failed allocating attribute name");
1486     // A special case when value is of type OCStringLL
1487     if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
1488     {
1489         resAttrib->attrValue = CloneOCStringLL((OCStringLL *)value);
1490     }
1491     else
1492     {
1493         resAttrib->attrValue = OICStrdup((char *)value);
1494     }
1495     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrValue, "Failed allocating attribute value");
1496     resAttrib->next = NULL;
1497
1498     if (!resource->rsrcAttributes)
1499     {
1500         resource->rsrcAttributes = resAttrib;
1501     }
1502     else
1503     {
1504         OCAttribute *temp = resource->rsrcAttributes;
1505         for (; temp->next; temp = temp->next)
1506         {
1507             if (0 == strcmp(attribute, temp->attrName))
1508             {
1509                 if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, temp->attrName))
1510                 {
1511                     OCFreeOCStringLL((OCStringLL *)temp->attrValue);
1512                 }
1513                  {
1514                     OICFree((char *)temp->attrValue);
1515                 }
1516                 break;
1517             }
1518         }
1519         temp->next = resAttrib;
1520     }
1521     return OC_STACK_OK;
1522
1523 exit:
1524     OCDeleteResourceAttributes(resAttrib);
1525     return OC_STACK_NO_MEMORY;
1526
1527 }
1528
1529 OCStackResult OCSetPropertyValue(OCPayloadType type, const char *prop, const void *value)
1530 {
1531     if (!prop)
1532     {
1533         return OC_STACK_INVALID_PARAM;
1534     }
1535     if (strlen(prop) == 0)
1536     {
1537         return OC_STACK_INVALID_PARAM;
1538     }
1539
1540     OCStackResult res = OC_STACK_ERROR;
1541     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
1542     {
1543         const char *pathType = (type == PAYLOAD_TYPE_DEVICE) ? OC_RSRVD_DEVICE_URI : OC_RSRVD_PLATFORM_URI;
1544         OCResource *resource = FindResourceByUri(pathType);
1545         if (!resource)
1546         {
1547             OIC_LOG(ERROR, TAG, "Resource does not exist.");
1548         }
1549         if (value)
1550         {
1551             res = OCSetAttribute(resource, prop, value);
1552         }
1553     }
1554
1555     return res;
1556 }