[IOT-2537] Filter eps returned from RD queries. 03/21603/6
authorTodd Malsbary <todd.malsbary@intel.com>
Wed, 19 Jul 2017 23:07:54 +0000 (16:07 -0700)
committerDan Mihai <Daniel.Mihai@microsoft.com>
Sat, 19 Aug 2017 02:13:45 +0000 (02:13 +0000)
When resources in the RD are hosted on the same host as the RD server,
the eps returned in the /oic/res response may be filtered identically
to resources hosted by the RD server itself.  This ensures the
response from either the RD or the publishing device is identical.

Bug: https://jira.iotivity.org/browse/IOT-2537
Change-Id: I655fce9919e09305d1a09f2b6a286427e302e606
Signed-off-by: Todd Malsbary <todd.malsbary@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/21603
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Dan Mihai <Daniel.Mihai@microsoft.com>
resource/csdk/resource-directory/include/rd_database.h
resource/csdk/resource-directory/src/internal/rd_database.c
resource/csdk/resource-directory/src/rd_server.c
resource/csdk/stack/include/ocstack.h
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/oicresourcedirectory.c

index 287750e..d50c0d3 100644 (file)
@@ -43,6 +43,16 @@ OCStackResult OC_CALL OCRDDatabaseInit();
  */
 OCStackResult OC_CALL OCRDDatabaseStoreResources(const OCRepPayload *payload);
 
+/**
+ * Stores in database the published resource and marks them as originating at this host so that the
+ * eps can be filtered.
+ *
+ * @param payload is the the published resource payload.
+ *
+ * @return ::OC_STACK_OK in case of success or else other value.
+ */
+OCStackResult OC_CALL OCRDDatabaseStoreResourcesFromThisHost(const OCRepPayload *payload);
+
 /**
  * Delete the RD resources
  *
index 4eca1bc..d54a859 100644 (file)
@@ -56,7 +56,8 @@ static sqlite3 *gRDDB = NULL;
 #define RD_TABLE \
     "create table RD_DEVICE_LIST(ID INTEGER PRIMARY KEY AUTOINCREMENT, " \
     XSTR(OC_RSRVD_DEVICE_ID) " UNIQUE NOT NULL, " \
-    XSTR(OC_RSRVD_TTL) " NOT NULL);"
+    XSTR(OC_RSRVD_TTL) " NOT NULL," \
+    "EXTERNAL_HOST INTEGER NOT NULL);"
 
 #define RD_LL_TABLE  \
     "create table RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)" INTEGER PRIMARY KEY AUTOINCREMENT, " \
@@ -112,7 +113,7 @@ static bool stringArgumentsWithinBounds(const char** arguments, size_t count)
     return true;
 }
 
-static int storeResourceTypes(char **resourceTypes, size_t size, sqlite3_int64 rowid)
+static int storeResourceTypes(const char **resourceTypes, size_t size, sqlite3_int64 rowid)
 {
     int res = 1;
     sqlite3_stmt *stmt = NULL;
@@ -169,7 +170,7 @@ exit:
     return res;
 }
 
-static int storeInterfaces(char **interfaces, size_t size, sqlite3_int64 rowid)
+static int storeInterfaces(const char **interfaces, size_t size, sqlite3_int64 rowid)
 {
     int res = 1;
     sqlite3_stmt *stmt = NULL;
@@ -290,7 +291,7 @@ exit:
     return res;
 }
 
-static int storeLinkPayload(OCRepPayload *rdPayload, sqlite3_int64 rowid)
+static int storeLinkPayload(const OCRepPayload *rdPayload, sqlite3_int64 rowid)
 {
     int res = SQLITE_OK;
 
@@ -413,8 +414,8 @@ static int storeLinkPayload(OCRepPayload *rdPayload, sqlite3_int64 rowid)
                 OCRepPayloadGetStringArray(link, OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
                 OCRepPayloadGetStringArray(link, OC_RSRVD_INTERFACE, &itf, itfDim);
                 OCRepPayloadGetPropObjectArray(link, OC_RSRVD_ENDPOINTS, &eps, epsDim);
-                VERIFY_SQLITE(storeResourceTypes(rt, rtDim[0], ins));
-                VERIFY_SQLITE(storeInterfaces(itf, itfDim[0], ins));
+                VERIFY_SQLITE(storeResourceTypes((const char **) rt, rtDim[0], ins));
+                VERIFY_SQLITE(storeInterfaces((const char **) itf, itfDim[0], ins));
                 VERIFY_SQLITE(storeEndpoints(eps, epsDim[0], ins));
             }
             else
@@ -472,7 +473,7 @@ static int storeLinkPayload(OCRepPayload *rdPayload, sqlite3_int64 rowid)
     return res;
 }
 
-static int storeResources(OCRepPayload *payload)
+static int storeResources(const OCRepPayload *payload, bool externalHost)
 {
     char *deviceId = NULL;
     sqlite3_stmt *stmt = NULL;
@@ -482,15 +483,16 @@ static int storeResources(OCRepPayload *payload)
         return OC_STACK_ERROR;
     }
 
-    sqlite3_int64 ttl = 0;
-    OCRepPayloadGetPropInt(payload, OC_RSRVD_DEVICE_TTL, &ttl);
+    int64_t tmp = 0;
+    OCRepPayloadGetPropInt(payload, OC_RSRVD_DEVICE_TTL, &tmp);
+    sqlite3_int64 ttl = tmp;
 
     int res;
     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
 
     /* INSERT OR IGNORE then UPDATE to update or insert the row without triggering the cascading deletes */
