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