Fix Device and Payload response
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocresource.c
index d109ba3..989fab2 100755 (executable)
 // For POSIX.1-2001 base specification,
 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
 #define _POSIX_C_SOURCE 200112L
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
 
-#ifdef WITH_ARDUINO
+#include "iotivity_config.h"
+#ifdef HAVE_STRING_H
 #include <string.h>
-#else
+#endif
+#ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
 
 #include "secureresourcemanager.h"
 #include "cacommon.h"
 #include "cainterface.h"
-#include "rdpayload.h"
 #include "ocpayload.h"
-
-#ifdef WITH_RD
-#include "rd_server.h"
-#endif
-
+#include "platform_features.h"
+#include "payload_logging.h"
 #ifdef ROUTING_GATEWAY
 #include "routingmanager.h"
 #endif
 
+#ifdef RD_SERVER
+#include "rd_database.h"
+#endif
+
 /// Module Name
 #define TAG "OIC_RI_RESOURCE"
 
 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
             {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
 
-#define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
-             TAG, #arg " is NULL"); return (retVal); } }
-
 extern OCResource *headResource;
 static OCPlatformInfo savedPlatformInfo = {0};
 static OCDeviceInfo savedDeviceInfo = {0};
@@ -73,8 +75,7 @@ static OCDeviceInfo savedDeviceInfo = {0};
  */
 static OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
                                                   OCDiscoveryPayload* payload,
-                                                  OCDevAddr *endpoint,
-                                                  bool rdResponse);
+                                                  OCDevAddr *endpoint);
 
 //-----------------------------------------------------------------------------
 // Default resource entity handler function
@@ -111,6 +112,29 @@ static OCStackResult GetSecurePortInfo(OCDevAddr *endpoint, uint16_t *port)
     return OC_STACK_OK;
 }
 
+#ifdef TCP_ADAPTER
+/* This method will retrieve the tcp port */
+static OCStackResult GetTCPPortInfo(OCDevAddr *endpoint, uint16_t *port)
+{
+    uint16_t p = 0;
+
+    if (endpoint->adapter == OC_ADAPTER_IP)
+    {
+        if (endpoint->flags & OC_IP_USE_V4)
+        {
+            p = caglobals.tcp.ipv4.port;
+        }
+        else if (endpoint->flags & OC_IP_USE_V6)
+        {
+            p = caglobals.tcp.ipv6.port;
+        }
+    }
+
+    *port = p;
+    return OC_STACK_OK;
+}
+#endif
+
 /*
  * Function will extract 0, 1 or 2 filters from query.
  * More than 2 filters or unsupported filters will result in error.
@@ -120,32 +144,47 @@ static OCStackResult GetSecurePortInfo(OCDevAddr *endpoint, uint16_t *port)
  */
 static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char **filterTwo)
 {
-
     char *key = NULL;
     char *value = NULL;
+    char *queryDup = NULL;
     char *restOfQuery = NULL;
+    char *keyValuePair = NULL;
     int numKeyValuePairsParsed = 0;
 
     *filterOne = NULL;
     *filterTwo = NULL;
 
-    OIC_LOG_V(INFO, TAG, "Extracting params from %s", query);
+    queryDup = OICStrdup(query);
+    if (NULL == queryDup)
+    {
+        OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    OIC_LOG_V(INFO, TAG, "Extracting params from %s", queryDup);
 
-    char *keyValuePair = strtok_r (query, OC_QUERY_SEPARATOR, &restOfQuery);
+    OCStackResult eCode = OC_STACK_INVALID_QUERY;
+    if (strnlen(queryDup, MAX_QUERY_LENGTH) >= MAX_QUERY_LENGTH)
+    {
+        OIC_LOG(ERROR, TAG, "Query exceeds maximum length.");
+        goto exit;
+    }
+
+    keyValuePair = strtok_r (queryDup, OC_QUERY_SEPARATOR, &restOfQuery);
 
     while(keyValuePair)
     {
         if (numKeyValuePairsParsed >= 2)
         {
             OIC_LOG(ERROR, TAG, "More than 2 queries params in URI.");
-            return OC_STACK_INVALID_QUERY;
+            goto exit;
         }
 
         key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
 
         if (!key || !value)
         {
-            return OC_STACK_INVALID_QUERY;
+            goto exit;
         }
         else if (strncasecmp(key, OC_RSRVD_INTERFACE, sizeof(OC_RSRVD_INTERFACE) - 1) == 0)
         {
@@ -158,15 +197,45 @@ static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char
         else
         {
             OIC_LOG_V(ERROR, TAG, "Unsupported query key: %s", key);
-            return OC_STACK_INVALID_QUERY;
+            goto exit;
         }
         ++numKeyValuePairsParsed;
 
         keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
     }
 
+    if (*filterOne)
+    {
+        *filterOne = OICStrdup(*filterOne);
+        if (NULL == *filterOne)
+        {
+            OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
+            eCode = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+    }
+
+    if (*filterTwo)
+    {
+        *filterTwo = OICStrdup(*filterTwo);
+        if (NULL == *filterTwo)
+        {
+            OIC_LOG_V(ERROR, TAG, "Creating duplicate string failed!");
+            OICFree(*filterOne);
+            eCode = OC_STACK_NO_MEMORY;
+            goto exit;
+        }
+    }
+
+    OICFree(queryDup);
     OIC_LOG_V(INFO, TAG, "Extracted params if: %s and rt: %s.", *filterOne, *filterTwo);
     return OC_STACK_OK;
+
+exit:
+    *filterOne = NULL;
+    *filterTwo = NULL;
+    OICFree(queryDup);
+    return eCode;
 }
 
 static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
@@ -199,6 +268,21 @@ static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
         return OC_PRESENCE;
     }
 #endif //WITH_PRESENCE
+
+#ifdef MQ_BROKER
+    else if (0 == strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_MQ_URI))
+    {
+        return OC_MQ_BROKER_URI;
+    }
+#endif //MQ_BROKER
+
+#ifdef TCP_ADAPTER
+    else if (strcmp(uriInRequest, OC_RSRVD_KEEPALIVE_URI) == 0)
+    {
+        return OC_KEEPALIVE_RESOURCE_URI;
+    }
+#endif
+
     return OC_UNKNOWN_URI;
 }
 
