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