-    static const char insertDeviceList[] = "INSERT OR IGNORE INTO RD_DEVICE_LIST (ID, di, ttl) "
-        "VALUES ((SELECT ID FROM RD_DEVICE_LIST WHERE di=@deviceId), @deviceId, @ttl)";
+    static const char insertDeviceList[] = "INSERT OR IGNORE INTO RD_DEVICE_LIST (ID, di, ttl, external_host) "
+        "VALUES ((SELECT ID FROM RD_DEVICE_LIST WHERE di=@deviceId), @deviceId, @ttl, @external_host)";
     int insertDeviceListSize = (int)sizeof(insertDeviceList);
     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertDeviceList, insertDeviceListSize,
                     &stmt, NULL));
@@ -503,6 +505,8 @@ static int storeResources(OCRepPayload *payload)
     {
         VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@ttl"), ttl));
     }
+    VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@external_host"),
+            externalHost));
     res = sqlite3_step(stmt);
     if (SQLITE_DONE != res)
     {
@@ -717,11 +721,20 @@ exit:
     return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
 }
 
-OCStackResult OC_CALL OCRDDatabaseStoreResources(OCRepPayload *payload)
+OCStackResult OC_CALL OCRDDatabaseStoreResources(const OCRepPayload *payload)
 {
     CHECK_DATABASE_INIT;
     int res;
-    VERIFY_SQLITE(storeResources(payload));
+    VERIFY_SQLITE(storeResources(payload, true));
+exit:
+    return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
+}
+
+OCStackResult OC_CALL OCRDDatabaseStoreResourcesFromThisHost(const OCRepPayload *payload)
+{
+    CHECK_DATABASE_INIT;
+    int res;
+    VERIFY_SQLITE(storeResources(payload, false));
 exit:
     return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
 }
index 606e73f..f0b33df 100644 (file)
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+#ifdef HAVE_IN6ADDR_H
+#include <in6addr.h>
+#endif
 #include "payload_logging.h"
 #include "ocpayload.h"
 #include "octypes.h"
 #include "oic_string.h"
+#include "cainterface.h"
 
 #define TAG PCF("OIC_RD_SERVER")
 
@@ -93,6 +103,54 @@ static OCEntityHandlerResult handleGetRequest(const OCEntityHandlerRequest *ehRe
     return ehResult;
 }
 