@@ -285,27 +369,32 @@ OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
 }
 
 OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
-                        OCDiscoveryPayload *payload, OCDevAddr *devAddr, bool rdResponse)
+                        OCDiscoveryPayload *payload, OCDevAddr *devAddr)
 {
     if (!resourcePtr || !payload)
     {
         return OC_STACK_INVALID_PARAM;
     }
-    uint16_t port = 0;
+    uint16_t securePort = 0;
     if (resourcePtr->resourceProperties & OC_SECURE)
     {
-       if (GetSecurePortInfo(devAddr, &port) != OC_STACK_OK)
+       if (GetSecurePortInfo(devAddr, &securePort) != OC_STACK_OK)
        {
-           port = 0;
+           securePort = 0;
        }
     }
 
-    if (rdResponse)
+#ifdef TCP_ADAPTER
+    uint16_t tcpPort = 0;
+    if (GetTCPPortInfo(devAddr, &tcpPort) != OC_STACK_OK)
     {
-        port = devAddr->port;
+        tcpPort = 0;
     }
+    OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort, tcpPort);
+#else
+    OCDiscoveryPayloadAddResource(payload, resourcePtr, securePort);
+#endif
 
-    OCDiscoveryPayloadAddResource(payload, resourcePtr, port);
     return OC_STACK_OK;
 }
 
