[IOT-1593] TLS ports and CA_SECURE flag added for secure socket accept
[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     OCStackResult discoveryResult = OC_STACK_ERROR;
838     if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
839         request->method == OC_REST_DELETE)
840     {
841         OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
842             request->resourceUrl, request->method);
843         return OC_STACK_UNAUTHORIZED_REQ;
844     }
845
846     OCPayload* payload = NULL;
847     char *interfaceQuery = NULL;
848     char *resourceTypeQuery = NULL;
849     char *dataModelVersions = NULL;
850
851     OIC_LOG(INFO, TAG, "Entering HandleVirtualResource");
852
853     OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
854
855     // Step 1: Generate the response to discovery request
856     if (virtualUriInRequest == OC_WELL_KNOWN_URI
857 #ifdef MQ_BROKER
858             || virtualUriInRequest == OC_MQ_BROKER_URI
859 #endif
860             )
861     {
862         discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
863                 &interfaceQuery, &resourceTypeQuery);
864         VERIFY_SUCCESS(discoveryResult);
865         if (!interfaceQuery && !resourceTypeQuery)
866         {
867             // If no query is sent, default interface is used i.e. oic.if.ll.
868             interfaceQuery = OICStrdup(OC_RSRVD_INTERFACE_LL);
869         }
870
871         bool baselineQuery = false;
872         if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT))
873         {
874             baselineQuery = true;
875         }
876
877         discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload);
878         VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload.");
879         VERIFY_SUCCESS(discoveryResult);
880
881         OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
882         if (baselineQuery)
883         {
884             discoveryResult = addDiscoveryBaselineCommonProperties(discPayload);
885             VERIFY_SUCCESS(discoveryResult);
886         }
887         OCResourceProperty prop = OC_DISCOVERABLE;
888 #ifdef MQ_BROKER
889         prop = (OC_MQ_BROKER_URI == virtualUriInRequest) ? OC_MQ_BROKER : prop;
890 #endif
891         for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
892         {
893             discoveryResult = OC_STACK_NO_RESOURCE;
894 #ifdef RD_SERVER
895             discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery,
896                 discPayload);
897 #endif
898             if (OC_STACK_NO_RESOURCE == discoveryResult)
899             {
900                 // This case will handle when no resource type and it is oic.if.ll.
901                 if (!resourceTypeQuery && !baselineQuery && (resource->resourceProperties & prop))
902                 {
903                     discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
904                 }
905                 else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery))
906                 {
907                     discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
908                 }
909                 else
910                 {
911                     discoveryResult = OC_STACK_OK;
912                 }
913             }
914         }
915         if (discPayload->resources == NULL)
916         {
917             discoveryResult = OC_STACK_NO_RESOURCE;
918         }
919     }
920     else if (virtualUriInRequest == OC_DEVICE_URI)
921     {
922         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_DEVICE_URI);
923         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Device URI not found.");
924         discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, NULL, true);
925
926     }
927     else if (virtualUriInRequest == OC_PLATFORM_URI)
928     {
929         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
930         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Platform URI not found.");
931         discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, NULL, false);
932     }
933 #ifdef ROUTING_GATEWAY
934     else if (OC_GATEWAY_URI == virtualUriInRequest)
935     {
936         // Received request for a gateway
937         OIC_LOG(INFO, TAG, "Request is for Gateway Virtual Request");
938         discoveryResult = RMHandleGatewayRequest(request, resource);
939     }
940 #endif
941 #ifdef TCP_ADAPTER
942     else if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
943     {
944         // Received request for a keepalive
945         OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
946         discoveryResult = HandleKeepAliveRequest(request, resource);
947     }
948 #endif
949     /**
950      * Step 2: Send the discovery response
951      *
952      * Iotivity should respond to discovery requests in below manner:
953      * 1)If query filter matching fails and discovery request is multicast,
954      *   it should NOT send any response.
955      * 2)If query filter matching fails and discovery request is unicast,
956      *   it should send an error(RESOURCE_NOT_FOUND - 404) response.
957      * 3)If Server does not have any 'DISCOVERABLE' resources and discovery
958      *   request is multicast, it should NOT send any response.
959      * 4)If Server does not have any 'DISCOVERABLE' resources and discovery
960      *   request is unicast, it should send an error(RESOURCE_NOT_FOUND - 404) response.
961      */
962
963 #ifdef WITH_PRESENCE
964     if ((virtualUriInRequest == OC_PRESENCE) &&
965         (resource->resourceProperties & OC_ACTIVE))
966     {
967         // Need to send ACK when the request is CON.
968         if (request->qos == OC_HIGH_QOS)
969         {
970             CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
971             CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
972             SendDirectStackResponse(&endpoint, request->coapID, CA_EMPTY, CA_MSG_ACKNOWLEDGE,
973                                     0, NULL, NULL, 0, NULL, CA_RESPONSE_FOR_RES);
974         }
975         FindAndDeleteServerRequest(request);
976
977         // Presence uses observer notification api to respond via SendPresenceNotification.
978         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
979     }
980     else
981 #endif
982 #if ROUTING_GATEWAY
983     // Gateway uses the RMHandleGatewayRequest to respond to the request.
984     if (OC_GATEWAY_URI != virtualUriInRequest)
985 #endif
986     {
987 #if TCP_ADAPTER
988         // KeepAlive uses the HandleKeepAliveRequest to respond to the request.
989         if (OC_KEEPALIVE_RESOURCE_URI != virtualUriInRequest)
990 #endif
991         {
992             OIC_LOG_PAYLOAD(DEBUG, payload);
993             if(discoveryResult == OC_STACK_OK)
994             {
995                 SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
996             }
997             else if(((request->devAddr.flags &  OC_MULTICAST) == false) &&
998                 (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
999                 (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
1000             {
1001                 OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request",
1002                     discoveryResult, virtualUriInRequest);
1003                 SendNonPersistantDiscoveryResponse(request, resource, NULL,
1004                     (discoveryResult == OC_STACK_NO_RESOURCE) ?
1005                             OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
1006             }
1007             else
1008             {
1009                 // Ignoring the discovery request as per RFC 7252, Section #8.2
1010                 OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send.");
1011                 // the request should be removed.
1012                 // since it never remove and causes a big memory waste.
1013                 FindAndDeleteServerRequest(request);
1014             }
1015         }
1016     }
1017
1018 exit:
1019     if (interfaceQuery)
1020     {
1021         OICFree(interfaceQuery);
1022     }
1023
1024     if (resourceTypeQuery)
1025     {
1026         OICFree(resourceTypeQuery);
1027     }
1028     OCPayloadDestroy(payload);
1029     if (dataModelVersions)
1030     {
1031         OICFree(dataModelVersions);
1032     }
1033     return discoveryResult;
1034 }
1035
1036 static OCStackResult
1037 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
1038 {
1039     if(!request)
1040     {
1041         return OC_STACK_INVALID_PARAM;
1042     }
1043
1044     OCStackResult result = OC_STACK_OK;
1045     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1046     OCEntityHandlerRequest ehRequest = {0};
1047
1048     OIC_LOG(INFO, TAG, "Entering HandleResourceWithDefaultDeviceEntityHandler");
1049     result = FormOCEntityHandlerRequest(&ehRequest,
1050                                         (OCRequestHandle) request->requestId,
1051                                         request->method,
1052                                         &request->devAddr,
1053                                         (OCResourceHandle) NULL, request->query,
1054                                         PAYLOAD_TYPE_REPRESENTATION,
1055                                         request->payload,
1056                                         request->payloadSize,
1057                                         request->numRcvdVendorSpecificHeaderOptions,
1058                                         request->rcvdVendorSpecificHeaderOptions,
1059                                         (OCObserveAction)request->observationOption,
1060                                         (OCObservationId)0,
1061                                         request->coapID);
1062     VERIFY_SUCCESS(result);
1063
1064     // At this point we know for sure that defaultDeviceHandler exists
1065     ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
1066                                   (char*) request->resourceUrl, defaultDeviceHandlerCallbackParameter);
1067     if(ehResult == OC_EH_SLOW)
1068     {
1069         OIC_LOG(INFO, TAG, "This is a slow resource");
1070         request->slowFlag = 1;
1071     }
1072     else if(ehResult == OC_EH_ERROR)
1073     {
1074         FindAndDeleteServerRequest(request);
1075     }
1076     result = EntityHandlerCodeToOCStackCode(ehResult);
1077 exit:
1078     OCPayloadDestroy(ehRequest.payload);
1079     return result;
1080 }
1081
1082 static OCStackResult
1083 HandleResourceWithEntityHandler (OCServerRequest *request,
1084                                  OCResource *resource,
1085                                  uint8_t collectionResource)
1086 {
1087     OC_UNUSED(collectionResource);
1088
1089     if(!request || ! resource)
1090     {
1091         return OC_STACK_INVALID_PARAM;
1092     }
1093
1094     OCStackResult result = OC_STACK_ERROR;
1095     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1096     OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
1097     ResourceObserver *resObs = NULL;
1098
1099     OCEntityHandlerRequest ehRequest = {0};
1100
1101     OIC_LOG(INFO, TAG, "Entering HandleResourceWithEntityHandler");
1102     OCPayloadType type = PAYLOAD_TYPE_REPRESENTATION;
1103     // check the security resource
1104     if (request && request->resourceUrl && SRMIsSecurityResourceURI(request->resourceUrl))
1105     {
1106         type = PAYLOAD_TYPE_SECURITY;
1107     }
1108
1109     result = FormOCEntityHandlerRequest(&ehRequest,
1110                                         (OCRequestHandle)request->requestId,
1111                                         request->method,
1112                                         &request->devAddr,
1113                                         (OCResourceHandle)resource,
1114                                         request->query,
1115                                         type,
1116                                         request->payload,
1117                                         request->payloadSize,
1118                                         request->numRcvdVendorSpecificHeaderOptions,
1119                                         request->rcvdVendorSpecificHeaderOptions,
1120                                         (OCObserveAction)request->observationOption,
1121                                         0,
1122                                         request->coapID);
1123     VERIFY_SUCCESS(result);
1124
1125     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
1126     {
1127         OIC_LOG(INFO, TAG, "No observation requested");
1128         ehFlag = OC_REQUEST_FLAG;
1129     }
1130     else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER)
1131     {
1132         OIC_LOG(INFO, TAG, "Observation registration requested");
1133
1134         ResourceObserver *obs = GetObserverUsingToken (request->requestToken,
1135                                     request->tokenLength);
1136
1137         if (obs)
1138         {
1139             OIC_LOG (INFO, TAG, "Observer with this token already present");
1140             OIC_LOG (INFO, TAG, "Possibly re-transmitted CON OBS request");
1141             OIC_LOG (INFO, TAG, "Not adding observer. Not responding to client");
1142             OIC_LOG (INFO, TAG, "The first request for this token is already ACKED.");
1143
1144             // server requests are usually free'd when the response is sent out
1145             // for the request in ocserverrequest.c : HandleSingleResponse()
1146             // Since we are making an early return and not responding, the server request
1147             // needs to be deleted.
1148             FindAndDeleteServerRequest (request);
1149             return OC_STACK_OK;
1150         }
1151
1152         result = GenerateObserverId(&ehRequest.obsInfo.obsId);
1153         VERIFY_SUCCESS(result);
1154
1155         result = AddObserver ((const char*)(request->resourceUrl),
1156                 (const char *)(request->query),
1157                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
1158                 resource, request->qos, request->acceptFormat,
1159                 &request->devAddr);
1160
1161         if(result == OC_STACK_OK)
1162         {
1163             OIC_LOG(INFO, TAG, "Added observer successfully");
1164             request->observeResult = OC_STACK_OK;
1165             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
1166         }
1167         else if (result == OC_STACK_RESOURCE_ERROR)
1168         {
1169             OIC_LOG(INFO, TAG, "The Resource is not active, discoverable or observable");
1170             request->observeResult = OC_STACK_ERROR;
1171             ehFlag = OC_REQUEST_FLAG;
1172         }
1173         else
1174         {
1175             // The error in observeResult for the request will be used when responding to this
1176             // request by omitting the observation option/sequence number.
1177             request->observeResult = OC_STACK_ERROR;
1178             OIC_LOG(ERROR, TAG, "Observer Addition failed");
1179             ehFlag = OC_REQUEST_FLAG;
1180             FindAndDeleteServerRequest(request);
1181             goto exit;
1182         }
1183
1184     }
1185     else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER)
1186     {
1187         OIC_LOG(INFO, TAG, "Deregistering observation requested");
1188
1189         resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
1190
1191         if (NULL == resObs)
1192         {
1193             // Stack does not contain this observation request
1194             // Either token is incorrect or observation list is corrupted
1195             result = OC_STACK_ERROR;
1196             goto exit;
1197         }
1198         ehRequest.obsInfo.obsId = resObs->observeId;
1199         ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
1200
1201         result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
1202
1203         if(result == OC_STACK_OK)
1204         {
1205             OIC_LOG(INFO, TAG, "Removed observer successfully");
1206             request->observeResult = OC_STACK_OK;
1207             // There should be no observe option header for de-registration response.
1208             // Set as an invalid value here so we can detect it later and remove the field in response.
1209             request->observationOption = MAX_SEQUENCE_NUMBER + 1;
1210         }
1211         else
1212         {
1213             request->observeResult = OC_STACK_ERROR;
1214             OIC_LOG(ERROR, TAG, "Observer Removal failed");
1215             FindAndDeleteServerRequest(request);
1216             goto exit;
1217         }
1218     }
1219     else
1220     {
1221         result = OC_STACK_ERROR;
1222         goto exit;
1223     }
1224
1225     ehResult = resource->entityHandler(ehFlag, &ehRequest, resource->entityHandlerCallbackParam);
1226     if(ehResult == OC_EH_SLOW)
1227     {
1228         OIC_LOG(INFO, TAG, "This is a slow resource");
1229         request->slowFlag = 1;
1230     }
1231     else if(ehResult == OC_EH_ERROR)
1232     {
1233         FindAndDeleteServerRequest(request);
1234     }
1235     result = EntityHandlerCodeToOCStackCode(ehResult);
1236 exit:
1237     OCPayloadDestroy(ehRequest.payload);
1238     return result;
1239 }
1240
1241 static OCStackResult
1242 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
1243                                               OCResource *resource)
1244 {
1245     if(!request || !resource)
1246     {
1247         return OC_STACK_INVALID_PARAM;
1248     }
1249
1250     OCStackResult result = OC_STACK_ERROR;
1251     OCEntityHandlerRequest ehRequest = {0};
1252
1253     result = FormOCEntityHandlerRequest(&ehRequest,
1254                                         (OCRequestHandle)request->requestId,
1255                                         request->method,
1256                                         &request->devAddr,
1257                                         (OCResourceHandle)resource,
1258                                         request->query,
1259                                         PAYLOAD_TYPE_REPRESENTATION,
1260                                         request->payload,
1261                                         request->payloadSize,
1262                                         request->numRcvdVendorSpecificHeaderOptions,
1263                                         request->rcvdVendorSpecificHeaderOptions,
1264                                         (OCObserveAction)request->observationOption,
1265                                         (OCObservationId)0,
1266                                         request->coapID);
1267     if(result == OC_STACK_OK)
1268     {
1269         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
1270     }
1271
1272     OCPayloadDestroy(ehRequest.payload);
1273     return result;
1274 }
1275
1276 OCStackResult
1277 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
1278 {
1279     OCStackResult ret = OC_STACK_OK;
1280
1281     switch (resHandling)
1282     {
1283         case OC_RESOURCE_VIRTUAL:
1284         {
1285             ret = HandleVirtualResource (request, resource);
1286             break;
1287         }
1288         case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
1289         {
1290             ret = HandleDefaultDeviceEntityHandler(request);
1291             break;
1292         }
1293         case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
1294         {
1295             OIC_LOG(INFO, TAG, "OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER");
1296             return OC_STACK_ERROR;
1297         }
1298         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
1299         {
1300             ret = HandleResourceWithEntityHandler (request, resource, 0);
1301             break;
1302         }
1303         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
1304         {
1305             ret = HandleResourceWithEntityHandler (request, resource, 1);
1306             break;
1307         }
1308         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
1309         {
1310             ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
1311             break;
1312         }
1313         case OC_RESOURCE_NOT_SPECIFIED:
1314         {
1315             ret = OC_STACK_NO_RESOURCE;
1316             break;
1317         }
1318         default:
1319         {
1320             OIC_LOG(INFO, TAG, "Invalid Resource Determination");
1321             return OC_STACK_ERROR;
1322         }
1323     }
1324     return ret;
1325 }
1326
1327 OCStackResult OCSetPlatformInfo(OCPlatformInfo info)
1328 {
1329     OCResource *resource = NULL;
1330     if (!info.platformID || !info.manufacturerName)
1331     {
1332         OIC_LOG(ERROR, TAG, "No value specified.");
1333         goto exit;
1334     }
1335     if (0 == strlen(info.platformID) || 0 == strlen(info.manufacturerName))
1336     {
1337         OIC_LOG(ERROR, TAG, "The passed value cannot be empty");
1338         goto exit;
1339     }
1340     if ((info.manufacturerName && strlen(info.manufacturerName) > MAX_PLATFORM_NAME_LENGTH) ||
1341         (info.manufacturerUrl && strlen(info.manufacturerUrl) > MAX_PLATFORM_URL_LENGTH) ||
1342         (info.modelNumber && strlen(info.modelNumber) > MAX_PLATFORM_NAME_LENGTH) ||
1343         (info.platformVersion && strlen(info.platformVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1344         (info.operatingSystemVersion && strlen(info.operatingSystemVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1345         (info.hardwareVersion && strlen(info.hardwareVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1346         (info.firmwareVersion && strlen(info.firmwareVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1347         (info.supportUrl && strlen(info.supportUrl) > MAX_PLATFORM_URL_LENGTH))
1348     {
1349         OIC_LOG(ERROR, TAG, "The passed value is bigger than permitted.");
1350         goto exit;
1351     }
1352
1353     resource = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
1354     if (!resource)
1355     {
1356         OIC_LOG(ERROR, TAG, "Platform Resource does not exist.");
1357         goto exit;
1358     }
1359     OIC_LOG(INFO, TAG, "Entering OCSetPlatformInfo");
1360     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_PLATFORM_ID, info.platformID));
1361     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_NAME, info.manufacturerName));
1362     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_URL, info.manufacturerUrl);
1363     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MODEL_NUM, info.modelNumber);
1364     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_DATE, info.dateOfManufacture);
1365     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_PLATFORM_VERSION, info.platformVersion);
1366     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_OS_VERSION, info.operatingSystemVersion);
1367     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_HARDWARE_VERSION, info.hardwareVersion);
1368     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_FIRMWARE_VERSION, info.firmwareVersion);
1369     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_SUPPORT_URL, info.supportUrl);
1370     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_SYSTEM_TIME, info.systemTime);
1371     OIC_LOG(INFO, TAG, "Platform parameter initialized successfully.");
1372     return OC_STACK_OK;
1373
1374 exit:
1375     return OC_STACK_INVALID_PARAM;
1376 }
1377
1378 OCStackResult OCSetDeviceInfo(OCDeviceInfo info)
1379 {
1380     OCStringLL *dataModelVersion = NULL;
1381     OCResource *resource = FindResourceByUri(OC_RSRVD_DEVICE_URI);
1382     if (!resource)
1383     {
1384         OIC_LOG(ERROR, TAG, "Device Resource does not exist.");
1385         goto exit;
1386     }
1387     if (!info.deviceName || info.deviceName[0] == '\0')
1388     {
1389         OIC_LOG(ERROR, TAG, "Null or empty device name.");
1390        return OC_STACK_INVALID_PARAM;
1391     }
1392
1393     if (OCGetServerInstanceIDString() == NULL)
1394     {
1395         OIC_LOG(INFO, TAG, "Device ID generation failed");
1396         goto exit;
1397     }
1398
1399     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, info.deviceName));
1400     for (OCStringLL *temp = info.types; temp; temp = temp->next)
1401     {
1402         if (temp->value)
1403         {
1404             VERIFY_SUCCESS(OCBindResourceTypeToResource(resource, temp->value));
1405         }
1406     }
1407     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, info.specVersion ?
1408         info.specVersion: OC_SPEC_VERSION));
1409     if (info.dataModelVersions)
1410     {
1411         VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, info.dataModelVersions));
1412     }
1413     else
1414     {
1415         dataModelVersion = OCCreateOCStringLL(OC_DATA_MODEL_VERSION);
1416         VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, dataModelVersion));
1417     }
1418     OIC_LOG(INFO, TAG, "Device parameter initialized successfully.");
1419     return OC_STACK_OK;
1420
1421 exit:
1422     if (dataModelVersion)
1423     {
1424         OCFreeOCStringLL(dataModelVersion);
1425     }
1426     return OC_STACK_ERROR;
1427 }
1428
1429 OCStackResult OCGetAttribute(const OCResource *resource, const char *attribute, void **value)
1430 {
1431     if (!resource || !attribute)
1432     {
1433         return OC_STACK_INVALID_PARAM;
1434     }
1435     if (0 == strlen(attribute))
1436     {
1437         return OC_STACK_INVALID_PARAM;
1438     }
1439     for (OCAttribute *temp = resource->rsrcAttributes; temp; temp = temp->next)
1440     {
1441         if (0 == strcmp(attribute, temp->attrName))
1442         {
1443             // A special case as this type return OCStringLL
1444             if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
1445             {
1446                 *value = CloneOCStringLL((OCStringLL *)temp->attrValue);
1447                 return OC_STACK_OK;
1448             }
1449             else
1450             {
1451                 *value = OICStrdup((char *)temp->attrValue);
1452                 return OC_STACK_OK;
1453             }
1454         }
1455     }
1456     return OC_STACK_NO_RESOURCE;
1457 }
1458
1459 OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **value)
1460 {
1461     if (!prop || *value)
1462     {
1463         return OC_STACK_INVALID_PARAM;
1464     }
1465     if (strlen(prop) == 0)
1466     {
1467         return OC_STACK_INVALID_PARAM;
1468     }
1469     OCStackResult res =  OC_STACK_NO_RESOURCE;
1470     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
1471     {
1472         const char *pathType = (type == PAYLOAD_TYPE_DEVICE) ? OC_RSRVD_DEVICE_URI : OC_RSRVD_PLATFORM_URI;
1473         OCResource *resource = FindResourceByUri(pathType);
1474         if (!resource)
1475         {
1476             return OC_STACK_NO_RESOURCE;
1477         }
1478
1479         res = OCGetAttribute(resource, prop, value);
1480     }
1481     return res;
1482 }
1483
1484 OCStackResult OCSetAttribute(OCResource* resource, const char* attribute, const void* value)
1485 {
1486     OCAttribute *resAttrib = (OCAttribute *)OICCalloc(1, sizeof(OCAttribute));
1487     VERIFY_PARAM_NON_NULL(TAG, resAttrib, "Failed allocation OCAttribute");
1488     resAttrib->attrName = OICStrdup(attribute);
1489     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrName, "Failed allocating attribute name");
1490     // A special case when value is of type OCStringLL
1491     if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
1492     {
1493         resAttrib->attrValue = CloneOCStringLL((OCStringLL *)value);
1494     }
1495     else
1496     {
1497         resAttrib->attrValue = OICStrdup((char *)value);
1498     }
1499     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrValue, "Failed allocating attribute value");
1500     resAttrib->next = NULL;
1501
1502     if (!resource->rsrcAttributes)
1503     {
1504         resource->rsrcAttributes = resAttrib;
1505     }
1506     else
1507     {
1508         OCAttribute *temp = resource->rsrcAttributes;
1509         for (; temp->next; temp = temp->next)
1510         {
1511             if (0 == strcmp(attribute, temp->attrName))
1512             {
1513                 if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, temp->attrName))
1514                 {
1515                     OCFreeOCStringLL((OCStringLL *)temp->attrValue);
1516                 }
1517                  {
1518                     OICFree((char *)temp->attrValue);
1519                 }
1520                 break;
1521             }
1522         }
1523         temp->next = resAttrib;
1524     }
1525     return OC_STACK_OK;
1526
1527 exit:
1528     OCDeleteResourceAttributes(resAttrib);
1529     return OC_STACK_NO_MEMORY;
1530
1531 }
1532
1533 OCStackResult OCSetPropertyValue(OCPayloadType type, const char *prop, const void *value)
1534 {
1535     if (!prop)
1536     {
1537         return OC_STACK_INVALID_PARAM;
1538     }
1539     if (strlen(prop) == 0)
1540     {
1541         return OC_STACK_INVALID_PARAM;
1542     }
1543
1544     OCStackResult res = OC_STACK_ERROR;
1545     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
1546     {
1547         const char *pathType = (type == PAYLOAD_TYPE_DEVICE) ? OC_RSRVD_DEVICE_URI : OC_RSRVD_PLATFORM_URI;
1548         OCResource *resource = FindResourceByUri(pathType);
1549         if (!resource)
1550         {
1551             OIC_LOG(ERROR, TAG, "Resource does not exist.");
1552         }
1553         if (value)
1554         {
1555             res = OCSetAttribute(resource, prop, value);
1556         }
1557     }
1558
1559     return res;
1560 }