+static bool isRequestFromThisHost(const OCEntityHandlerRequest *ehRequest)
+{
+    /* ehRequest->devAddr.addr includes zone ID which inet_pton doesn't like */
+    struct in6_addr addr6;
+    if (ehRequest->devAddr.flags & OC_IP_USE_V6)
+    {
+        char addr[MAX_ADDR_STR_SIZE];
+        const char *src = ehRequest->devAddr.addr;
+        char *dst = addr;
+        while (*src && *src != '%')
+        {
+            *dst++ = *src++;
+        }
+        *dst = '\0';
+        inet_pton(AF_INET6, addr, &addr6);
+    }
+
+    bool fromThisHost = false;
+    CAEndpoint_t *caEps = NULL;
+    size_t nCaEps = 0;
+    if (CA_STATUS_OK == CAGetNetworkInformation(&caEps, &nCaEps))
+    {
+        for (size_t i = 0; i < nCaEps; ++i)
+        {
+            if (caEps[i].flags & ehRequest->devAddr.flags & OC_IP_USE_V6)
+            {
+                struct in6_addr ca6;
+                if ((1 == inet_pton(AF_INET6, caEps[i].addr, &ca6)) &&
+                        !memcmp(&ca6, &addr6, sizeof(struct in6_addr)))
+                {
+                    fromThisHost = true;
+                    break;
+                }
+            }
+            else if (!strcmp(caEps[i].addr, ehRequest->devAddr.addr))
+            {
+                fromThisHost = true;
+                break;
+            }
+        }
+        if (caEps)
+        {
+            OICFree(caEps);
+        }
+    }
+    return fromThisHost;
+}
+
 /**
  * This internal method handles RD publish request.
  * Responds with the RD success message.
@@ -116,7 +174,16 @@ static OCEntityHandlerResult handlePublishRequest(const OCEntityHandlerRequest *
         OIC_LOG_PAYLOAD(DEBUG, (OCPayload *) payload);
         if (OC_STACK_OK == OCRDDatabaseInit())
         {
-            if (OC_STACK_OK == OCRDDatabaseStoreResources(payload))
+            OCStackResult result;
+            if (isRequestFromThisHost(ehRequest))
+            {
+                result = OCRDDatabaseStoreResourcesFromThisHost(payload);
+            }
+            else
+            {
+                result = OCRDDatabaseStoreResources(payload);
+            }
+            if (OC_STACK_OK == result)
             {
                 OIC_LOG_V(DEBUG, TAG, "Stored resources.");
                 resPayload = payload;
index da59c7f..7a94b8c 100644 (file)
@@ -736,6 +736,22 @@ const char *OC_CALL OCRDDatabaseGetStorageFilename();
 OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType,
                                                  const char *resourceType,
                                                  OCDiscoveryPayload **discPayload);
+
+/**
+* Search the RD database for queries.
+*
+* @param interfaceType is the interface type that is queried.
+* @param resourceType is the resource type that is queried.
+* @param endpoint is the requesting endpoint to filter created eps value against.
+* @param discPayload NULL if no resource found or else OCDiscoveryPayload with the details
+* about the resources.
+*
+* @return ::OC_STACK_OK in case of success or else other value.
+*/
+OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreateWithEp(const char *interfaceType,
+                                                 const char *resourceType,
+                                                 OCDevAddr *endpoint,
+                                                 OCDiscoveryPayload **discPayload);
 #endif // RD_SERVER
 #endif // RD_CLIENT || RD_SERVER
 