@@ -426,6 +515,8 @@ OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
     switch (ehResult)
     {
         case OC_EH_OK:
+        case OC_EH_CONTENT:
+        case OC_EH_VALID:
             result = OC_STACK_OK;
             break;
         case OC_EH_SLOW:
@@ -435,7 +526,10 @@ OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
             result = OC_STACK_ERROR;
             break;
         case OC_EH_FORBIDDEN:
-            result = OC_STACK_RESOURCE_ERROR;
+            result = OC_STACK_FORBIDDEN_REQ;
+            break;
+        case OC_EH_INTERNAL_SERVER_ERROR:
+            result = OC_STACK_INTERNAL_SERVER_ERROR;
             break;
         case OC_EH_RESOURCE_CREATED:
             result = OC_STACK_RESOURCE_CREATED;
@@ -443,6 +537,9 @@ OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
         case OC_EH_RESOURCE_DELETED:
             result = OC_STACK_RESOURCE_DELETED;
             break;
+        case OC_EH_CHANGED:
+            result = OC_STACK_RESOURCE_CHANGED;
+            break;
         case OC_EH_RESOURCE_NOT_FOUND:
             result = OC_STACK_NO_RESOURCE;
             break;
@@ -498,9 +595,9 @@ static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter)
 
     while (interfacePtr)
     {
-        if ((strcmp (interfacePtr->name, interfaceFilter) == 0) &&
-            (strcmp (OC_RSRVD_INTERFACE_LL, interfaceFilter) == 0 ||
-             strcmp (OC_RSRVD_INTERFACE_DEFAULT, interfaceFilter) == 0))
+        if (strcmp (interfacePtr->name, interfaceFilter) == 0 ||
+            strcmp (OC_RSRVD_INTERFACE_LL, interfaceFilter) == 0 ||
+            strcmp (OC_RSRVD_INTERFACE_DEFAULT, interfaceFilter) == 0)
         {
             return true;
         }
@@ -564,102 +661,105 @@ OCStackResult SendNonPersistantDiscoveryResponse(OCServerRequest *request, OCRes
 
     return OCDoResponse(&response);
 }
+#ifdef RD_SERVER
+/**
+ * Find resource at the resource directory server. This resource is not local resource but a
+ * remote resource.
+ *
+ * @param resource The resource to check the matching resource URI.
+ * @param interfaceQuery The interface query parameter.
+ * @param resourceTypeQuery The resourceType query parameter.
+ * @param discPayload The payload that will be added with the resource information if found at RD.
+ *
+ * @return ::OC_STACK_OK if the resource is found else ::OC_STACK_NO_RESOURCE.
+ * In case if build is not with flag RD_SERVER, it returns ::OC_STACK_NO_RESOURCE.
+ */
+static OCStackResult findResourceAtRD(const OCResource* resource, const char *interfaceQuery,
+    const char *resourceTypeQuery, OCDiscoveryPayload *discPayload)
+{
+    if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0)
+    {
+        if (OC_STACK_OK == OCRDDatabaseCheckResources(interfaceQuery, resourceTypeQuery, discPayload))
+        {
+            return OC_STACK_OK;
+        }
+    }
 
-#ifdef WITH_RD
-static OCStackResult checkResourceExistsAtRD(const char *interfaceType, const char *resourceType,
-     OCResource **payload, OCDevAddr *devAddr)
+    return OC_STACK_NO_RESOURCE;
+}
+#endif
+
+/**
+ * Creates a discovery payload and add device id information. This information is included in all
+ * /oic/res response.
+ *
+ * @param payload  payload that will have memory alllocated and device id information added.
+ *
+ * @return ::OC_STACK_OK if successful in allocating memory and adding ID information.
+ * ::OC_STACK_NO_MEMORY if failed allocating the memory.
+ */
+static OCStackResult discoveryPayloadCreateAndAddDeviceId(OCPayload **payload)
 {
-    OCResourceCollectionPayload *repPayload;
-    if (!payload)
+    if (*payload)
     {
-        return OC_STACK_ERROR;
+        OIC_LOG_V(DEBUG, TAG, "Payload is already allocated");
+        return OC_STACK_OK;
     }
-    if (OCRDCheckPublishedResource(interfaceType, resourceType, &repPayload, devAddr) == OC_STACK_OK)
+
+    *payload = (OCPayload *) OCDiscoveryPayloadCreate();
+    VERIFY_PARAM_NON_NULL(TAG, *payload, "Failed adding device id to discovery payload.");
+
     {
-        if (!repPayload)
-        {
-            return OC_STACK_ERROR;
-        }
-        OCResource *ptr = ((OCResource *) OICCalloc(1, sizeof(OCResource)));
-        if (!ptr)
-        {
-           return OC_STACK_NO_MEMORY;
-        }
+        OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)*payload;
+        discPayload->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
+        VERIFY_PARAM_NON_NULL(TAG, discPayload->sid, "Failed adding device id to discovery payload.");
 
-        ptr->uri = OICStrdup(repPayload->setLinks->href);
-        if (!ptr->uri)
+        const char* uid = OCGetServerInstanceIDString();
+        if (uid)
         {
-           return OC_STACK_NO_MEMORY;
-        }
-        OCStringLL *rt = repPayload->setLinks->rt;
-        while (rt)
-        {
-            OCResourceType *temp = (OCResourceType *) OICCalloc(1, sizeof(OCResourceType));
-            if(!temp)
-            {
-                OICFree(ptr->uri);
-                return OC_STACK_NO_MEMORY;
-            }
-            temp->next = NULL;
-            temp->resourcetypename = OICStrdup(rt->value);
-            if (!ptr->rsrcType)
-            {
-                ptr->rsrcType = temp;
-            }
-            else
-            {
-                OCResourceType *type = ptr->rsrcType;
-                while (type->next)
-                {
-                    type = type->next;
-                }
-                type->next = temp;
-            }
-            rt = rt->next;
+            memcpy(discPayload->sid, uid, UUID_STRING_SIZE);
         }
 
-        OCStringLL *itf = repPayload->setLinks->itf;
-        while (itf)
-        {
-            OCResourceInterface *temp = (OCResourceInterface *) OICCalloc(1, sizeof(OCResourceInterface));
-            if (!temp)
-            {
-                OICFree(ptr->uri);
-
-                return OC_STACK_NO_MEMORY;
-            }
-            temp->next = NULL;
-            temp->name = OICStrdup(itf->value);
-            if (!ptr->rsrcInterface)
-            {
-                ptr->rsrcInterface = temp;
-            }
-            else
-            {
-                OCResourceInterface *type = ptr->rsrcInterface;
-                while (type->next)
-                {
-                    type = type->next;
-                }
-                type->next = temp;
-            }
-            itf = itf->next;
-        }
+    }
+    return OC_STACK_OK;
+exit:
+    OCPayloadDestroy(*payload);
+    return OC_STACK_NO_MEMORY;
+}
 
