Fix query handling for /oic/res
[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)
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 = caglobals.tcp.ipv4.port;
124         }
125         else if (endpoint->flags & OC_IP_USE_V6)
126         {
127             p = 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)
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
363     OCResourceType *resType = resourcePtr->rsrcType;
364     while(resType)
365     {
366         OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename);
367         resType = resType->next;
368     }
369
370     OCResourceInterface *resInterface = resourcePtr->rsrcInterface;
371     while(resInterface)
372     {
373         OCRepPayloadAddInterface(tempPayload, resInterface->name);
374         resInterface = resInterface->next;
375     }
376
377     OCAttribute *resAttrib = resourcePtr->rsrcAttributes;
378     while(resAttrib)
379     {
380         if (resAttrib->attrName && resAttrib->attrValue)
381         {
382             if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, resAttrib->attrName))
383             {
384                 appendOCStringLL(tempPayload, (OCStringLL *)resAttrib->attrValue);
385             }
386             else
387             {
388                 OCRepPayloadSetPropString(tempPayload, resAttrib->attrName, (char *)resAttrib->attrValue);
389             }
390         }
391         resAttrib = resAttrib->next;
392     }
393
394     OCResourceProperty p = OCGetResourceProperties((OCResourceHandle *)resourcePtr);
395     OCRepPayload *policy = OCRepPayloadCreate();
396     if (!policy)
397     {
398         OCPayloadDestroy((OCPayload *)tempPayload);
399         return OC_STACK_NO_MEMORY;
400     }
401     OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, ((p & OC_DISCOVERABLE) | (p & OC_OBSERVABLE)));
402     if (p & OC_SECURE)
403     {
404         OCRepPayloadSetPropBool(policy, OC_RSRVD_SECURE, p & OC_SECURE);
405         uint16_t securePort = 0;
406         if (GetSecurePortInfo(devAddr, &securePort) != OC_STACK_OK)
407         {
408             securePort = 0;
409         }
410         OCRepPayloadSetPropInt(policy, OC_RSRVD_HOSTING_PORT, securePort);
411     }
412     OCRepPayloadSetPropObjectAsOwner(tempPayload, OC_RSRVD_POLICY, policy);
413
414     if(!*payload)
415     {
416         *payload = tempPayload;
417     }
418     else
419     {
420         OCRepPayloadAppend(*payload, tempPayload);
421     }
422
423     return OC_STACK_OK;
424 }
425
426 OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
427                         OCDiscoveryPayload *payload, OCDevAddr *devAddr)
428 {
429     if (!resourcePtr || !payload)
430     {
431         return OC_STACK_INVALID_PARAM;
432     }
433     uint16_t securePort = 0;
434     if (resourcePtr->resourceProperties & OC_SECURE)
435     {
436        if (GetSecurePortInfo(devAddr, &securePort) != OC_STACK_OK)
437        {
438            securePort = 0;
439        }
440     }
441
442 #ifdef TCP_ADAPTER
443     uint16_t tcpPort = 0;
444     if (GetTCPPortInfo(devAddr, &tcpPort) != OC_STACK_OK)
445     {
446         tcpPort = 0;
447     }
448     OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort, tcpPort);
449 #else
450     OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort);
451 #endif
452
453     return OC_STACK_OK;
454 }
455
456 uint8_t IsCollectionResource (OCResource *resource)
457 {
458     if(!resource)
459     {
460         return 0;
461     }
462
463     if(resource->rsrcChildResourcesHead != NULL)
464     {
465         return 1;
466     }
467
468     return 0;
469 }
470
471 OCResource *FindResourceByUri(const char* resourceUri)
472 {
473     if(!resourceUri)
474     {
475         return NULL;
476     }
477
478     OCResource * pointer = headResource;
479     while (pointer)
480     {
481         if (strcmp(resourceUri, pointer->uri) == 0)
482         {
483             return pointer;
484         }
485         pointer = pointer->next;
486     }
487     OIC_LOG_V(INFO, TAG, "Resource %s not found", resourceUri);
488     return NULL;
489 }
490
491
492 OCStackResult DetermineResourceHandling (const OCServerRequest *request,
493                                          ResourceHandling *handling,
494                                          OCResource **resource)
495 {
496     if(!request || !handling || !resource)
497     {
498         return OC_STACK_INVALID_PARAM;
499     }
500
501     OIC_LOG_V(INFO, TAG, "DetermineResourceHandling for %s", request->resourceUrl);
502
503     // Check if virtual resource
504     if (GetTypeOfVirtualURI(request->resourceUrl) != OC_UNKNOWN_URI)
505     {
506         OIC_LOG_V (INFO, TAG, "%s is virtual", request->resourceUrl);
507         *handling = OC_RESOURCE_VIRTUAL;
508         *resource = headResource;
509         return OC_STACK_OK;
510     }
511     if (strlen((const char*)(request->resourceUrl)) == 0)
512     {
513         // Resource URL not specified
514         *handling = OC_RESOURCE_NOT_SPECIFIED;
515         return OC_STACK_NO_RESOURCE;
516     }
517     else
518     {
519         OCResource *resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
520         *resource = resourcePtr;
521         if (!resourcePtr)
522         {
523             if(defaultDeviceHandler)
524             {
525                 *handling = OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER;
526                 return OC_STACK_OK;
527             }
528
529             // Resource does not exist
530             // and default device handler does not exist
531             *handling = OC_RESOURCE_NOT_SPECIFIED;
532             return OC_STACK_NO_RESOURCE;
533         }
534
535         if (IsCollectionResource (resourcePtr))
536         {
537             // Collection resource
538             if (resourcePtr->entityHandler != defaultResourceEHandler)
539             {
540                 *handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
541                 return OC_STACK_OK;
542             }
543             else
544             {
545                 *handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
546                 return OC_STACK_OK;
547             }
548         }
549         else
550         {
551             // Resource not a collection
552             if (resourcePtr->entityHandler != defaultResourceEHandler)
553             {
554                 *handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
555                 return OC_STACK_OK;
556             }
557             else
558             {
559                 *handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
560                 return OC_STACK_OK;
561             }
562         }
563     }
564 }
565
566 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
567 {
568     OCStackResult result;
569
570     switch (ehResult)
571     {
572         case OC_EH_OK:
573         case OC_EH_CONTENT:
574         case OC_EH_VALID:
575             result = OC_STACK_OK;
576             break;
577         case OC_EH_SLOW:
578             result = OC_STACK_SLOW_RESOURCE;
579             break;
580         case OC_EH_ERROR:
581             result = OC_STACK_ERROR;
582             break;
583         case OC_EH_FORBIDDEN:
584             result = OC_STACK_FORBIDDEN_REQ;
585             break;
586         case OC_EH_INTERNAL_SERVER_ERROR:
587             result = OC_STACK_INTERNAL_SERVER_ERROR;
588             break;
589         case OC_EH_RESOURCE_CREATED:
590             result = OC_STACK_RESOURCE_CREATED;
591             break;
592         case OC_EH_RESOURCE_DELETED:
593             result = OC_STACK_RESOURCE_DELETED;
594             break;
595         case OC_EH_CHANGED:
596             result = OC_STACK_RESOURCE_CHANGED;
597             break;
598         case OC_EH_RESOURCE_NOT_FOUND:
599             result = OC_STACK_NO_RESOURCE;
600             break;
601         default:
602             result = OC_STACK_ERROR;
603     }
604
605     return result;
606 }
607
608 static bool resourceMatchesRTFilter(OCResource *resource, char *resourceTypeFilter)
609 {
610     if (!resource)
611     {
612         return false;
613     }
614
615     // Null or empty is analogous to no filter.
616     if (resourceTypeFilter == NULL || *resourceTypeFilter == 0)
617     {
618         return true;
619     }
620
621     OCResourceType *resourceTypePtr = resource->rsrcType;
622
623     while (resourceTypePtr)
624     {
625         if (strcmp (resourceTypePtr->resourcetypename, resourceTypeFilter) == 0)
626         {
627             return true;
628         }
629         resourceTypePtr = resourceTypePtr->next;
630     }
631
632     OIC_LOG_V(INFO, TAG, "%s does not contain rt=%s.", resource->uri, resourceTypeFilter);
633     return false;
634 }
635
636 static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter)
637 {
638     if (!resource)
639     {
640         return false;
641     }
642
643     // Null or empty is analogous to no filter.
644     if (interfaceFilter == NULL || *interfaceFilter == 0)
645     {
646         return true;
647     }
648
649     OCResourceInterface *interfacePtr = resource->rsrcInterface;
650
651     while (interfacePtr)
652     {
653         if (strcmp (interfacePtr->name, interfaceFilter) == 0 ||
654             strcmp (OC_RSRVD_INTERFACE_LL, interfaceFilter) == 0 ||
655             strcmp (OC_RSRVD_INTERFACE_DEFAULT, interfaceFilter) == 0)
656         {
657             return true;
658         }
659         interfacePtr = interfacePtr->next;
660     }
661
662     OIC_LOG_V(INFO, TAG, "%s does not contain if=%s.", resource->uri, interfaceFilter);
663     return false;
664 }
665
666 /*
667  * If the filters are null, they will be assumed to NOT be present
668  * and the resource will not be matched against them.
669  * Function will return true if all non null AND non empty filters passed in find a match.
670  */
671 static bool includeThisResourceInResponse(OCResource *resource,
672                                           char *interfaceFilter,
673                                           char *resourceTypeFilter)
674 {
675     if (!resource)
676     {
677         OIC_LOG(ERROR, TAG, "Invalid resource");
678         return false;
679     }
680
681     if (resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
682     {
683         /*
684          * At least one valid filter should be available to
685          * include the resource in discovery response
686          */
687         if (!(resourceTypeFilter && *resourceTypeFilter))
688         {
689             OIC_LOG_V(INFO, TAG, "%s no query string for EXPLICIT_DISCOVERABLE \
690                 resource", resource->uri);
691             return false;
692         }
693     }
694     else if ( !(resource->resourceProperties & OC_ACTIVE) ||
695          !(resource->resourceProperties & OC_DISCOVERABLE))
696     {
697         OIC_LOG_V(INFO, TAG, "%s not ACTIVE or DISCOVERABLE", resource->uri);
698         return false;
699     }
700
701     return resourceMatchesIFFilter(resource, interfaceFilter) &&
702            resourceMatchesRTFilter(resource, resourceTypeFilter);
703
704 }
705
706 OCStackResult SendNonPersistantDiscoveryResponse(OCServerRequest *request, OCResource *resource,
707                                 OCPayload *discoveryPayload, OCEntityHandlerResult ehResult)
708 {
709     OCEntityHandlerResponse response = {0};
710
711     response.ehResult = ehResult;
712     response.payload = discoveryPayload;
713     response.persistentBufferFlag = 0;
714     response.requestHandle = (OCRequestHandle) request;
715     response.resourceHandle = (OCResourceHandle) resource;
716
717     return OCDoResponse(&response);
718 }
719 #ifdef RD_SERVER
720 /**
721  * Find resource at the resource directory server. This resource is not local resource but a
722  * remote resource.
723  *
724  * @param resource The resource to check the matching resource URI.
725  * @param interfaceQuery The interface query parameter.
726  * @param resourceTypeQuery The resourceType query parameter.
727  * @param discPayload The payload that will be added with the resource information if found at RD.
728  *
729  * @return ::OC_STACK_OK if the resource is found else ::OC_STACK_NO_RESOURCE.
730  * In case if build is not with flag RD_SERVER, it returns ::OC_STACK_NO_RESOURCE.
731  */
732 static OCStackResult findResourceAtRD(const OCResource* resource, const char *interfaceQuery,
733     const char *resourceTypeQuery, OCDiscoveryPayload *discPayload)
734 {
735     if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0)
736     {
737         if (OC_STACK_OK == OCRDDatabaseCheckResources(interfaceQuery, resourceTypeQuery, discPayload))
738         {
739             return OC_STACK_OK;
740         }
741     }
742
743     return OC_STACK_NO_RESOURCE;
744 }
745 #endif
746
747 /**
748  * Creates a discovery payload and add device id information. This information is included in all
749  * /oic/res response.
750  *
751  * @param payload  payload that will have memory alllocated and device id information added.
752  *
753  * @return ::OC_STACK_OK if successful in allocating memory and adding ID information.
754  * ::OC_STACK_NO_MEMORY if failed allocating the memory.
755  */
756 static OCStackResult discoveryPayloadCreateAndAddDeviceId(OCPayload **payload)
757 {
758     if (*payload)
759     {
760         OIC_LOG_V(DEBUG, TAG, "Payload is already allocated");
761         return OC_STACK_OK;
762     }
763
764     *payload = (OCPayload *) OCDiscoveryPayloadCreate();
765     VERIFY_PARAM_NON_NULL(TAG, *payload, "Failed adding device id to discovery payload.");
766
767     {
768         OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)*payload;
769         discPayload->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
770         VERIFY_PARAM_NON_NULL(TAG, discPayload->sid, "Failed adding device id to discovery payload.");
771
772         const char* uid = OCGetServerInstanceIDString();
773         if (uid)
774         {
775             memcpy(discPayload->sid, uid, UUID_STRING_SIZE);
776         }
777
778     }
779     return OC_STACK_OK;
780 exit:
781     OCPayloadDestroy(*payload);
782     return OC_STACK_NO_MEMORY;
783 }
784
785 /**
786  * Add the common properties to the payload, they are only included in case of oic.if.baseline response.
787  *
788  * @param discPayload payload that will have the baseline information included.
789  *
790  * @return ::OC_STACK_OK if successful in adding all the information. ::OC_STACK_NO_MEMORY if failed
791  * allocating the memory for the baseline information.
792  */
793 static OCStackResult addDiscoveryBaselineCommonProperties(OCDiscoveryPayload *discPayload)
794 {
795     discPayload->uri = OICStrdup(OC_RSRVD_WELL_KNOWN_URI);
796     VERIFY_PARAM_NON_NULL(TAG, discPayload->uri, "Failed adding href to discovery payload.");
797
798     OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, "deviceName", (void **)&discPayload->name);
799
800     discPayload->type = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
801     VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt to discovery payload.");
802     discPayload->type->value = OICStrdup(OC_RSRVD_RESOURCE_TYPE_RES);
803     VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt value to discovery payload.");
804
805     OCResourcePayloadAddStringLL(&discPayload->iface, OC_RSRVD_INTERFACE_LL);
806     OCResourcePayloadAddStringLL(&discPayload->iface, OC_RSRVD_INTERFACE_DEFAULT);
807     VERIFY_PARAM_NON_NULL(TAG, discPayload->iface, "Failed adding if to discovery payload.");
808
809     return OC_STACK_OK;
810
811 exit:
812     return OC_STACK_NO_MEMORY;
813 }
814
815 static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource)
816 {
817     if (!request || !resource)
818     {
819         return OC_STACK_INVALID_PARAM;
820     }
821
822     OCStackResult discoveryResult = OC_STACK_ERROR;
823     if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
824         request->method == OC_REST_DELETE)
825     {
826         OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
827             request->resourceUrl, request->method);
828         return OC_STACK_UNAUTHORIZED_REQ;
829     }
830
831     OCPayload* payload = NULL;
832     char *interfaceQuery = NULL;
833     char *resourceTypeQuery = NULL;
834     char *dataModelVersions = NULL;
835
836     OIC_LOG(INFO, TAG, "Entering HandleVirtualResource");
837
838     OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
839
840     // Step 1: Generate the response to discovery request
841     if (virtualUriInRequest == OC_WELL_KNOWN_URI
842 #ifdef MQ_BROKER
843             || virtualUriInRequest == OC_MQ_BROKER_URI
844 #endif
845             )
846     {
847         discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
848                 &interfaceQuery, &resourceTypeQuery);
849         VERIFY_SUCCESS(discoveryResult);
850         if (!interfaceQuery && !resourceTypeQuery)
851         {
852             // If no query is sent, default interface is used i.e. oic.if.ll.
853             interfaceQuery = OICStrdup(OC_RSRVD_INTERFACE_LL);
854         }
855
856         bool baselineQuery = false;
857         if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT))
858         {
859             baselineQuery = true;
860         }
861
862         discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload);
863         VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload.");
864         VERIFY_SUCCESS(discoveryResult);
865
866         OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
867         if (baselineQuery)
868         {
869             discoveryResult = addDiscoveryBaselineCommonProperties(discPayload);
870             VERIFY_SUCCESS(discoveryResult);
871         }
872         OCResourceProperty prop = OC_DISCOVERABLE;
873 #ifdef MQ_BROKER
874         prop = (OC_MQ_BROKER_URI == virtualUriInRequest) ? OC_MQ_BROKER : prop;
875 #endif
876         for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
877         {
878             discoveryResult = OC_STACK_NO_RESOURCE;
879 #ifdef RD_SERVER
880             discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery,
881                 discPayload);
882 #endif
883             if (OC_STACK_NO_RESOURCE == discoveryResult)
884             {
885                 // This case will handle when no resource type and it is oic.if.ll.
886                 if (!resourceTypeQuery && !baselineQuery && (resource->resourceProperties & prop))
887                 {
888                     discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
889                 }
890                 else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery))
891                 {
892                     discoveryResult = BuildVirtualResourceResponse(resource, discPayload, &request->devAddr);
893                 }
894                 else
895                 {
896                     discoveryResult = OC_STACK_OK;
897                 }
898             }
899         }
900         if (discPayload->resources == NULL)
901         {
902             discoveryResult = OC_STACK_NO_RESOURCE;
903         }
904     }
905     else if (virtualUriInRequest == OC_DEVICE_URI)
906     {
907         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_DEVICE_URI);
908         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Device URI not found.");
909         discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, &request->devAddr);
910     }
911     else if (virtualUriInRequest == OC_PLATFORM_URI)
912     {
913         OCResource *resourcePtr = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
914         VERIFY_PARAM_NON_NULL(TAG, resourcePtr, "Platform URI not found.");
915         discoveryResult = BuildResponseRepresentation(resourcePtr, (OCRepPayload **)&payload, &request->devAddr);
916     }
917 #ifdef ROUTING_GATEWAY
918     else if (OC_GATEWAY_URI == virtualUriInRequest)
919     {
920         // Received request for a gateway
921         OIC_LOG(INFO, TAG, "Request is for Gateway Virtual Request");
922         discoveryResult = RMHandleGatewayRequest(request, resource);
923     }
924 #endif
925 #ifdef TCP_ADAPTER
926     else if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
927     {
928         // Received request for a keepalive
929         OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
930         discoveryResult = HandleKeepAliveRequest(request, resource);
931     }
932 #endif
933     /**
934      * Step 2: Send the discovery response
935      *
936      * Iotivity should respond to discovery requests in below manner:
937      * 1)If query filter matching fails and discovery request is multicast,
938      *   it should NOT send any response.
939      * 2)If query filter matching fails and discovery request is unicast,
940      *   it should send an error(RESOURCE_NOT_FOUND - 404) response.
941      * 3)If Server does not have any 'DISCOVERABLE' resources and discovery
942      *   request is multicast, it should NOT send any response.
943      * 4)If Server does not have any 'DISCOVERABLE' resources and discovery
944      *   request is unicast, it should send an error(RESOURCE_NOT_FOUND - 404) response.
945      */
946
947 #ifdef WITH_PRESENCE
948     if ((virtualUriInRequest == OC_PRESENCE) &&
949         (resource->resourceProperties & OC_ACTIVE))
950     {
951         // Need to send ACK when the request is CON.
952         if (request->qos == OC_HIGH_QOS)
953         {
954             CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
955             CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
956             SendDirectStackResponse(&endpoint, request->coapID, CA_EMPTY, CA_MSG_ACKNOWLEDGE,
957                                     0, NULL, NULL, 0, NULL, CA_RESPONSE_FOR_RES);
958         }
959         FindAndDeleteServerRequest(request);
960
961         // Presence uses observer notification api to respond via SendPresenceNotification.
962         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
963     }
964     else
965 #endif
966 #if ROUTING_GATEWAY
967     // Gateway uses the RMHandleGatewayRequest to respond to the request.
968     if (OC_GATEWAY_URI != virtualUriInRequest)
969 #endif
970     {
971 #if TCP_ADAPTER
972         // KeepAlive uses the HandleKeepAliveRequest to respond to the request.
973         if (OC_KEEPALIVE_RESOURCE_URI != virtualUriInRequest)
974 #endif
975         {
976             OIC_LOG_PAYLOAD(DEBUG, payload);
977             if(discoveryResult == OC_STACK_OK)
978             {
979                 SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
980             }
981             else if(((request->devAddr.flags &  OC_MULTICAST) == false) &&
982                 (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
983                 (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
984             {
985                 OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request",
986                     discoveryResult, virtualUriInRequest);
987                 SendNonPersistantDiscoveryResponse(request, resource, NULL,
988                     (discoveryResult == OC_STACK_NO_RESOURCE) ?
989                             OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
990             }
991             else
992             {
993                 // Ignoring the discovery request as per RFC 7252, Section #8.2
994                 OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send.");
995                 // the request should be removed.
996                 // since it never remove and causes a big memory waste.
997                 FindAndDeleteServerRequest(request);
998             }
999         }
1000     }
1001
1002 exit:
1003     if (interfaceQuery)
1004     {
1005         OICFree(interfaceQuery);
1006     }
1007
1008     if (resourceTypeQuery)
1009     {
1010         OICFree(resourceTypeQuery);
1011     }
1012     OCPayloadDestroy(payload);
1013     if (dataModelVersions)
1014     {
1015         OICFree(dataModelVersions);
1016     }
1017     return discoveryResult;
1018 }
1019
1020 static OCStackResult
1021 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
1022 {
1023     if(!request)
1024     {
1025         return OC_STACK_INVALID_PARAM;
1026     }
1027
1028     OCStackResult result = OC_STACK_OK;
1029     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1030     OCEntityHandlerRequest ehRequest = {0};
1031
1032     OIC_LOG(INFO, TAG, "Entering HandleResourceWithDefaultDeviceEntityHandler");
1033     result = FormOCEntityHandlerRequest(&ehRequest,
1034                                         (OCRequestHandle) request,
1035                                         request->method,
1036                                         &request->devAddr,
1037                                         (OCResourceHandle) NULL, request->query,
1038                                         PAYLOAD_TYPE_REPRESENTATION,
1039                                         request->payload,
1040                                         request->payloadSize,
1041                                         request->numRcvdVendorSpecificHeaderOptions,
1042                                         request->rcvdVendorSpecificHeaderOptions,
1043                                         (OCObserveAction)request->observationOption,
1044                                         (OCObservationId)0,
1045                                         request->coapID);
1046     VERIFY_SUCCESS(result);
1047
1048     // At this point we know for sure that defaultDeviceHandler exists
1049     ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
1050                                   (char*) request->resourceUrl, defaultDeviceHandlerCallbackParameter);
1051     if(ehResult == OC_EH_SLOW)
1052     {
1053         OIC_LOG(INFO, TAG, "This is a slow resource");
1054         request->slowFlag = 1;
1055     }
1056     else if(ehResult == OC_EH_ERROR)
1057     {
1058         FindAndDeleteServerRequest(request);
1059     }
1060     result = EntityHandlerCodeToOCStackCode(ehResult);
1061 exit:
1062     OCPayloadDestroy(ehRequest.payload);
1063     return result;
1064 }
1065
1066 static OCStackResult
1067 HandleResourceWithEntityHandler (OCServerRequest *request,
1068                                  OCResource *resource,
1069                                  uint8_t collectionResource)
1070 {
1071     OC_UNUSED(collectionResource);
1072
1073     if(!request || ! resource)
1074     {
1075         return OC_STACK_INVALID_PARAM;
1076     }
1077
1078     OCStackResult result = OC_STACK_ERROR;
1079     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1080     OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
1081     ResourceObserver *resObs = NULL;
1082
1083     OCEntityHandlerRequest ehRequest = {0};
1084
1085     OIC_LOG(INFO, TAG, "Entering HandleResourceWithEntityHandler");
1086     OCPayloadType type = PAYLOAD_TYPE_REPRESENTATION;
1087     // check the security resource
1088     if (request && request->resourceUrl && SRMIsSecurityResourceURI(request->resourceUrl))
1089     {
1090         type = PAYLOAD_TYPE_SECURITY;
1091
1092     }
1093
1094     result = FormOCEntityHandlerRequest(&ehRequest,
1095                                         (OCRequestHandle)request,
1096                                         request->method,
1097                                         &request->devAddr,
1098                                         (OCResourceHandle)resource,
1099                                         request->query,
1100                                         type,
1101                                         request->payload,
1102                                         request->payloadSize,
1103                                         request->numRcvdVendorSpecificHeaderOptions,
1104                                         request->rcvdVendorSpecificHeaderOptions,
1105                                         (OCObserveAction)request->observationOption,
1106                                         0,
1107                                         request->coapID);
1108     VERIFY_SUCCESS(result);
1109
1110     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
1111     {
1112         OIC_LOG(INFO, TAG, "No observation requested");
1113         ehFlag = OC_REQUEST_FLAG;
1114     }
1115     else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER)
1116     {
1117         OIC_LOG(INFO, TAG, "Observation registration requested");
1118
1119         ResourceObserver *obs = GetObserverUsingToken (request->requestToken,
1120                                     request->tokenLength);
1121
1122         if (obs)
1123         {
1124             OIC_LOG (INFO, TAG, "Observer with this token already present");
1125             OIC_LOG (INFO, TAG, "Possibly re-transmitted CON OBS request");
1126             OIC_LOG (INFO, TAG, "Not adding observer. Not responding to client");
1127             OIC_LOG (INFO, TAG, "The first request for this token is already ACKED.");
1128
1129             // server requests are usually free'd when the response is sent out
1130             // for the request in ocserverrequest.c : HandleSingleResponse()
1131             // Since we are making an early return and not responding, the server request
1132             // needs to be deleted.
1133             FindAndDeleteServerRequest (request);
1134             return OC_STACK_OK;
1135         }
1136
1137         result = GenerateObserverId(&ehRequest.obsInfo.obsId);
1138         VERIFY_SUCCESS(result);
1139
1140         result = AddObserver ((const char*)(request->resourceUrl),
1141                 (const char *)(request->query),
1142                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
1143                 resource, request->qos, request->acceptFormat,
1144                 &request->devAddr);
1145
1146         if(result == OC_STACK_OK)
1147         {
1148             OIC_LOG(INFO, TAG, "Added observer successfully");
1149             request->observeResult = OC_STACK_OK;
1150             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
1151         }
1152         else if (result == OC_STACK_RESOURCE_ERROR)
1153         {
1154             OIC_LOG(INFO, TAG, "The Resource is not active, discoverable or observable");
1155             request->observeResult = OC_STACK_ERROR;
1156             ehFlag = OC_REQUEST_FLAG;
1157         }
1158         else
1159         {
1160             // The error in observeResult for the request will be used when responding to this
1161             // request by omitting the observation option/sequence number.
1162             request->observeResult = OC_STACK_ERROR;
1163             OIC_LOG(ERROR, TAG, "Observer Addition failed");
1164             ehFlag = OC_REQUEST_FLAG;
1165             FindAndDeleteServerRequest(request);
1166             goto exit;
1167         }
1168
1169     }
1170     else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER)
1171     {
1172         OIC_LOG(INFO, TAG, "Deregistering observation requested");
1173
1174         resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
1175
1176         if (NULL == resObs)
1177         {
1178             // Stack does not contain this observation request
1179             // Either token is incorrect or observation list is corrupted
1180             result = OC_STACK_ERROR;
1181             goto exit;
1182         }
1183         ehRequest.obsInfo.obsId = resObs->observeId;
1184         ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
1185
1186         result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
1187
1188         if(result == OC_STACK_OK)
1189         {
1190             OIC_LOG(INFO, TAG, "Removed observer successfully");
1191             request->observeResult = OC_STACK_OK;
1192             // There should be no observe option header for de-registration response.
1193             // Set as an invalid value here so we can detect it later and remove the field in response.
1194             request->observationOption = MAX_SEQUENCE_NUMBER + 1;
1195         }
1196         else
1197         {
1198             request->observeResult = OC_STACK_ERROR;
1199             OIC_LOG(ERROR, TAG, "Observer Removal failed");
1200             FindAndDeleteServerRequest(request);
1201             goto exit;
1202         }
1203     }
1204     else
1205     {
1206         result = OC_STACK_ERROR;
1207         goto exit;
1208     }
1209
1210     ehResult = resource->entityHandler(ehFlag, &ehRequest, resource->entityHandlerCallbackParam);
1211     if(ehResult == OC_EH_SLOW)
1212     {
1213         OIC_LOG(INFO, TAG, "This is a slow resource");
1214         request->slowFlag = 1;
1215     }
1216     else if(ehResult == OC_EH_ERROR)
1217     {
1218         FindAndDeleteServerRequest(request);
1219     }
1220     result = EntityHandlerCodeToOCStackCode(ehResult);
1221 exit:
1222     OCPayloadDestroy(ehRequest.payload);
1223     return result;
1224 }
1225
1226 static OCStackResult
1227 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
1228                                               OCResource *resource)
1229 {
1230     if(!request || !resource)
1231     {
1232         return OC_STACK_INVALID_PARAM;
1233     }
1234
1235     OCStackResult result = OC_STACK_ERROR;
1236     OCEntityHandlerRequest ehRequest = {0};
1237
1238     result = FormOCEntityHandlerRequest(&ehRequest,
1239                                         (OCRequestHandle)request,
1240                                         request->method,
1241                                         &request->devAddr,
1242                                         (OCResourceHandle)resource,
1243                                         request->query,
1244                                         PAYLOAD_TYPE_REPRESENTATION,
1245                                         request->payload,
1246                                         request->payloadSize,
1247                                         request->numRcvdVendorSpecificHeaderOptions,
1248                                         request->rcvdVendorSpecificHeaderOptions,
1249                                         (OCObserveAction)request->observationOption,
1250                                         (OCObservationId)0,
1251                                         request->coapID);
1252     if(result == OC_STACK_OK)
1253     {
1254         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
1255     }
1256
1257     OCPayloadDestroy(ehRequest.payload);
1258     return result;
1259 }
1260
1261 OCStackResult
1262 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
1263 {
1264     OCStackResult ret = OC_STACK_OK;
1265
1266     switch (resHandling)
1267     {
1268         case OC_RESOURCE_VIRTUAL:
1269         {
1270             ret = HandleVirtualResource (request, resource);
1271             break;
1272         }
1273         case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
1274         {
1275             ret = HandleDefaultDeviceEntityHandler(request);
1276             break;
1277         }
1278         case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
1279         {
1280             OIC_LOG(INFO, TAG, "OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER");
1281             return OC_STACK_ERROR;
1282         }
1283         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
1284         {
1285             ret = HandleResourceWithEntityHandler (request, resource, 0);
1286             break;
1287         }
1288         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
1289         {
1290             ret = HandleResourceWithEntityHandler (request, resource, 1);
1291             break;
1292         }
1293         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
1294         {
1295             ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
1296             break;
1297         }
1298         case OC_RESOURCE_NOT_SPECIFIED:
1299         {
1300             ret = OC_STACK_NO_RESOURCE;
1301             break;
1302         }
1303         default:
1304         {
1305             OIC_LOG(INFO, TAG, "Invalid Resource Determination");
1306             return OC_STACK_ERROR;
1307         }
1308     }
1309     return ret;
1310 }
1311
1312 OCStackResult OCSetPlatformInfo(OCPlatformInfo info)
1313 {
1314     OCResource *resource = NULL;
1315     if (!info.platformID || !info.manufacturerName)
1316     {
1317         OIC_LOG(ERROR, TAG, "No value specified.");
1318         goto exit;
1319     }
1320     if (0 == strlen(info.platformID) || 0 == strlen(info.manufacturerName))
1321     {
1322         OIC_LOG(ERROR, TAG, "The passed value cannot be empty");
1323         goto exit;
1324     }
1325     if ((info.manufacturerName && strlen(info.manufacturerName) > MAX_PLATFORM_NAME_LENGTH) ||
1326         (info.manufacturerUrl && strlen(info.manufacturerUrl) > MAX_PLATFORM_URL_LENGTH) ||
1327         (info.modelNumber && strlen(info.modelNumber) > MAX_PLATFORM_NAME_LENGTH) ||
1328         (info.platformVersion && strlen(info.platformVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1329         (info.operatingSystemVersion && strlen(info.operatingSystemVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1330         (info.hardwareVersion && strlen(info.hardwareVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1331         (info.firmwareVersion && strlen(info.firmwareVersion) > MAX_PLATFORM_NAME_LENGTH) ||
1332         (info.supportUrl && strlen(info.supportUrl) > MAX_PLATFORM_URL_LENGTH))
1333     {
1334         OIC_LOG(ERROR, TAG, "The passed value is bigger than permitted.");
1335         goto exit;
1336     }
1337
1338     resource = FindResourceByUri(OC_RSRVD_PLATFORM_URI);
1339     if (!resource)
1340     {
1341         OIC_LOG(ERROR, TAG, "Platform Resource does not exist.");
1342         goto exit;
1343     }
1344     OIC_LOG(INFO, TAG, "Entering OCSetPlatformInfo");
1345     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_PLATFORM_ID, info.platformID));
1346     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_NAME, info.manufacturerName));
1347     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_URL, info.manufacturerUrl);
1348     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MODEL_NUM, info.modelNumber);
1349     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_MFG_DATE, info.dateOfManufacture);
1350     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_PLATFORM_VERSION, info.platformVersion);
1351     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_OS_VERSION, info.operatingSystemVersion);
1352     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_HARDWARE_VERSION, info.hardwareVersion);
1353     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_FIRMWARE_VERSION, info.firmwareVersion);
1354     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_SUPPORT_URL, info.supportUrl);
1355     OCSetPropertyValue(PAYLOAD_TYPE_PLATFORM, OC_RSRVD_SYSTEM_TIME, info.systemTime);
1356     OIC_LOG(INFO, TAG, "Platform parameter initialized successfully.");
1357     return OC_STACK_OK;
1358
1359 exit:
1360     return OC_STACK_INVALID_PARAM;
1361 }
1362
1363 OCStackResult OCSetDeviceInfo(OCDeviceInfo info)
1364 {
1365     OCStringLL *dataModelVersion = NULL;
1366     OCResource *resource = FindResourceByUri(OC_RSRVD_DEVICE_URI);
1367     if (!resource)
1368     {
1369         OIC_LOG(ERROR, TAG, "Device Resource does not exist.");
1370         goto exit;
1371     }
1372     if (!info.deviceName || info.deviceName[0] == '\0')
1373     {
1374         OIC_LOG(ERROR, TAG, "Null or empty device name.");
1375        return OC_STACK_INVALID_PARAM;
1376     }
1377
1378     if (OCGetServerInstanceIDString() == NULL)
1379     {
1380         OIC_LOG(INFO, TAG, "Device ID generation failed");
1381         goto exit;
1382     }
1383
1384     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, info.deviceName));
1385     for (OCStringLL *temp = info.types; temp; temp = temp->next)
1386     {
1387         if (temp->value)
1388         {
1389             VERIFY_SUCCESS(OCBindResourceTypeToResource(resource, temp->value));
1390         }
1391     }
1392     VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, info.specVersion ?
1393         info.specVersion: OC_SPEC_VERSION));
1394     if (info.dataModelVersions)
1395     {
1396         VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, info.dataModelVersions));
1397     }
1398     else
1399     {
1400         dataModelVersion = OCCreateOCStringLL(OC_DATA_MODEL_VERSION);
1401         VERIFY_SUCCESS(OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION, dataModelVersion));
1402     }
1403     OIC_LOG(INFO, TAG, "Device parameter initialized successfully.");
1404     return OC_STACK_OK;
1405
1406 exit:
1407     if (dataModelVersion)
1408     {
1409         OCFreeOCStringLL(dataModelVersion);
1410     }
1411     return OC_STACK_ERROR;
1412 }
1413
1414 OCStackResult OCGetAttribute(const OCResource *resource, const char *attribute, void **value)
1415 {
1416     if (!resource || !attribute)
1417     {
1418         return OC_STACK_INVALID_PARAM;
1419     }
1420     if (0 == strlen(attribute))
1421     {
1422         return OC_STACK_INVALID_PARAM;
1423     }
1424     for (OCAttribute *temp = resource->rsrcAttributes; temp; temp = temp->next)
1425     {
1426         if (0 == strcmp(attribute, temp->attrName))
1427         {
1428             // A special case as this type return OCStringLL
1429             if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
1430             {
1431                 *value = CloneOCStringLL((OCStringLL *)temp->attrValue);
1432                 return OC_STACK_OK;
1433             }
1434             else
1435             {
1436                 *value = OICStrdup((char *)temp->attrValue);
1437                 return OC_STACK_OK;
1438             }
1439         }
1440     }
1441     return OC_STACK_NO_RESOURCE;
1442 }
1443
1444 OCStackResult OCGetPropertyValue(OCPayloadType type, const char *prop, void **value)
1445 {
1446     if (!prop || *value)
1447     {
1448         return OC_STACK_INVALID_PARAM;
1449     }
1450     if (strlen(prop) == 0)
1451     {
1452         return OC_STACK_INVALID_PARAM;
1453     }
1454     OCStackResult res =  OC_STACK_NO_RESOURCE;
1455     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
1456     {
1457         const char *pathType = (type == PAYLOAD_TYPE_DEVICE) ? OC_RSRVD_DEVICE_URI : OC_RSRVD_PLATFORM_URI;
1458         OCResource *resource = FindResourceByUri(pathType);
1459         if (!resource)
1460         {
1461             return OC_STACK_NO_RESOURCE;
1462         }
1463
1464         res = OCGetAttribute(resource, prop, value);
1465     }
1466     return res;
1467 }
1468
1469 OCStackResult OCSetAttribute(OCResource* resource, const char* attribute, const void* value)
1470 {
1471     OCAttribute *resAttrib = (OCAttribute *)OICCalloc(1, sizeof(OCAttribute));
1472     VERIFY_PARAM_NON_NULL(TAG, resAttrib, "Failed allocation OCAttribute");
1473     resAttrib->attrName = OICStrdup(attribute);
1474     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrName, "Failed allocating attribute name");
1475     // A special case when value is of type OCStringLL
1476     if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, attribute))
1477     {
1478         resAttrib->attrValue = CloneOCStringLL((OCStringLL *)value);
1479     }
1480     else
1481     {
1482         resAttrib->attrValue = OICStrdup((char *)value);
1483     }
1484     VERIFY_PARAM_NON_NULL(TAG, resAttrib->attrValue, "Failed allocating attribute value");
1485     resAttrib->next = NULL;
1486
1487     if (!resource->rsrcAttributes)
1488     {
1489         resource->rsrcAttributes = resAttrib;
1490     }
1491     else
1492     {
1493         OCAttribute *temp = resource->rsrcAttributes;
1494         for (; temp->next; temp = temp->next)
1495         {
1496             if (0 == strcmp(attribute, temp->attrName))
1497             {
1498                 if (0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, temp->attrName))
1499                 {
1500                     OCFreeOCStringLL((OCStringLL *)temp->attrValue);
1501                 }
1502                  {
1503                     OICFree((char *)temp->attrValue);
1504                 }
1505                 break;
1506             }
1507         }
1508         temp->next = resAttrib;
1509     }
1510     return OC_STACK_OK;
1511
1512 exit:
1513     OCDeleteResourceAttributes(resAttrib);
1514     return OC_STACK_NO_MEMORY;
1515
1516 }
1517
1518 OCStackResult OCSetPropertyValue(OCPayloadType type, const char *prop, const void *value)
1519 {
1520     if (!prop)
1521     {
1522         return OC_STACK_INVALID_PARAM;
1523     }
1524     if (strlen(prop) == 0)
1525     {
1526         return OC_STACK_INVALID_PARAM;
1527     }
1528
1529     OCStackResult res = OC_STACK_ERROR;
1530     if (PAYLOAD_TYPE_DEVICE == type || PAYLOAD_TYPE_PLATFORM == type)
1531     {
1532         const char *pathType = (type == PAYLOAD_TYPE_DEVICE) ? OC_RSRVD_DEVICE_URI : OC_RSRVD_PLATFORM_URI;
1533         OCResource *resource = FindResourceByUri(pathType);
1534         if (!resource)
1535         {
1536             OIC_LOG(ERROR, TAG, "Resource does not exist.");
1537         }
1538         if (value)
1539         {
1540             res = OCSetAttribute(resource, prop, value);
1541         }
1542     }
1543
1544     return res;
1545 }