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