-        ptr->resourceProperties = (OCResourceProperty) repPayload->tags->bitmap;
+/**
+ * Add the common properties to the payload, they are only included in case of oic.if.baseline response.
+ *
+ * @param discPayload payload that will have the baseline information included.
+ *
+ * @return ::OC_STACK_OK if successful in adding all the information. ::OC_STACK_NO_MEMORY if failed
+ * allocating the memory for the baseline information.
+ */
+static OCStackResult addDiscoveryBaselineCommonProperties(OCDiscoveryPayload *discPayload)
+{
+    discPayload->uri = OICStrdup(OC_RSRVD_WELL_KNOWN_URI);
+    VERIFY_PARAM_NON_NULL(TAG, discPayload->uri, "Failed adding href to discovery payload.");
 
-        OCFreeCollectionResource(repPayload);
-        *payload = ptr;
-        return OC_STACK_OK;
-    }
-    else
+    if (savedDeviceInfo.deviceName)
     {
-        OIC_LOG_V(ERROR, TAG, "The resource type or interface type doe not exist \
-                             on the resource directory");
+        discPayload->name = OICStrdup(savedDeviceInfo.deviceName);
+        VERIFY_PARAM_NON_NULL(TAG, discPayload->name, "Failed adding name to discovery payload.");
     }
-    return OC_STACK_ERROR;
+
+    discPayload->type = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL));
+    VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt to discovery payload.");
+    discPayload->type->value = OICStrdup(OC_RSRVD_RESOURCE_TYPE_RES);
+    VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt value to discovery payload.");
+
+    OCResourcePayloadAddStringLL(&discPayload->iface, OC_RSRVD_INTERFACE_LL);
+    OCResourcePayloadAddStringLL(&discPayload->iface, OC_RSRVD_INTERFACE_DEFAULT);
+    VERIFY_PARAM_NON_NULL(TAG, discPayload->iface, "Failed adding if to discovery payload.");
+
+    return OC_STACK_OK;
+
+exit:
+    return OC_STACK_NO_MEMORY;
 }
-#endif
 
 static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource)
 {
@@ -669,213 +769,140 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
     }
 
     OCStackResult discoveryResult = OC_STACK_ERROR;
-
-    bool bMulticast    = false;     // Was the discovery request a multicast request?
     OCPayload* payload = NULL;
+    char *interfaceQuery = NULL;
+    char *resourceTypeQuery = NULL;
+    char *dataModelVersions = NULL;
 
     OIC_LOG(INFO, TAG, "Entering HandleVirtualResource");
 
     OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
 
     // Step 1: Generate the response to discovery request
-    if (virtualUriInRequest == OC_WELL_KNOWN_URI)
+    if (virtualUriInRequest == OC_WELL_KNOWN_URI
+#ifdef MQ_BROKER
+            || virtualUriInRequest == OC_MQ_BROKER_URI
+#endif
+            )
     {
-        if (request->method == OC_REST_PUT || request->method == OC_REST_POST || request->method == OC_REST_DELETE)
+        if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
+            request->method == OC_REST_DELETE)
         {
-            OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d", request->resourceUrl, request->method);
-            return OC_STACK_UNAUTHORIZED_REQ;
+            OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
+                request->resourceUrl, request->method);
+            discoveryResult = OC_STACK_UNAUTHORIZED_REQ;
+            goto exit;
         }
 
-        char *interfaceQuery = NULL;
-        char *resourceTypeQuery = NULL;
-
         discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
                 &interfaceQuery, &resourceTypeQuery);
-        bool interfaceQueryAllocated = false;
+        VERIFY_SUCCESS(discoveryResult, OC_STACK_OK);
         if (!interfaceQuery && !resourceTypeQuery)
         {
-            interfaceQueryAllocated = true;
+            // If no query is sent, default interface is used i.e. oic.if.ll.
             interfaceQuery = OICStrdup(OC_RSRVD_INTERFACE_LL);
         }
 
-        if (discoveryResult == OC_STACK_OK)
+        bool baselineQuery = false;
+        if (interfaceQuery && 0 != strcmp(interfaceQuery, OC_RSRVD_INTERFACE_LL))
         {
-            payload = (OCPayload *)OCDiscoveryPayloadCreate();
+            baselineQuery = true;
+        }
 
-            if (payload)
-            {
-                OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
-                discPayload->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
-                VERIFY_NON_NULL(discPayload->sid, ERROR, OC_STACK_NO_MEMORY);
-                const char* uid = OCGetServerInstanceIDString();
-                if(uid)
-                {
-                    memcpy(discPayload->sid, uid, UUID_STRING_SIZE);
-                }
+        discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload);
+        VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload.");
+        VERIFY_SUCCESS(discoveryResult, OC_STACK_OK);
 
