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