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