-                if (!resourceTypeQuery && interfaceQuery && (0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_LL)))
+        OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload;
+        if (baselineQuery)
+        {
+            discoveryResult = addDiscoveryBaselineCommonProperties(discPayload);
+            VERIFY_SUCCESS(discoveryResult, OC_STACK_OK);
+        }
+        OCResourceProperty prop = OC_DISCOVERABLE;
+#ifdef MQ_BROKER
+        prop = (OC_MQ_BROKER_URI == virtualUriInRequest) ? OC_MQ_BROKER : prop;
+#endif
+        for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
+        {
+            discoveryResult = OC_STACK_NO_RESOURCE;
+#ifdef RD_SERVER
+            discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery,
+                discPayload);
+#endif
+            if (OC_STACK_NO_RESOURCE == discoveryResult)
+            {
+                if ((!baselineQuery && (resource->resourceProperties & prop)) ||
+                    (baselineQuery && (includeThisResourceInResponse(resource, interfaceQuery,
+                                                                     resourceTypeQuery))))
                 {
-                    for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next)
-                    {
-                        bool result = false;
-                        if (resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
-                        {
-                            if (resourceTypeQuery && resourceMatchesRTFilter(resource, resourceTypeQuery))
-                            {
-                                result = true;
-                            }
-                        }
-                        if (resource->resourceProperties & OC_DISCOVERABLE)
-                        {
-                            result = true;
-                        }
-
-                        if (result)
-                        {
-                            discoveryResult = BuildVirtualResourceResponse(resource,
-                            discPayload, &request->devAddr, false);
-                        }
-                    }
+                    discoveryResult = BuildVirtualResourceResponse(resource, discPayload,
+                        &request->devAddr);
                 }
                 else
                 {
-                    if ((interfaceQuery && (0 != strcmp(interfaceQuery, OC_RSRVD_INTERFACE_LL))) ||
-                        !interfaceQuery)
-                    {
-                        discPayload->uri = OICStrdup(OC_RSRVD_WELL_KNOWN_URI);
-                        VERIFY_NON_NULL(discPayload->uri, ERROR, OC_STACK_NO_MEMORY);
-                        if (savedDeviceInfo.deviceName)
-                        {
-                            discPayload->name = OICStrdup(savedDeviceInfo.deviceName);
-                            VERIFY_NON_NULL(discPayload->name, ERROR, OC_STACK_NO_MEMORY);
-                        }
-                        discPayload->type = OICStrdup(OC_RSRVD_RESOURCE_TYPE_RES);
-                        VERIFY_NON_NULL(discPayload->type, ERROR, OC_STACK_NO_MEMORY);
-                        OCResourcePayloadAddStringLL(&discPayload->interface, OC_RSRVD_INTERFACE_LL);
-                        OCResourcePayloadAddStringLL(&discPayload->interface, OC_RSRVD_INTERFACE_DEFAULT);
-                        VERIFY_NON_NULL(discPayload->interface, ERROR, OC_STACK_NO_MEMORY);
-                    }
-                    bool foundResourceAtRD = false;
-                    for (;resource && discoveryResult == OC_STACK_OK; resource = resource->next)
-                    {
-#ifdef WITH_RD
-                        if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0)
-                        {
-                            OCResource *resource1 = NULL;
-                            OCDevAddr devAddr;
-                            discoveryResult = checkResourceExistsAtRD(interfaceQuery,
-                                resourceTypeQuery, &resource1, &devAddr);
-                            if (discoveryResult != OC_STACK_OK)
-                            {
-                                 break;
-                            }
-                            discoveryResult = BuildVirtualResourceResponse(resource1,
-                                discPayload, &devAddr, true);
-                            if (payload)
-                            {
-                                discPayload->baseURI = OICStrdup(devAddr.addr);
-                            }
-                            OICFree(resource1->uri);
-                            for (OCResourceType *rsrcRt = resource1->rsrcType, *rsrcRtNext = NULL; rsrcRt; )
-                            {
-                                rsrcRtNext = rsrcRt->next;
-                                OICFree(rsrcRt->resourcetypename);
-                                OICFree(rsrcRt);
-                                rsrcRt = rsrcRtNext;
-                            }
-
-                            for (OCResourceInterface *rsrcPtr = resource1->rsrcInterface, *rsrcNext = NULL; rsrcPtr; )
-                            {
-                                rsrcNext = rsrcPtr->next;
-                                OICFree(rsrcPtr->name);
-                                OICFree(rsrcPtr);
-                                rsrcPtr = rsrcNext;
-                            }
-                            foundResourceAtRD = true;
-                        }
-#endif
-                        if (!foundResourceAtRD && includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery))
-                        {
-                            discoveryResult = BuildVirtualResourceResponse(resource,
-                                discPayload, &request->devAddr, false);
-                        }
-                    }
-                    // Set discoveryResult appropriately if no 'valid' resources are available
-                    if (discPayload->resources == NULL && !foundResourceAtRD)
-                    {
-                        discoveryResult = OC_STACK_NO_RESOURCE;
-                    }
+                    discoveryResult = OC_STACK_OK;
                 }
             }
-            else
-            {
-                discoveryResult = OC_STACK_NO_MEMORY;
-            }
         }
