Fix Discovery issue with OCResource
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocresource.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2001 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2001 base specification,
26 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
27 #define _POSIX_C_SOURCE 200112L
28 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE
30 #endif
31
32 #include "iotivity_config.h"
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39
40 #include "ocresource.h"
41 #include "ocresourcehandler.h"
42 #include "ocobserve.h"
43 #include "occollection.h"
44 #include "oic_malloc.h"
45 #include "oic_string.h"
46 #include "logger.h"
47 #include "cJSON.h"
48 #include "ocpayload.h"
49 #include "secureresourcemanager.h"
50 #include "cacommon.h"
51 #include "cainterface.h"
52 #include "ocpayload.h"
53 #include "platform_features.h"
54 #include "payload_logging.h"
55 #ifdef ROUTING_GATEWAY
56 #include "routingmanager.h"
57 #endif
58
59 #ifdef RD_SERVER
60 #include "rd_database.h"
61 #endif
62
63 /// Module Name
64 #define TAG "OIC_RI_RESOURCE"
65
66 #define VERIFY_SUCCESS(op, 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 ::OC_STACK_OK if successful in allocating memory and adding ID information.
704  * ::OC_STACK_NO_MEMORY if failed allocating the memory.
705  */
706 static OCStackResult discoveryPayloadCreateAndAddDeviceId(OCPayload **payload)
707 {
708     if (*payload)
709     {
710         OIC_LOG_V(DEBUG, TAG, "Payload is already allocated");
711         return OC_STACK_OK;
712     }
713
714     *payload = (OCPayload *) OCDiscoveryPayloadCreate();
715     VERIFY_PARAM_NON_NULL(TAG, *payload, "Failed adding device id to 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     }
729     return OC_STACK_OK;
730 exit:
731     OCPayloadDestroy(*payload);
732     return OC_STACK_NO_MEMORY;
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             discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload);
819             VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload.");
820             VERIFY_SUCCESS(discoveryResult, OC_STACK_OK);
821
822             OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
823             if (baselineQuery)
824             {
825                 discoveryResult = addDiscoveryBaselineCommonProperties(discPayload);
826                 VERIFY_SUCCESS(discoveryResult, OC_STACK_OK);
827             }
828             OCResourceProperty prop = OC_DISCOVERABLE;
829 #ifdef MQ_BROKER
830             prop = (OC_MQ_BROKER_URI == virtualUriInRequest) ? OC_MQ_BROKER : prop;
831 #endif
832             for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
833             {
834                 discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery,
835                     discPayload);
836                 if (OC_STACK_NO_RESOURCE == discoveryResult)
837                 {
838                     if ((!baselineQuery && (resource->resourceProperties & prop)) ||
839                         (baselineQuery && (includeThisResourceInResponse(resource, interfaceQuery,
840                                                                          resourceTypeQuery))))
841                     {
842                         discoveryResult = BuildVirtualResourceResponse(resource, discPayload,
843                             &request->devAddr);
844                     }
845                     else
846                     {
847                         discoveryResult = OC_STACK_OK;
848                     }
849                 }
850             }
851             if (discPayload->resources == NULL)
852             {
853                 discoveryResult = OC_STACK_NO_RESOURCE;
854             }
855         }
856     }
857     else if (virtualUriInRequest == OC_DEVICE_URI)
858     {
859         if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
860             request->method == OC_REST_DELETE)
861         {
862             OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
863                 request->resourceUrl, request->method);
864             discoveryResult = OC_STACK_UNAUTHORIZED_REQ;
865             goto exit;
866         }
867
868         const char* deviceId = OCGetServerInstanceIDString();
869         VERIFY_PARAM_NON_NULL(TAG, deviceId, "Failed retrieving device id.");
870         discoveryResult = OC_STACK_NO_MEMORY;
871         dataModelVersions = OCCreateString(savedDeviceInfo.dataModelVersions);
872         VERIFY_PARAM_NON_NULL(TAG, dataModelVersions, "Failed adding data model version.");
873         payload = (OCPayload*) OCDevicePayloadCreate(deviceId, savedDeviceInfo.deviceName,
874             savedDeviceInfo.types, savedDeviceInfo.specVersion, dataModelVersions);
875         VERIFY_PARAM_NON_NULL(TAG, payload, "Failed adding device payload.");
876     }
877     else if (virtualUriInRequest == OC_PLATFORM_URI)
878     {
879         if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
880             request->method == OC_REST_DELETE)
881         {
882             OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
883                 request->resourceUrl, request->method);
884             discoveryResult = OC_STACK_UNAUTHORIZED_REQ;
885             goto exit;
886         }
887
888         discoveryResult = OC_STACK_NO_MEMORY;
889         payload = (OCPayload *)OCPlatformPayloadCreate(&savedPlatformInfo);
890         VERIFY_PARAM_NON_NULL(TAG, payload, "Failed adding platform payload.");
891    }
892 #ifdef ROUTING_GATEWAY
893     else if (OC_GATEWAY_URI == virtualUriInRequest)
894     {
895         // Received request for a gateway
896         OIC_LOG(INFO, TAG, "Request is for Gateway Virtual Request");
897         discoveryResult = RMHandleGatewayRequest(request, resource);
898     }
899 #endif
900 #ifdef TCP_ADAPTER
901     else if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
902     {
903         // Received request for a keepalive
904         OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
905         discoveryResult = HandleKeepAliveRequest(request, resource);
906     }
907 #endif
908     /**
909      * Step 2: Send the discovery response
910      *
911      * Iotivity should respond to discovery requests in below manner:
912      * 1)If query filter matching fails and discovery request is multicast,
913      *   it should NOT send any response.
914      * 2)If query filter matching fails and discovery request is unicast,
915      *   it should send an error(RESOURCE_NOT_FOUND - 404) response.
916      * 3)If Server does not have any 'DISCOVERABLE' resources and discovery
917      *   request is multicast, it should NOT send any response.
918      * 4)If Server does not have any 'DISCOVERABLE' resources and discovery
919      *   request is unicast, it should send an error(RESOURCE_NOT_FOUND - 404) response.
920      */
921
922 #ifdef WITH_PRESENCE
923     if ((virtualUriInRequest == OC_PRESENCE) &&
924         (resource->resourceProperties & OC_ACTIVE))
925     {
926         // Need to send ACK when the request is CON.
927         if (request->qos == OC_HIGH_QOS)
928         {
929             CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
930             CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
931             SendDirectStackResponse(&endpoint, request->coapID, CA_EMPTY, CA_MSG_ACKNOWLEDGE,
932                                     0, NULL, NULL, 0, NULL, CA_RESPONSE_FOR_RES);
933         }
934         FindAndDeleteServerRequest(request);
935
936         // Presence uses observer notification api to respond via SendPresenceNotification.
937         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
938     }
939     else
940 #endif
941 #if ROUTING_GATEWAY
942     // Gateway uses the RMHandleGatewayRequest to respond to the request.
943     if (OC_GATEWAY_URI != virtualUriInRequest)
944 #endif
945     {
946 #if TCP_ADAPTER
947         // KeepAlive uses the HandleKeepAliveRequest to respond to the request.
948         if (OC_KEEPALIVE_RESOURCE_URI != virtualUriInRequest)
949 #endif
950         {
951             OIC_LOG_PAYLOAD(DEBUG, payload);
952             if(discoveryResult == OC_STACK_OK)
953             {
954                 SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
955             }
956             else if(((request->devAddr.flags &  OC_MULTICAST) == false) &&
957                 (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
958                 (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
959             {
960                 OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request",
961                     discoveryResult, virtualUriInRequest);
962                 SendNonPersistantDiscoveryResponse(request, resource, NULL,
963                     (discoveryResult == OC_STACK_NO_RESOURCE) ?
964                             OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
965             }
966             else
967             {
968                 // Ignoring the discovery request as per RFC 7252, Section #8.2
969                 OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send.");
970                 // the request should be removed.
971                 // since it never remove and causes a big memory waste.
972                 FindAndDeleteServerRequest(request);
973             }
974         }
975     }
976
977 exit:
978     if (interfaceQuery)
979     {
980         OICFree(interfaceQuery);
981     }
982
983     if (resourceTypeQuery)
984     {
985         OICFree(resourceTypeQuery);
986     }
987     OCPayloadDestroy(payload);
988     if (dataModelVersions)
989     {
990         OICFree(dataModelVersions);
991     }
992     return discoveryResult;
993 }
994
995 static OCStackResult
996 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
997 {
998     if(!request)
999     {
1000         return OC_STACK_INVALID_PARAM;
1001     }
1002
1003     OCStackResult result = OC_STACK_OK;
1004     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1005     OCEntityHandlerRequest ehRequest = {0};
1006
1007     OIC_LOG(INFO, TAG, "Entering HandleResourceWithDefaultDeviceEntityHandler");
1008     result = FormOCEntityHandlerRequest(&ehRequest,
1009                                         (OCRequestHandle) request,
1010                                         request->method,
1011                                         &request->devAddr,
1012                                         (OCResourceHandle) NULL, request->query,
1013                                         PAYLOAD_TYPE_REPRESENTATION,
1014                                         request->payload,
1015                                         request->payloadSize,
1016                                         request->numRcvdVendorSpecificHeaderOptions,
1017                                         request->rcvdVendorSpecificHeaderOptions,
1018                                         (OCObserveAction)request->observationOption,
1019                                         (OCObservationId)0,
1020                                         request->coapID);
1021     VERIFY_SUCCESS(result, OC_STACK_OK);
1022
1023     // At this point we know for sure that defaultDeviceHandler exists
1024     ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
1025                                   (char*) request->resourceUrl, defaultDeviceHandlerCallbackParameter);
1026     if(ehResult == OC_EH_SLOW)
1027     {
1028         OIC_LOG(INFO, TAG, "This is a slow resource");
1029         request->slowFlag = 1;
1030     }
1031     else if(ehResult == OC_EH_ERROR)
1032     {
1033         FindAndDeleteServerRequest(request);
1034     }
1035     result = EntityHandlerCodeToOCStackCode(ehResult);
1036 exit:
1037     OCPayloadDestroy(ehRequest.payload);
1038     return result;
1039 }
1040
1041 static OCStackResult
1042 HandleResourceWithEntityHandler (OCServerRequest *request,
1043                                  OCResource *resource,
1044                                  uint8_t collectionResource)
1045 {
1046     OC_UNUSED(collectionResource);
1047
1048     if(!request || ! resource)
1049     {
1050         return OC_STACK_INVALID_PARAM;
1051     }
1052
1053     OCStackResult result = OC_STACK_ERROR;
1054     OCEntityHandlerResult ehResult = OC_EH_ERROR;
1055     OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
1056     ResourceObserver *resObs = NULL;
1057
1058     OCEntityHandlerRequest ehRequest = {0};
1059
1060     OIC_LOG(INFO, TAG, "Entering HandleResourceWithEntityHandler");
1061     OCPayloadType type = PAYLOAD_TYPE_REPRESENTATION;
1062     // check the security resource
1063     if (request && request->resourceUrl && SRMIsSecurityResourceURI(request->resourceUrl))
1064     {
1065         type = PAYLOAD_TYPE_SECURITY;
1066
1067     }
1068
1069     result = FormOCEntityHandlerRequest(&ehRequest,
1070                                         (OCRequestHandle)request,
1071                                         request->method,
1072                                         &request->devAddr,
1073                                         (OCResourceHandle)resource,
1074                                         request->query,
1075                                         type,
1076                                         request->payload,
1077                                         request->payloadSize,
1078                                         request->numRcvdVendorSpecificHeaderOptions,
1079                                         request->rcvdVendorSpecificHeaderOptions,
1080                                         (OCObserveAction)request->observationOption,
1081                                         0,
1082                                         request->coapID);
1083     VERIFY_SUCCESS(result, OC_STACK_OK);
1084
1085     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
1086     {
1087         OIC_LOG(INFO, TAG, "No observation requested");
1088         ehFlag = OC_REQUEST_FLAG;
1089     }
1090     else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER)
1091     {
1092         OIC_LOG(INFO, TAG, "Observation registration requested");
1093
1094         ResourceObserver *obs = GetObserverUsingToken (request->requestToken,
1095                                     request->tokenLength);
1096
1097         if (obs)
1098         {
1099             OIC_LOG (INFO, TAG, "Observer with this token already present");
1100             OIC_LOG (INFO, TAG, "Possibly re-transmitted CON OBS request");
1101             OIC_LOG (INFO, TAG, "Not adding observer. Not responding to client");
1102             OIC_LOG (INFO, TAG, "The first request for this token is already ACKED.");
1103
1104             // server requests are usually free'd when the response is sent out
1105             // for the request in ocserverrequest.c : HandleSingleResponse()
1106             // Since we are making an early return and not responding, the server request
1107             // needs to be deleted.
1108             FindAndDeleteServerRequest (request);
1109             return OC_STACK_OK;
1110         }
1111
1112         result = GenerateObserverId(&ehRequest.obsInfo.obsId);
1113         VERIFY_SUCCESS(result, OC_STACK_OK);
1114
1115         result = AddObserver ((const char*)(request->resourceUrl),
1116                 (const char *)(request->query),
1117                 ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
1118                 resource, request->qos, request->acceptFormat,
1119                 &request->devAddr);
1120
1121         if(result == OC_STACK_OK)
1122         {
1123             OIC_LOG(INFO, TAG, "Added observer successfully");
1124             request->observeResult = OC_STACK_OK;
1125             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
1126         }
1127         else if (result == OC_STACK_RESOURCE_ERROR)
1128         {
1129             OIC_LOG(INFO, TAG, "The Resource is not active, discoverable or observable");
1130             request->observeResult = OC_STACK_ERROR;
1131             ehFlag = OC_REQUEST_FLAG;
1132         }
1133         else
1134         {
1135             // The error in observeResult for the request will be used when responding to this
1136             // request by omitting the observation option/sequence number.
1137             request->observeResult = OC_STACK_ERROR;
1138             OIC_LOG(ERROR, TAG, "Observer Addition failed");
1139             ehFlag = OC_REQUEST_FLAG;
1140             FindAndDeleteServerRequest(request);
1141             goto exit;
1142         }
1143
1144     }
1145     else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER)
1146     {
1147         OIC_LOG(INFO, TAG, "Deregistering observation requested");
1148
1149         resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
1150
1151         if (NULL == resObs)
1152         {
1153             // Stack does not contain this observation request
1154             // Either token is incorrect or observation list is corrupted
1155             result = OC_STACK_ERROR;
1156             goto exit;
1157         }
1158         ehRequest.obsInfo.obsId = resObs->observeId;
1159         ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
1160
1161         result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
1162
1163         if(result == OC_STACK_OK)
1164         {
1165             OIC_LOG(INFO, TAG, "Removed observer successfully");
1166             request->observeResult = OC_STACK_OK;
1167             // There should be no observe option header for de-registration response.
1168             // Set as an invalid value here so we can detect it later and remove the field in response.
1169             request->observationOption = MAX_SEQUENCE_NUMBER + 1;
1170         }
1171         else
1172         {
1173             request->observeResult = OC_STACK_ERROR;
1174             OIC_LOG(ERROR, TAG, "Observer Removal failed");
1175             FindAndDeleteServerRequest(request);
1176             goto exit;
1177         }
1178     }
1179     else
1180     {
1181         result = OC_STACK_ERROR;
1182         goto exit;
1183     }
1184
1185     ehResult = resource->entityHandler(ehFlag, &ehRequest, resource->entityHandlerCallbackParam);
1186     if(ehResult == OC_EH_SLOW)
1187     {
1188         OIC_LOG(INFO, TAG, "This is a slow resource");
1189         request->slowFlag = 1;
1190     }
1191     else if(ehResult == OC_EH_ERROR)
1192     {
1193         FindAndDeleteServerRequest(request);
1194     }
1195     result = EntityHandlerCodeToOCStackCode(ehResult);
1196 exit:
1197     OCPayloadDestroy(ehRequest.payload);
1198     return result;
1199 }
1200
1201 static OCStackResult
1202 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
1203                                               OCResource *resource)
1204 {
1205     if(!request || !resource)
1206     {
1207         return OC_STACK_INVALID_PARAM;
1208     }
1209
1210     OCStackResult result = OC_STACK_ERROR;
1211     OCEntityHandlerRequest ehRequest = {0};
1212
1213     result = FormOCEntityHandlerRequest(&ehRequest,
1214                                         (OCRequestHandle)request,
1215                                         request->method,
1216                                         &request->devAddr,
1217                                         (OCResourceHandle)resource,
1218                                         request->query,
1219                                         PAYLOAD_TYPE_REPRESENTATION,
1220                                         request->payload,
1221                                         request->payloadSize,
1222                                         request->numRcvdVendorSpecificHeaderOptions,
1223                                         request->rcvdVendorSpecificHeaderOptions,
1224                                         (OCObserveAction)request->observationOption,
1225                                         (OCObservationId)0,
1226                                         request->coapID);
1227     if(result == OC_STACK_OK)
1228     {
1229         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
1230     }
1231
1232     OCPayloadDestroy(ehRequest.payload);
1233     return result;
1234 }
1235
1236 OCStackResult
1237 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
1238 {
1239     OCStackResult ret = OC_STACK_OK;
1240
1241     switch (resHandling)
1242     {
1243         case OC_RESOURCE_VIRTUAL:
1244         {
1245             ret = HandleVirtualResource (request, resource);
1246             break;
1247         }
1248         case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
1249         {
1250             ret = HandleDefaultDeviceEntityHandler(request);
1251             break;
1252         }
1253         case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
1254         {
1255             OIC_LOG(INFO, TAG, "OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER");
1256             return OC_STACK_ERROR;
1257         }
1258         case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
1259         {
1260             ret = HandleResourceWithEntityHandler (request, resource, 0);
1261             break;
1262         }
1263         case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
1264         {
1265             ret = HandleResourceWithEntityHandler (request, resource, 1);
1266             break;
1267         }
1268         case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
1269         {
1270             ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
1271             break;
1272         }
1273         case OC_RESOURCE_NOT_SPECIFIED:
1274         {
1275             ret = OC_STACK_NO_RESOURCE;
1276             break;
1277         }
1278         default:
1279         {
1280             OIC_LOG(INFO, TAG, "Invalid Resource Determination");
1281             return OC_STACK_ERROR;
1282         }
1283     }
1284     return ret;
1285 }
1286
1287 void DeletePlatformInfo()
1288 {
1289     OIC_LOG(INFO, TAG, "Deleting platform info.");
1290
1291     OICFree(savedPlatformInfo.platformID);
1292     savedPlatformInfo.platformID = NULL;
1293
1294     OICFree(savedPlatformInfo.manufacturerName);
1295     savedPlatformInfo.manufacturerName = NULL;
1296
1297     OICFree(savedPlatformInfo.manufacturerUrl);
1298     savedPlatformInfo.manufacturerUrl = NULL;
1299
1300     OICFree(savedPlatformInfo.modelNumber);
1301     savedPlatformInfo.modelNumber = NULL;
1302
1303     OICFree(savedPlatformInfo.dateOfManufacture);
1304     savedPlatformInfo.dateOfManufacture = NULL;
1305
1306     OICFree(savedPlatformInfo.platformVersion);
1307     savedPlatformInfo.platformVersion = NULL;
1308
1309     OICFree(savedPlatformInfo.operatingSystemVersion);
1310     savedPlatformInfo.operatingSystemVersion = NULL;
1311
1312     OICFree(savedPlatformInfo.hardwareVersion);
1313     savedPlatformInfo.hardwareVersion = NULL;
1314
1315     OICFree(savedPlatformInfo.firmwareVersion);
1316     savedPlatformInfo.firmwareVersion = NULL;
1317
1318     OICFree(savedPlatformInfo.supportUrl);
1319     savedPlatformInfo.supportUrl = NULL;
1320
1321     OICFree(savedPlatformInfo.systemTime);
1322     savedPlatformInfo.systemTime = NULL;
1323 }
1324
1325 static OCStackResult DeepCopyPlatFormInfo(OCPlatformInfo info)
1326 {
1327     savedPlatformInfo.platformID = OICStrdup(info.platformID);
1328     savedPlatformInfo.manufacturerName = OICStrdup(info.manufacturerName);
1329     savedPlatformInfo.manufacturerUrl = OICStrdup(info.manufacturerUrl);
1330     savedPlatformInfo.modelNumber = OICStrdup(info.modelNumber);
1331     savedPlatformInfo.dateOfManufacture = OICStrdup(info.dateOfManufacture);
1332     savedPlatformInfo.platformVersion = OICStrdup(info.platformVersion);
1333     savedPlatformInfo.operatingSystemVersion = OICStrdup(info.operatingSystemVersion);
1334     savedPlatformInfo.hardwareVersion = OICStrdup(info.hardwareVersion);
1335     savedPlatformInfo.firmwareVersion = OICStrdup(info.firmwareVersion);
1336     savedPlatformInfo.supportUrl = OICStrdup(info.supportUrl);
1337     savedPlatformInfo.systemTime = OICStrdup(info.systemTime);
1338
1339     if ((!savedPlatformInfo.platformID && info.platformID)||
1340         (!savedPlatformInfo.manufacturerName && info.manufacturerName)||
1341         (!savedPlatformInfo.manufacturerUrl && info.manufacturerUrl)||
1342         (!savedPlatformInfo.modelNumber && info.modelNumber)||
1343         (!savedPlatformInfo.dateOfManufacture && info.dateOfManufacture)||
1344         (!savedPlatformInfo.platformVersion && info.platformVersion)||
1345         (!savedPlatformInfo.operatingSystemVersion && info.operatingSystemVersion)||
1346         (!savedPlatformInfo.hardwareVersion && info.hardwareVersion)||
1347         (!savedPlatformInfo.firmwareVersion && info.firmwareVersion)||
1348         (!savedPlatformInfo.supportUrl && info.supportUrl)||
1349         (!savedPlatformInfo.systemTime && info.systemTime))
1350     {
1351         DeletePlatformInfo();
1352         return OC_STACK_INVALID_PARAM;
1353     }
1354
1355     return OC_STACK_OK;
1356
1357 }
1358
1359 OCStackResult SavePlatformInfo(OCPlatformInfo info)
1360 {
1361     DeletePlatformInfo();
1362
1363     OCStackResult res = DeepCopyPlatFormInfo(info);
1364
1365     if (res != OC_STACK_OK)
1366     {
1367         OIC_LOG_V(ERROR, TAG, "Failed to save platform info. errno(%d)", res);
1368     }
1369     else
1370     {
1371         OIC_LOG(INFO, TAG, "Platform info saved.");
1372     }
1373
1374     return res;
1375 }
1376
1377 void DeleteDeviceInfo()
1378 {
1379     OIC_LOG(INFO, TAG, "Deleting device info.");
1380
1381     OICFree(savedDeviceInfo.deviceName);
1382     OCFreeOCStringLL(savedDeviceInfo.types);
1383     OICFree(savedDeviceInfo.specVersion);
1384     OCFreeOCStringLL(savedDeviceInfo.dataModelVersions);
1385     savedDeviceInfo.deviceName = NULL;
1386     savedDeviceInfo.specVersion = NULL;
1387     savedDeviceInfo.dataModelVersions = NULL;
1388 }
1389
1390 static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
1391 {
1392     savedDeviceInfo.deviceName = OICStrdup(info.deviceName);
1393
1394     if(!savedDeviceInfo.deviceName && info.deviceName)
1395     {
1396         DeleteDeviceInfo();
1397         return OC_STACK_NO_MEMORY;
1398     }
1399
1400     if (info.types)
1401     {
1402         savedDeviceInfo.types = CloneOCStringLL(info.types);
1403         OCStringLL *type = info.types;
1404         bool found = false;
1405         while (type)
1406         {
1407             if (type && type->value && 0 == strcmp(type->value, OC_RSRVD_RESOURCE_TYPE_DEVICE))
1408             {
1409                 found = true;
1410             }
1411             type = type->next;
1412         }
1413         if (!found)
1414         {
1415             // Append the oic.wk.d at the start of rt link parameter value.
1416             OCStringLL *dest = (OCStringLL*)OICCalloc (1, sizeof (OCStringLL));
1417             if (!dest)
1418             {
1419                 DeleteDeviceInfo();
1420                 return OC_STACK_NO_MEMORY;
1421             }
1422             dest->value = OICStrdup (OC_RSRVD_RESOURCE_TYPE_DEVICE);
1423             if (!dest->value)
1424             {
1425                 DeleteDeviceInfo();
1426                 return OC_STACK_NO_MEMORY;
1427             }
1428             dest->next = savedDeviceInfo.types;
1429             savedDeviceInfo.types = dest;
1430         }
1431         if(!savedDeviceInfo.types && info.types)
1432         {
1433             DeleteDeviceInfo();
1434             return OC_STACK_NO_MEMORY;
1435         }
1436     }
1437
1438     if (info.specVersion)
1439     {
1440         savedDeviceInfo.specVersion = OICStrdup(info.specVersion);
1441         if(!savedDeviceInfo.specVersion && info.specVersion)
1442         {
1443             DeleteDeviceInfo();
1444             return OC_STACK_NO_MEMORY;
1445         }
1446     }
1447     else
1448     {
1449         savedDeviceInfo.specVersion = OICStrdup(OC_SPEC_VERSION);
1450         if(!savedDeviceInfo.specVersion && OC_SPEC_VERSION)
1451         {
1452             DeleteDeviceInfo();
1453             return OC_STACK_NO_MEMORY;
1454         }
1455     }
1456
1457     if (info.dataModelVersions)
1458     {
1459         savedDeviceInfo.dataModelVersions = CloneOCStringLL(info.dataModelVersions);
1460         if(!savedDeviceInfo.dataModelVersions && info.dataModelVersions)
1461         {
1462             DeleteDeviceInfo();
1463             return OC_STACK_NO_MEMORY;
1464         }
1465     }
1466     else
1467     {
1468         savedDeviceInfo.dataModelVersions = (OCStringLL *)OICCalloc(1,sizeof(OCStringLL));
1469         if (!savedDeviceInfo.dataModelVersions)
1470         {
1471             return OC_STACK_NO_MEMORY;
1472         }
1473         savedDeviceInfo.dataModelVersions->value = OICStrdup(OC_DATA_MODEL_VERSION);
1474         if(!savedDeviceInfo.dataModelVersions->value && OC_DATA_MODEL_VERSION)
1475         {
1476             DeleteDeviceInfo();
1477             return OC_STACK_NO_MEMORY;
1478         }
1479     }
1480
1481     return OC_STACK_OK;
1482 }
1483
1484 OCStackResult SaveDeviceInfo(OCDeviceInfo info)
1485 {
1486     OCStackResult res = OC_STACK_OK;
1487
1488     DeleteDeviceInfo();
1489
1490     res = DeepCopyDeviceInfo(info);
1491
1492     VERIFY_SUCCESS(res, OC_STACK_OK);
1493
1494     if (OCGetServerInstanceIDString() == NULL)
1495     {
1496         OIC_LOG(INFO, TAG, "Device ID generation failed");
1497         res =  OC_STACK_ERROR;
1498         goto exit;
1499     }
1500
1501     OIC_LOG(INFO, TAG, "Device initialized successfully.");
1502     return OC_STACK_OK;
1503
1504 exit:
1505     DeleteDeviceInfo();
1506     return res;
1507 }