index 4fa0a9c..6ed1199 100644 (file)
@@ -1194,7 +1194,7 @@ OCStackResult BuildIntrospectionResponseRepresentation(const OCResource *resourc
                 char *proto = NULL;
 
                 // consider IP or TCP adapter for payload that is visible to the client
-                if (((CA_ADAPTER_IP | CA_ADAPTER_TCP) & info->adapter) && 
+                if (((CA_ADAPTER_IP | CA_ADAPTER_TCP) & info->adapter) &&
                     (info->ifindex == devAddr->ifindex))
                 {
                     OCTpsSchemeFlags matchedTps = OC_NO_TPS;
@@ -1651,13 +1651,15 @@ static OCStackResult EHRequest(OCEntityHandlerRequest *ehRequest, OCPayloadType
  * In case if RD server is not started, it returns ::OC_STACK_NO_RESOURCE.
  */
 static OCStackResult findResourcesAtRD(const char *interfaceQuery,
-                                       const char *resourceTypeQuery, OCDiscoveryPayload **discPayload)
+                                       const char *resourceTypeQuery,
+                                       OCDevAddr *endpoint,
+                                       OCDiscoveryPayload **discPayload)
 {
     OCStackResult result = OC_STACK_NO_RESOURCE;
     if (OCGetResourceHandleAtUri(OC_RSRVD_RD_URI) != NULL)
     {
-        result = OCRDDatabaseDiscoveryPayloadCreate(interfaceQuery, resourceTypeQuery,
-            (*discPayload) ? &(*discPayload)->next : discPayload);
+        result = OCRDDatabaseDiscoveryPayloadCreateWithEp(interfaceQuery, resourceTypeQuery,
+                endpoint, (*discPayload) ? &(*discPayload)->next : discPayload);
     }
     if ((*discPayload) && (*discPayload)->resources)
     {
@@ -1886,7 +1888,8 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
             OICFree(networkInfo);
         }
 #ifdef RD_SERVER
-        discoveryResult = findResourcesAtRD(interfaceQuery, resourceTypeQuery, (OCDiscoveryPayload **)&payload);
+        discoveryResult = findResourcesAtRD(interfaceQuery, resourceTypeQuery, &request->devAddr,
+                (OCDiscoveryPayload **)&payload);
 #endif
     }
     else if (virtualUriInRequest == OC_DEVICE_URI)
@@ -2577,7 +2580,7 @@ static OCStackResult IsDatabaseUpdateNeeded(const char *attribute, const void *v
         }
         else
         {
-            OIC_LOG_V(ERROR, TAG, 
+            OIC_LOG_V(ERROR, TAG,
                 "Call to OCGetPropertyValue for the current PIID failed with error: %d", result);
         }
     }
@@ -2597,7 +2600,7 @@ OCStackResult OC_CALL OCSetAttribute(OCResource *resource, const char *attribute
     // write.
     if (OC_STACK_OK != IsDatabaseUpdateNeeded(attribute, value, &updateDatabase))
     {
-        OIC_LOG_V(WARNING, TAG, 
+        OIC_LOG_V(WARNING, TAG,
             "Could not determine if a database update was needed for %s. Proceeding without updating the database.",
             attribute);
         updateDatabase = false;
index 92945fb..42de22a 100644 (file)
@@ -34,6 +34,7 @@
 #include "ocendpoint.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
+#include "cainterface.h"
 
 #define TAG "OIC_RI_RESOURCEDIRECTORY"
 
@@ -133,7 +134,8 @@ exit:
 }
 
 /* stmt is of form "SELECT * FROM RD_DEVICE_LINK_LIST ..." */
-static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDiscoveryPayload *discPayload)
+static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDevAddr *devAddr,
+        OCDiscoveryPayload *discPayload)
 {
     int res = sqlite3_step(stmt);
     if (SQLITE_ROW != res)
@@ -208,6 +210,16 @@ static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDiscoveryPayloa
 
         resourcePayload->bitmap = (uint8_t)(bitmap & (OC_OBSERVABLE | OC_DISCOVERABLE));
 
+        CAEndpoint_t *networkInfo = NULL;
+        size_t infoSize = 0;
+        if (devAddr)
+        {
+            CAResult_t caResult = CAGetNetworkInformation(&networkInfo, &infoSize);
+            if (CA_STATUS_FAILED == caResult)
+            {
+                OIC_LOG(WARNING, TAG, "CAGetNetworkInformation has error on parsing network infomation");
+            }
+        }
         const char ep[] = "SELECT ep,pri FROM RD_LINK_EP WHERE LINK_ID=@id";
         int epSize = (int)sizeof(ep);
         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, ep, epSize, &stmtEP, NULL));
@@ -224,16 +236,45 @@ static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDiscoveryPayloa
             }
             sqlite3_int64 pri = sqlite3_column_int64(stmtEP, pri_value_index);
             epPayload->pri = (uint16_t)pri;
-            OCEndpointPayload **tmp = &resourcePayload->eps;
-            while (*tmp)
+            bool includeEp = true;
+            if (devAddr)
+            {
+                CAEndpoint_t *info = NULL;
+                for (size_t i = 0; i < infoSize; ++i)
+                {
+                    if (!strcmp(epPayload->addr, networkInfo[i].addr))
+                    {
+                        info = &networkInfo[i];
+                        break;
+                    }
+                }
+                includeEp = info &&
+                        (((OC_ADAPTER_IP | OC_ADAPTER_TCP) & (devAddr->adapter)) &&
+                        ((((CA_ADAPTER_IP | CA_ADAPTER_TCP) & info->adapter) &&
+                                (info->ifindex == devAddr->ifindex)) ||
+                                info->adapter == CA_ADAPTER_RFCOMM_BTEDR));
+            }
+            if (includeEp)
             {
-                tmp = &(*tmp)->next;
+                OCEndpointPayload **tmp = &resourcePayload->eps;
+                while (*tmp)
+                {
+                    tmp = &(*tmp)->next;
+                }
+                *tmp = epPayload;
+            }
+            else
+            {
+                OICFree(epPayload);
             }
-            *tmp = epPayload;
             epPayload = NULL;
         }
         VERIFY_SQLITE(sqlite3_finalize(stmtEP));
         stmtEP = NULL;