-        else
+        if (discPayload->resources == NULL)
         {
-            OIC_LOG_V(ERROR, TAG, "Error (%d) parsing query.", discoveryResult);
-        }
-        if (interfaceQueryAllocated)
-        {
-            OICFree(interfaceQuery);
+            discoveryResult = OC_STACK_NO_RESOURCE;
         }
     }
     else if (virtualUriInRequest == OC_DEVICE_URI)
     {
-        if (request->method == OC_REST_PUT || request->method == OC_REST_POST || request->method == OC_REST_DELETE)
+        if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
+            request->method == OC_REST_DELETE)
         {
-            OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d", request->resourceUrl, request->method);
-            return OC_STACK_UNAUTHORIZED_REQ;
+            OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
+                request->resourceUrl, request->method);
+            discoveryResult = OC_STACK_UNAUTHORIZED_REQ;
+            goto exit;
         }
 
         const char* deviceId = OCGetServerInstanceIDString();
-        if (!deviceId)
-        {
-            discoveryResult = OC_STACK_ERROR;
-        }
-        else
-        {
-            payload = (OCPayload*) OCDevicePayloadCreate(deviceId, savedDeviceInfo.deviceName,
-                savedDeviceInfo.types, OC_SPEC_VERSION, OC_DATA_MODEL_VERSION);
-            if (!payload)
-            {
-                discoveryResult = OC_STACK_NO_MEMORY;
-            }
-            else
-            {
-                discoveryResult = OC_STACK_OK;
-            }
-        }
+        VERIFY_PARAM_NON_NULL(TAG, deviceId, "Failed retrieving device id.");
+        discoveryResult = OC_STACK_NO_MEMORY;
+        dataModelVersions = OCCreateString(savedDeviceInfo.dataModelVersions);
+        VERIFY_PARAM_NON_NULL(TAG, dataModelVersions, "Failed adding data model version.");
+        payload = (OCPayload*) OCDevicePayloadCreate(deviceId, savedDeviceInfo.deviceName,
+            savedDeviceInfo.types, savedDeviceInfo.specVersion, dataModelVersions);
+        VERIFY_PARAM_NON_NULL(TAG, payload, "Failed adding device payload.");
+        discoveryResult = OC_STACK_OK;
     }
     else if (virtualUriInRequest == OC_PLATFORM_URI)
     {
-        if (request->method == OC_REST_PUT || request->method == OC_REST_POST || request->method == OC_REST_DELETE)
+        if (request->method == OC_REST_PUT || request->method == OC_REST_POST ||
+            request->method == OC_REST_DELETE)
         {
-            OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d", request->resourceUrl, request->method);
-            return OC_STACK_UNAUTHORIZED_REQ;
+            OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d",
+                request->resourceUrl, request->method);
+            discoveryResult = OC_STACK_UNAUTHORIZED_REQ;
+            goto exit;
         }
 
-        payload = (OCPayload*)OCPlatformPayloadCreate(&savedPlatformInfo);
-        if (!payload)
-        {
-            discoveryResult = OC_STACK_NO_MEMORY;
-        }
-        else
-        {
-            discoveryResult = OC_STACK_OK;
-        }
-    }
+        discoveryResult = OC_STACK_NO_MEMORY;
+        payload = (OCPayload *)OCPlatformPayloadCreate(&savedPlatformInfo);
+        VERIFY_PARAM_NON_NULL(TAG, payload, "Failed adding platform payload.");
+        discoveryResult = OC_STACK_OK;
+   }
 #ifdef ROUTING_GATEWAY
     else if (OC_GATEWAY_URI == virtualUriInRequest)
     {
         // Received request for a gateway
         OIC_LOG(INFO, TAG, "Request is for Gateway Virtual Request");
         discoveryResult = RMHandleGatewayRequest(request, resource);
-
     }
 #endif
