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