+        if (networkInfo)
+        {
+            OICFree(networkInfo);
+        }
 
         const char di[] = "SELECT di FROM RD_DEVICE_LIST "
             "INNER JOIN RD_DEVICE_LINK_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID = RD_DEVICE_LIST.ID "
@@ -270,7 +311,7 @@ exit:
 }
 
 static OCStackResult CheckResources(const char *interfaceType, const char *resourceType,
-        OCDiscoveryPayload *discPayload)
+        OCDevAddr *devAddr, OCDiscoveryPayload *discPayload)
 {
     if (!interfaceType && !resourceType)
     {
@@ -328,7 +369,7 @@ static OCStackResult CheckResources(const char *interfaceType, const char *resou
             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@interfaceType"),
                             interfaceType, (int)interfaceTypeLength, SQLITE_STATIC));
         }
-        result = ResourcePayloadCreate(stmt, discPayload);
+        result = ResourcePayloadCreate(stmt, devAddr, discPayload);
     }
     else if (interfaceType)
     {
@@ -356,7 +397,7 @@ static OCStackResult CheckResources(const char *interfaceType, const char *resou
             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@interfaceType"),
                             interfaceType, (int)interfaceTypeLength, SQLITE_STATIC));
         }
-        result = ResourcePayloadCreate(stmt, discPayload);
+        result = ResourcePayloadCreate(stmt, devAddr, discPayload);
     }
 
 exit:
@@ -365,8 +406,13 @@ exit:
 }
 
 OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType,
-        const char *resourceType,
-        OCDiscoveryPayload **payload)
+        const char *resourceType, OCDiscoveryPayload **payload)
+{
+    return OCRDDatabaseDiscoveryPayloadCreateWithEp(interfaceType, resourceType, NULL, payload);
+}
+
+OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreateWithEp(const char *interfaceType,
+        const char *resourceType, OCDevAddr *endpoint, OCDiscoveryPayload **payload)
 {
     OCStackResult result;
     OCDiscoveryPayload *head = NULL;
@@ -396,9 +442,10 @@ OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceTy
     }
 
     const char *serverID = OCGetServerInstanceIDString();
-    const char input[] = "SELECT di FROM RD_DEVICE_LIST";
+    const char input[] = "SELECT di, external_host FROM RD_DEVICE_LIST";
     int inputSize = (int)sizeof(input);
     const uint8_t di_index = 0;
+    const uint8_t external_host_index = 1;
     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
     while (SQLITE_ROW == sqlite3_step(stmt))
     {
@@ -407,13 +454,14 @@ OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceTy
         {
             continue;
         }
+        sqlite3_int64 externalHost = sqlite3_column_int64(stmt, external_host_index);
         *tail = OCDiscoveryPayloadCreate();
         result = OC_STACK_INTERNAL_SERVER_ERROR;
         VERIFY_NON_NULL(*tail);
         (*tail)->sid = (char *)OICCalloc(1, UUID_STRING_SIZE);
         VERIFY_NON_NULL((*tail)->sid);
         memcpy((*tail)->sid, di, UUID_STRING_SIZE);
-        result = CheckResources(interfaceType, resourceType, *tail);
+        result = CheckResources(interfaceType, resourceType, externalHost ? NULL : endpoint, *tail);
         if (OC_STACK_OK == result)
         {
             tail = &(*tail)->next;