-
+#ifdef TCP_ADAPTER
+    else if (OC_KEEPALIVE_RESOURCE_URI == virtualUriInRequest)
+    {
+        // Received request for a keepalive
+        OIC_LOG(INFO, TAG, "Request is for KeepAlive Request");
+        discoveryResult = HandleKeepAliveRequest(request, resource);
+    }
+#endif
     /**
      * Step 2: Send the discovery response
      *
@@ -894,39 +921,73 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
     if ((virtualUriInRequest == OC_PRESENCE) &&
         (resource->resourceProperties & OC_ACTIVE))
     {
+        // Need to send ACK when the request is CON.
+        if (request->qos == OC_HIGH_QOS)
+        {
+            CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
+            CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
+            SendDirectStackResponse(&endpoint, request->coapID, CA_EMPTY, CA_MSG_ACKNOWLEDGE,
+                                    0, NULL, NULL, 0, NULL, CA_RESPONSE_FOR_RES);
+        }
+        FindAndDeleteServerRequest(request);
+
         // Presence uses observer notification api to respond via SendPresenceNotification.
         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
     }
     else
-    #endif
-#ifdef ROUTING_GATEWAY
+#endif
+#if ROUTING_GATEWAY
     // Gateway uses the RMHandleGatewayRequest to respond to the request.
     if (OC_GATEWAY_URI != virtualUriInRequest)
 #endif
     {
-        if(discoveryResult == OC_STACK_OK)
-        {
-            SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
-        }
-        else if(bMulticast == false && (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
-               (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
-        {
-            OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d)  \
-                discovery request", discoveryResult, virtualUriInRequest);
-            SendNonPersistantDiscoveryResponse(request, resource, NULL,
-                (discoveryResult == OC_STACK_NO_RESOURCE) ? OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
-        }
-        else
+#if TCP_ADAPTER
+        // KeepAlive uses the HandleKeepAliveRequest to respond to the request.
+        if (OC_KEEPALIVE_RESOURCE_URI != virtualUriInRequest)
+#endif
         {
-            // Ignoring the discovery request as per RFC 7252, Section #8.2
-            OIC_LOG(INFO, TAG, "Silently ignoring the request since device does not have \
-                any useful data to send");
+            OIC_LOG_PAYLOAD(DEBUG, payload);
+            if(discoveryResult == OC_STACK_OK)
+            {
+                SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
+            }
+            else if(((request->devAddr.flags &  OC_MULTICAST) == false) &&
+                (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) &&
+                (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE))
+            {
+                OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request",
+                    discoveryResult, virtualUriInRequest);
+                SendNonPersistantDiscoveryResponse(request, resource, NULL,
+                    (discoveryResult == OC_STACK_NO_RESOURCE) ?
+                            OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR);
+            }
+            else
+            {
+                // Ignoring the discovery request as per RFC 7252, Section #8.2
+                OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send.");
+                // the request should be removed.
+                // since it never remove and causes a big memory waste.
+                FindAndDeleteServerRequest(request);
+            }
         }
     }
 
-    OCPayloadDestroy(payload);
+exit:
+    if (interfaceQuery)
+    {
+        OICFree(interfaceQuery);
+    }
 
-    return OC_STACK_OK;
+    if (resourceTypeQuery)
+    {
+        OICFree(resourceTypeQuery);
+    }
+    OCPayloadDestroy(payload);
+    if (dataModelVersions)
+    {
+        OICFree(dataModelVersions);
+    }
+    return discoveryResult;
 }
 
 static OCStackResult
@@ -953,7 +1014,8 @@ HandleDefaultDeviceEntityHandler (OCServerRequest *request)
                                         request->numRcvdVendorSpecificHeaderOptions,
                                         request->rcvdVendorSpecificHeaderOptions,
                                         (OCObserveAction)request->observationOption,
-                                        (OCObservationId)0);
+                                        (OCObservationId)0,
+                                        request->coapID);
     VERIFY_SUCCESS(result, OC_STACK_OK);
 
     // At this point we know for sure that defaultDeviceHandler exists
@@ -979,6 +1041,8 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
                                  OCResource *resource,
                                  uint8_t collectionResource)
 {
+    OC_UNUSED(collectionResource);
+
     if(!request || ! resource)
     {
         return OC_STACK_INVALID_PARAM;
@@ -1000,11 +1064,6 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
 
     }
 
-    if (request && strcmp(request->resourceUrl, OC_RSRVD_RD_URI) == 0)
-    {
-        type = PAYLOAD_TYPE_RD;
-    }
-
     result = FormOCEntityHandlerRequest(&ehRequest,
                                         (OCRequestHandle)request,
                                         request->method,
@@ -1017,7 +1076,8 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
                                         request->numRcvdVendorSpecificHeaderOptions,
                                         request->rcvdVendorSpecificHeaderOptions,
                                         (OCObserveAction)request->observationOption,
-                                        0);
+                                        0,
+                                        request->coapID);
     VERIFY_SUCCESS(result, OC_STACK_OK);
 
     if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
@@ -1025,7 +1085,7 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
         OIC_LOG(INFO, TAG, "No observation requested");
         ehFlag = OC_REQUEST_FLAG;
     }
-    else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER && !collectionResource)
+    else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER)
     {
         OIC_LOG(INFO, TAG, "Observation registration requested");
 
@@ -1062,20 +1122,25 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
             request->observeResult = OC_STACK_OK;
             ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
         }
+        else if (result == OC_STACK_RESOURCE_ERROR)
+        {
+            OIC_LOG(INFO, TAG, "The Resource is not active, discoverable or observable");
+            request->observeResult = OC_STACK_ERROR;
+            ehFlag = OC_REQUEST_FLAG;
+        }
         else
         {
-            result = OC_STACK_OK;
-
             // The error in observeResult for the request will be used when responding to this
             // request by omitting the observation option/sequence number.
             request->observeResult = OC_STACK_ERROR;
             OIC_LOG(ERROR, TAG, "Observer Addition failed");
             ehFlag = OC_REQUEST_FLAG;
+            FindAndDeleteServerRequest(request);
+            goto exit;
         }
 
     }
-    else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER &&
-            !collectionResource)
+    else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER)
     {
         OIC_LOG(INFO, TAG, "Deregistering observation requested");
 
@@ -1097,12 +1162,16 @@ HandleResourceWithEntityHandler (OCServerRequest *request,
         {
             OIC_LOG(INFO, TAG, "Removed observer successfully");
             request->observeResult = OC_STACK_OK;
+            // There should be no observe option header for de-registration response.
+            // Set as an invalid value here so we can detect it later and remove the field in response.
+            request->observationOption = MAX_SEQUENCE_NUMBER + 1;
         }
         else
         {
-            result = OC_STACK_OK;
             request->observeResult = OC_STACK_ERROR;
             OIC_LOG(ERROR, TAG, "Observer Removal failed");
+            FindAndDeleteServerRequest(request);
+            goto exit;
         }
     }
     else
@@ -1151,7 +1220,8 @@ HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
                                         request->numRcvdVendorSpecificHeaderOptions,
                                         request->rcvdVendorSpecificHeaderOptions,
                                         (OCObserveAction)request->observationOption,
-                                        (OCObservationId)0);
+                                        (OCObservationId)0,
+                                        request->coapID);
     if(result == OC_STACK_OK)
     {
         result = DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest);
@@ -1308,8 +1378,11 @@ void DeleteDeviceInfo()
 
     OICFree(savedDeviceInfo.deviceName);
     OCFreeOCStringLL(savedDeviceInfo.types);
+    OICFree(savedDeviceInfo.specVersion);
+    OCFreeOCStringLL(savedDeviceInfo.dataModelVersions);
     savedDeviceInfo.deviceName = NULL;
-
+    savedDeviceInfo.specVersion = NULL;
+    savedDeviceInfo.dataModelVersions = NULL;
 }
 
 static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
@@ -1325,12 +1398,84 @@ static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
     if (info.types)
     {
         savedDeviceInfo.types = CloneOCStringLL(info.types);
+        OCStringLL *type = info.types;
+        bool found = false;
+        while (type)
+        {
+            if (type && type->value && 0 == strcmp(type->value, OC_RSRVD_RESOURCE_TYPE_DEVICE))
+            {
+                found = true;
+            }
+            type = type->next;
+        }
+        if (!found)
+        {
+            // Append the oic.wk.d at the start of rt link parameter value.
+            OCStringLL *dest = (OCStringLL*)OICCalloc (1, sizeof (OCStringLL));
+            if (!dest)
+            {
+                DeleteDeviceInfo();
+                return OC_STACK_NO_MEMORY;
+            }
+            dest->value = OICStrdup (OC_RSRVD_RESOURCE_TYPE_DEVICE);
+            if (!dest->value)
+            {
+                DeleteDeviceInfo();
+                return OC_STACK_NO_MEMORY;
+            }
+            dest->next = savedDeviceInfo.types;
+            savedDeviceInfo.types = dest;
+        }
         if(!savedDeviceInfo.types && info.types)
         {
             DeleteDeviceInfo();
             return OC_STACK_NO_MEMORY;
         }
     }
+
+    if (info.specVersion)
+    {
+        savedDeviceInfo.specVersion = OICStrdup(info.specVersion);
+        if(!savedDeviceInfo.specVersion && info.specVersion)
+        {
+            DeleteDeviceInfo();
+            return OC_STACK_NO_MEMORY;
+        }
+    }
+    else
+    {
+        savedDeviceInfo.specVersion = OICStrdup(OC_SPEC_VERSION);
+        if(!savedDeviceInfo.specVersion && OC_SPEC_VERSION)
+        {
+            DeleteDeviceInfo();
+            return OC_STACK_NO_MEMORY;
+        }
+    }
+
+    if (info.dataModelVersions)
+    {
+        savedDeviceInfo.dataModelVersions = CloneOCStringLL(info.dataModelVersions);
+        if(!savedDeviceInfo.dataModelVersions && info.dataModelVersions)
+        {
+            DeleteDeviceInfo();
+            return OC_STACK_NO_MEMORY;
+        }
+    }
+    else
+    {
+        savedDeviceInfo.dataModelVersions = (OCStringLL *)OICCalloc(1,sizeof(OCStringLL));
+        if (!savedDeviceInfo.dataModelVersions)
+        {
+            return OC_STACK_NO_MEMORY;
+        }
+        savedDeviceInfo.dataModelVersions->value = OICStrdup(OC_DATA_MODEL_VERSION);
+        if(!savedDeviceInfo.dataModelVersions->value && OC_DATA_MODEL_VERSION)
+        {
+            DeleteDeviceInfo();
+            return OC_STACK_NO_MEMORY;
+        }
+    }
+
     return OC_STACK_OK;
 }