Delete links lazily when TTL is reached. 09/22709/6
authorHabib Virji <habib.virji@samsung.com>
Tue, 3 Oct 2017 16:28:50 +0000 (17:28 +0100)
committerMushfiqul Islam <i.mushfiq@samsung.com>
Thu, 9 Nov 2017 05:55:40 +0000 (05:55 +0000)
Add ttl parameter to RD client APIs.

Bug: https://jira.iotivity.org/browse/IOT-1935
Change-Id: Ic189cebebbcf8127bea1d127dd11a116e09743bb
Signed-off-by: Habib Virji <habib.virji@samsung.com>
Signed-off-by: Todd Malsbary <todd.malsbary@intel.com>
12 files changed:
cloud/samples/client/thin_light/thin_room_light.cpp
resource/csdk/resource-directory/include/RDClient.h
resource/csdk/resource-directory/include/rd_client.h
resource/csdk/resource-directory/samples/rd_publishingClient.cpp
resource/csdk/resource-directory/src/RDClient.cpp
resource/csdk/resource-directory/src/internal/rd_database.c
resource/csdk/resource-directory/src/rd_client.c
resource/csdk/resource-directory/src/rd_server.c
resource/csdk/resource-directory/unittests/rddatabase.cpp
resource/csdk/resource-directory/unittests/rdtests.cpp
resource/csdk/stack/src/oicresourcedirectory.c
service/notification/src/provider/NSProviderResource.c

index 3f1b5d0..6da7701 100644 (file)
@@ -516,7 +516,7 @@ void PublishResources(string host)
         cout << "Publishing device info failed" << endl;
     }
 
-    res = OCRDPublish(nullptr, host.c_str(), CT_ADAPTER_TCP, NULL, 0, &cbData, OC_LOW_QOS);
+    res = OCRDPublish(nullptr, host.c_str(), CT_ADAPTER_TCP, NULL, 0, OIC_RD_PUBLISH_TTL, &cbData, OC_LOW_QOS);
     if (res != OC_STACK_OK)
     {
         cout << "Unable to publish default resources to cloud" << endl;
@@ -524,7 +524,7 @@ void PublishResources(string host)
 
     cout << "Publishing user resources" << endl;
 
-    res = OCRDPublish(nullptr, host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, &cbData, OC_LOW_QOS);
+    res = OCRDPublish(nullptr, host.c_str(), CT_ADAPTER_TCP, resourceHandles, 1, OIC_RD_PUBLISH_TTL, &cbData, OC_LOW_QOS);
     if (res != OC_STACK_OK)
     {
         cout << "Unable to publish user resources to cloud" << endl;
index b1aa711..294da85 100644 (file)
@@ -21,6 +21,7 @@
 #include "OCRepresentation.h"
 #include "OCApi.h"
 #include "octypes.h"
+#include "rd_client.h"
 
 typedef std::function<void(const OC::OCRepresentation&, const int)> PublishResourceCallback;
 typedef std::function<void(const int)> DeleteResourceCallback;
@@ -77,19 +78,47 @@ public:
     OCStackResult publishResourceToRD(const std::string& host,
                                       OCConnectivityType connectivityType,
                                       OC::ResourceHandles& resourceHandles,
+                                      uint32_t ttl,
                                       PublishResourceCallback callback);
 
     OCStackResult publishResourceToRD(const std::string& host,
                                      OCConnectivityType connectivityType,
+                                     uint32_t ttl,
                                      PublishResourceCallback callback,
                                      QualityOfService qos);
 
     OCStackResult publishResourceToRD(const std::string& host,
                                       OCConnectivityType connectivityType,
                                       OC::ResourceHandles& resourceHandles,
+                                      uint32_t ttl,
                                       PublishResourceCallback callback,
                                       QualityOfService qos);
 
+    OCStackResult publishResourceToRD(const std::string& host,
+                                      OCConnectivityType connectivityType,
+                                      OC::ResourceHandles& resourceHandles,
+                                      PublishResourceCallback callback)
+    {
+        return publishResourceToRD(host, connectivityType, resourceHandles, OIC_RD_PUBLISH_TTL, callback);
+    }
+
+    OCStackResult publishResourceToRD(const std::string& host,
+                                     OCConnectivityType connectivityType,
+                                     PublishResourceCallback callback,
+                                     QualityOfService qos)
+    {
+        return publishResourceToRD(host, connectivityType, OIC_RD_PUBLISH_TTL, callback, qos);
+    }
+
+    OCStackResult publishResourceToRD(const std::string& host,
+                                      OCConnectivityType connectivityType,
+                                      OC::ResourceHandles& resourceHandles,
+                                      PublishResourceCallback callback,
+                                      QualityOfService qos)
+    {
+        return publishResourceToRD(host, connectivityType, resourceHandles, OIC_RD_PUBLISH_TTL, callback, qos);
+    }
+
     /**
      * API for published resource delete from Resource Directory.
      * @note This API applies to resource server side only.
index dddcb37..8ed6aca 100644 (file)
@@ -30,16 +30,12 @@ extern "C" {
 
 #ifdef RD_CLIENT
 
+/** Default TTL to use when publishing resources. */
 #define OIC_RD_PUBLISH_TTL 86400
 
-#define OIC_RD_DEFAULT_RESOURCE 2
-
 /** JSON media type. */
 #define OC_MEDIA_TYPE_APPLICATION_JSON   "application/json"
 
-/** Platform Model Number.*/
-#define OC_DATA_MODEL_NUMBER            "x.model"
-
 /**
  * Discover Local RD across the network.
  *
@@ -73,6 +69,7 @@ OCStackResult OC_CALL OCRDDiscover(OCDoHandle *handle, OCConnectivityType connec
  * @param connectivityType  Type of connectivity indicating the interface.
  * @param resourceHandles   This is the resource handle which we need to register to RD.
  * @param nHandles          The counts of resource handle.
+ * @param ttl               The time to live, in seconds.
  * @param cbData            Asynchronous callback function that is invoked by the stack when
  *                          response is received. The callback is generated for each response
  *                          received.
@@ -82,7 +79,7 @@ OCStackResult OC_CALL OCRDDiscover(OCDoHandle *handle, OCConnectivityType connec
  */
 OCStackResult OC_CALL OCRDPublish(OCDoHandle *handle, const char *host,
                           OCConnectivityType connectivityType,
-                          OCResourceHandle *resourceHandles, uint8_t nHandles,
+                          OCResourceHandle *resourceHandles, uint8_t nHandles, uint32_t ttl,
                           OCCallbackData *cbData, OCQualityOfService qos);
 
 /**
@@ -99,6 +96,7 @@ OCStackResult OC_CALL OCRDPublish(OCDoHandle *handle, const char *host,
  * @param connectivityType  Type of connectivity indicating the interface.
  * @param resourceHandles   This is the resource handle which we need to register to RD.
  * @param nHandles          The counts of resource handle.
+ * @param ttl               The time to live, in seconds.
  * @param cbData            Asynchronous callback function that is invoked by the stack when
  *                          response is received. The callback is generated for each response
  *                          received.
@@ -109,7 +107,7 @@ OCStackResult OC_CALL OCRDPublish(OCDoHandle *handle, const char *host,
 OCStackResult OC_CALL OCRDPublishWithDeviceId(OCDoHandle *handle, const char *host,
                                       const unsigned char *id,
                                       OCConnectivityType connectivityType,
-                                      OCResourceHandle *resourceHandles, uint8_t nHandles,
+                                      OCResourceHandle *resourceHandles, uint8_t nHandles, uint32_t ttl,
                                       OCCallbackData *cbData, OCQualityOfService qos);
 
 /**
index 6a5be55..d7d5d3f 100644 (file)
@@ -156,7 +156,7 @@ int main()
                 cbData.context = (void*) DEFAULT_CONTEXT_VALUE;
                 std::string address = rdAddress.str();
                 OCRDPublish(nullptr, address.c_str(), CT_ADAPTER_IP, handles,
-                            2, &cbData, OC_LOW_QOS);
+                            2, OIC_RD_PUBLISH_TTL, &cbData, OC_LOW_QOS);
                 break;
             }
             case 3:
index f75f64e..96c766f 100644 (file)
@@ -32,7 +32,6 @@
 #include "ocpayload.h"
 
 #include "RDClient.h"
-#include "rd_client.h"
 
 using namespace OC;
 
@@ -93,23 +92,26 @@ OCStackApplicationResult publishResourceToRDCallback(void* ctx, OCDoHandle /*han
 OCStackResult RDClient::publishResourceToRD(const std::string& host,
                                             OCConnectivityType connectivityType,
                                             ResourceHandles& resourceHandles,
+                                            uint32_t ttl,
                                             PublishResourceCallback callback)
 {
-    return publishResourceToRD(host, connectivityType, resourceHandles, callback, static_cast<QualityOfService>(m_qos));
+    return publishResourceToRD(host, connectivityType, resourceHandles, ttl, callback, static_cast<QualityOfService>(m_qos));
 }
 
 OCStackResult RDClient::publishResourceToRD(const std::string& host,
                                             OCConnectivityType connectivityType,
+                                            uint32_t ttl,
                                             PublishResourceCallback callback,
                                             QualityOfService qos)
 {
     ResourceHandles resourceHandles;
-    return publishResourceToRD(host, connectivityType, resourceHandles, callback, qos);
+    return publishResourceToRD(host, connectivityType, resourceHandles, ttl, callback, qos);
 }
 
 OCStackResult RDClient::publishResourceToRD(const std::string& host,
                                    OCConnectivityType connectivityType,
                                    ResourceHandles& resourceHandles,
+                                   uint32_t ttl,
                                    PublishResourceCallback callback,
                                    QualityOfService qos)
 {
@@ -132,7 +134,7 @@ OCStackResult RDClient::publishResourceToRD(const std::string& host,
             throw OCException(OC::Exception::PUBLISH_RESOURCE_FAILED, result);
         }
         result = OCRDPublish(nullptr, host.c_str(), connectivityType, &resourceHandles[0],
-                             (uint8_t)resourceHandles.size(), &cbdata, static_cast<OCQualityOfService>(qos));
+                             (uint8_t)resourceHandles.size(), ttl, &cbdata, static_cast<OCQualityOfService>(qos));
     }
 
     if (OC_STACK_OK != result)
index 8caf709..6365f37 100644 (file)
@@ -28,6 +28,7 @@
 #include "octypes.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
+#include "oic_time.h"
 #include "ocstackinternal.h"
 
 #ifdef RD_SERVER
@@ -498,7 +499,8 @@ static int storeResources(const OCRepPayload *payload, bool externalHost)
     {
         return SQLITE_ERROR;
     }
-    sqlite3_int64 ttl = tmp;
+    /* Add current time in front of the seconds received from the Publishing Device */
+    sqlite3_int64 ttl = (tmp * US_PER_SEC) + OICGetCurrentTime(TIME_IN_US);
 
     /* links is a required property */
     OCRepPayloadValue *links = getLinks(payload);
@@ -734,6 +736,7 @@ OCStackResult OC_CALL OCRDDatabaseClose()
     int res;
     VERIFY_SQLITE(sqlite3_close(gRDDB));
     gRDDB = NULL;
+
 exit:
     return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
 }
index a06d1b8..7cc046f 100644 (file)
@@ -37,6 +37,8 @@
 
 #ifdef RD_CLIENT
 
+#define OIC_RD_DEFAULT_RESOURCE 2
+
 OCStackResult OC_CALL OCRDDiscover(OCDoHandle *handle, OCConnectivityType connectivityType,
                                    OCCallbackData *cbBiasFactor, OCQualityOfService qos)
 {
@@ -122,7 +124,7 @@ exit:
 
 OCStackResult OC_CALL OCRDPublish(OCDoHandle *handle, const char *host,
                                   OCConnectivityType connectivityType,
-                                  OCResourceHandle *resourceHandles, uint8_t nHandles,
+                                  OCResourceHandle *resourceHandles, uint8_t nHandles, uint32_t ttl,
                                   OCCallbackData *cbData, OCQualityOfService qos)
 {
     // Validate input parameters.
@@ -139,12 +141,12 @@ OCStackResult OC_CALL OCRDPublish(OCDoHandle *handle, const char *host,
     // Get Device ID from stack.
     const unsigned char *id = (const unsigned char *) OCGetServerInstanceIDString();
 
-    return OCRDPublishWithDeviceId(handle, host, id, connectivityType, resourceHandles, nHandles,
+    return OCRDPublishWithDeviceId(handle, host, id, connectivityType, resourceHandles, nHandles, ttl,
                                    cbData, qos);
 }
 
 static OCRepPayload *RDPublishPayloadCreate(const unsigned char *id,
-        const OCResourceHandle *resourceHandles, uint8_t nHandles)
+        const OCResourceHandle *resourceHandles, uint8_t nHandles, uint32_t ttl)
 {
     assert(id);
 
@@ -193,7 +195,7 @@ static OCRepPayload *RDPublishPayloadCreate(const unsigned char *id,
 
     // oic.wk.rdpub properties
     OCRepPayloadSetPropString(rdPayload, OC_RSRVD_DEVICE_ID, (const char*) id);
-    OCRepPayloadSetPropInt(rdPayload, OC_RSRVD_DEVICE_TTL, OIC_RD_PUBLISH_TTL);
+    OCRepPayloadSetPropInt(rdPayload, OC_RSRVD_DEVICE_TTL, ttl);
 
     dim[0] = nHandles;
     OCRepPayload **links = (OCRepPayload **)OICCalloc(dim[0], sizeof(OCRepPayload *));
@@ -327,7 +329,7 @@ exit:
 OCStackResult OC_CALL OCRDPublishWithDeviceId(OCDoHandle *handle, const char *host,
                                               const unsigned char *id,
                                               OCConnectivityType connectivityType,
-                                              OCResourceHandle *resourceHandles, uint8_t nHandles,
+                                              OCResourceHandle *resourceHandles, uint8_t nHandles, uint32_t ttl,
                                               OCCallbackData *cbData, OCQualityOfService qos)
 {
     // Validate input parameters.
@@ -383,7 +385,7 @@ OCStackResult OC_CALL OCRDPublishWithDeviceId(OCDoHandle *handle, const char *ho
     snprintf(targetUri, MAX_URI_LENGTH, "%s%s", host, OC_RSRVD_RD_URI);
     OIC_LOG_V(DEBUG, TAG, "Target URI: %s", targetUri);
 
-    OCRepPayload *rdPayload = RDPublishPayloadCreate(id, pubResHandle, nPubResHandles);
+    OCRepPayload *rdPayload = RDPublishPayloadCreate(id, pubResHandle, nPubResHandles, ttl);
     if (!rdPayload)
     {
         return OC_STACK_ERROR;
index f089ff9..cf9d638 100644 (file)
@@ -278,7 +278,7 @@ static OCEntityHandlerResult handleDeleteRequest(const OCEntityHandlerRequest *e
         {
             // Arduino's AVR-GCC doesn't support strtoll().
             int64_t i;
-            int matchedItems = sscanf(value, "%lld", &i);
+            int matchedItems = sscanf(value, "%"PRId64, &i);
             if (0 == matchedItems)
             {
                 OIC_LOG_V(ERROR, TAG, "Invalid ins query parameter: %s", value);
index d3d8910..8b53d1a 100644 (file)
@@ -96,6 +96,7 @@ typedef struct Resource
 } Resource;
 
 static OCRepPayload *CreateRDPublishPayload(const char *deviceId,
+                                            int64_t ttl,
                                             Resource *resources,
                                             size_t nresources)
 {
@@ -103,7 +104,7 @@ static OCRepPayload *CreateRDPublishPayload(const char *deviceId,
     EXPECT_TRUE(repPayload != NULL);
     EXPECT_TRUE(deviceId != NULL);
     EXPECT_TRUE(OCRepPayloadSetPropString(repPayload, OC_RSRVD_DEVICE_ID, deviceId));
-    EXPECT_TRUE(OCRepPayloadSetPropInt(repPayload, OC_RSRVD_DEVICE_TTL, 86400));
+    EXPECT_TRUE(OCRepPayloadSetPropInt(repPayload, OC_RSRVD_DEVICE_TTL, (ttl == 0 ? 86400: ttl)));
 
     const OCRepPayload *linkArr[nresources];
     size_t dimensions[MAX_REP_ARRAY_DEPTH] = {nresources, 0, 0};
@@ -205,7 +206,7 @@ static OCRepPayload *CreateResources(const char *deviceId)
         { "/a/thermostat", "core.thermostat", OC_RSRVD_INTERFACE_DEFAULT, OC_DISCOVERABLE },
         { "/a/light", "core.light", OC_RSRVD_INTERFACE_DEFAULT, OC_DISCOVERABLE }
     };
-    return CreateRDPublishPayload(deviceId, resources, 2);
+    return CreateRDPublishPayload(deviceId, 0, resources, 2);
 }
 
 TEST_F(RDDatabaseTests, Create)
@@ -252,7 +253,7 @@ TEST_F(RDDatabaseTests, AddResources)
     Resource resources[] = {
         { "/a/light2", "core.light", OC_RSRVD_INTERFACE_DEFAULT, OC_DISCOVERABLE }
     };
-    repPayload = CreateRDPublishPayload(deviceId, resources, 1);
+    repPayload = CreateRDPublishPayload(deviceId, 0, resources, 1);
     EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload));
     OCPayloadDestroy((OCPayload *)repPayload);
 
@@ -299,7 +300,7 @@ TEST_F(RDDatabaseTests, UpdateResources)
         { "/a/thermostat", "x.core.r.thermostat", "x.core.if.thermostat", OC_DISCOVERABLE | OC_OBSERVABLE },
         { "/a/light", "x.core.r.light", "x.core.if.light", OC_DISCOVERABLE | OC_OBSERVABLE }
     };
-    repPayload = CreateRDPublishPayload(deviceId, resources, 2);
+    repPayload = CreateRDPublishPayload(deviceId, 0, resources, 2);
     EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload));
     OCPayloadDestroy((OCPayload *)repPayload);
 
@@ -354,7 +355,7 @@ TEST_F(RDDatabaseTests, AddAndUpdateResources)
         { "/a/light", "x.core.r.light", "x.core.if.light", OC_DISCOVERABLE | OC_OBSERVABLE },
         { "/a/light2", "core.light", OC_RSRVD_INTERFACE_DEFAULT, OC_DISCOVERABLE }
     };
-    repPayload = CreateRDPublishPayload(deviceId, resources, 3);
+    repPayload = CreateRDPublishPayload(deviceId, 0, resources, 3);
     EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload));
     OCPayloadDestroy((OCPayload *)repPayload);
 
@@ -447,3 +448,44 @@ TEST_F(RDDatabaseTests, DeleteResourcesDevice)
     OCPayloadDestroy((OCPayload *)payloads[0]);
     OCPayloadDestroy((OCPayload *)payloads[1]);
 }
+
+TEST_F(RDDatabaseTests, TTLLapsedDeleteDevice)
+{
+    itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
+
+    const char *deviceIds[2] =
+    {
+        "7a960f46-a52e-4837-bd83-460b1a6dd56b",
+        "983656a7-c7e5-49c2-a201-edbeb7606fb5",
+    };
+    OCRepPayload *repPayload = CreateResources(deviceIds[0]);
+    ASSERT_TRUE(NULL != repPayload) << "CreateResources failed!";
+    EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload));
+    OCPayloadDestroy((OCPayload *)repPayload);
+
+    Resource resources[] = {
+        { "/a/light2", "core.light", OC_RSRVD_INTERFACE_DEFAULT, OC_DISCOVERABLE }
+    };
+    repPayload = CreateRDPublishPayload(deviceIds[0], 1, resources, 1);
+    EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload));
+    OCPayloadDestroy((OCPayload *)repPayload);
+    repPayload = CreateRDPublishPayload(deviceIds[1], OIC_RD_PUBLISH_TTL, resources, 1);
+    EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload));
+    OCPayloadDestroy((OCPayload *)repPayload);
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    OCDiscoveryPayload *discPayload = NULL;
+    EXPECT_EQ(OC_STACK_OK, OCRDDatabaseDiscoveryPayloadCreate(OC_RSRVD_INTERFACE_LL, NULL, &discPayload));
+    bool found = false;
+    for (OCDiscoveryPayload *payload = discPayload; payload; payload = payload->next)
+    {
+        if (!strcmp(deviceIds[0], payload->sid))
+        {
+            found = true;
+        }
+    }
+    EXPECT_FALSE(found);
+    OCDiscoveryPayloadDestroy(discPayload);
+    discPayload = NULL;
+}
index 1eb2496..ce80b9f 100644 (file)
@@ -203,14 +203,14 @@ TEST_F(RDTests, CreateRDResource)
 TEST_F(RDTests, RDPublishResourceNullAddr)
 {
     itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
-    EXPECT_EQ(OC_STACK_INVALID_IP, OCRDPublish(NULL, 0, CT_ADAPTER_IP, nullptr, 0, 0, OC_LOW_QOS));
+    EXPECT_EQ(OC_STACK_INVALID_IP, OCRDPublish(NULL, 0, CT_ADAPTER_IP, nullptr, 0, 0, 0, OC_LOW_QOS));
 }
 
 TEST_F(RDTests, RDPublishResourceNullCB)
 {
     itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
     EXPECT_EQ(OC_STACK_INVALID_CALLBACK, OCRDPublish(NULL, "127.0.0.1", CT_ADAPTER_IP, nullptr,
-                                                     0, 0, OC_LOW_QOS));
+                                                     0, 0, 0, OC_LOW_QOS));
 }
 
 TEST_F(RDTests, RDPublishResource)
@@ -229,7 +229,7 @@ TEST_F(RDTests, RDPublishResource)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
 
     EXPECT_EQ(OC_STACK_OK, OCRDPublish(NULL, "127.0.0.1", CT_ADAPTER_IP, &handle,
-                                       1, &cbData, OC_LOW_QOS));
+                                       1, OIC_RD_PUBLISH_TTL, &cbData, OC_LOW_QOS));
 }
 
 TEST_F(RDTests, RDPublishMultipleResources)
@@ -251,7 +251,7 @@ TEST_F(RDTests, RDPublishMultipleResources)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
 
     EXPECT_EQ(OC_STACK_OK, OCRDPublish(NULL, "127.0.0.1", CT_ADAPTER_IP, handles,
-                                       2, &cbData, OC_LOW_QOS));
+                                       2, OIC_RD_PUBLISH_TTL, &cbData, OC_LOW_QOS));
 }
 
 TEST_F(RDTests, RDDeleteResourceNullAddr)
@@ -424,7 +424,7 @@ TEST_P(RDDiscoverTests, DiscoverAllResources)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
-              2, publishCB, OC_LOW_QOS));
+              2, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     itst::Callback discoverCB(&DiscoverAllResourcesVerify);
@@ -470,7 +470,7 @@ TEST_P(RDDiscoverTests, ResourceQueryMatchesLocalAndRemote)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
-              1, publishCB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     itst::Callback discoverCB(&ResourceQueryMatchesLocalAndRemoteVerify);
@@ -510,7 +510,7 @@ TEST_P(RDDiscoverTests, ResourceQueryMatchesLocalOnly)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publishCB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     OIC_LOG(INFO, TAG, "Published");
@@ -631,15 +631,15 @@ TEST_P(RDDiscoverTests, DatabaseHas0ResourceQueryMatches)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publish0CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
     itst::Callback publish1CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2],
-              1, publish1CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish1CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish1CB.Wait(100));
     itst::Callback publish2CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3],
-              1, publish2CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish2CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish2CB.Wait(100));
 
     itst::Callback discoverCB(&DatabaseHas0ResourceQueryMatchesVerify);
@@ -697,15 +697,15 @@ TEST_P(RDDiscoverTests, DatabaseHas1ResourceQueryMatch)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publish0CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
     itst::Callback publish1CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2],
-              1, publish1CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish1CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish1CB.Wait(100));
     itst::Callback publish2CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3],
-              1, publish2CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish2CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish2CB.Wait(100));
 
     itst::Callback discoverCB(&DatabaseHas1ResourceQueryMatchVerify);
@@ -765,15 +765,15 @@ TEST_P(RDDiscoverTests, DatabaseHasNResourceQueryMatches)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publish0CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
     itst::Callback publish1CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2],
-              1, publish1CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish1CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish1CB.Wait(100));
     itst::Callback publish2CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3],
-              1, publish2CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish2CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish2CB.Wait(100));
 
     itst::Callback discoverCB(&DatabaseHasNResourceQueryMatchesVerify);
@@ -818,15 +818,15 @@ TEST_P(RDDiscoverTests, DatabaseHas0InterfaceQueryMatches)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publish0CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
     itst::Callback publish1CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2],
-              1, publish1CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish1CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish1CB.Wait(100));
     itst::Callback publish2CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3],
-              1, publish2CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish2CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish2CB.Wait(100));
 
     itst::Callback discoverCB(&DatabaseHas0InterfaceQueryMatchesVerify);
@@ -894,15 +894,15 @@ TEST_P(RDDiscoverTests, DatabaseHas1InterfaceQueryMatch)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publish0CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
     itst::Callback publish1CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2],
-              1, publish1CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish1CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish1CB.Wait(100));
     itst::Callback publish2CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3],
-              1, publish2CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish2CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish2CB.Wait(100));
 
     itst::Callback discoverCB(&DatabaseHas1InterfaceQueryMatchVerify);
@@ -969,15 +969,15 @@ TEST_P(RDDiscoverTests, DatabaseHasNInterfaceQueryMatches)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              1, publish0CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
     itst::Callback publish1CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2],
-              1, publish1CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish1CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish1CB.Wait(100));
     itst::Callback publish2CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3],
-              1, publish2CB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publish2CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish2CB.Wait(100));
 
     itst::Callback discoverCB(&DatabaseHasNInterfaceQueryMatchesVerify);
@@ -1047,7 +1047,7 @@ TEST_P(RDDiscoverTests, ResourceAndInterfaceQueryMatch)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publish0CB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1],
-              3, publish0CB, OC_LOW_QOS));
+              3, OIC_RD_PUBLISH_TTL, publish0CB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publish0CB.Wait(100));
 
     itst::Callback discoverCB(&ResourceAndInterfaceQueryMatchVerify);
@@ -1079,7 +1079,7 @@ TEST_P(RDDiscoverTests, Baseline)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
-              1, publishCB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     itst::Callback discoverCB(&BaselineVerify);
@@ -1117,7 +1117,7 @@ TEST_P(RDDiscoverTests, DeleteDevice)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
-              1, publishCB, OC_LOW_QOS));
+              1, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     itst::Callback deleteCB(&handleDeleteCB);
@@ -1183,7 +1183,7 @@ TEST_P(RDDiscoverTests, Delete1)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
-              2, publishCB, OC_LOW_QOS));
+              2, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     itst::Callback deleteCB(&handleDeleteCB);
@@ -1258,7 +1258,7 @@ TEST_P(RDDiscoverTests, DeleteN)
                                             NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
     itst::Callback publishCB(&handlePublishCB);
     EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
-              3, publishCB, OC_LOW_QOS));
+              3, OIC_RD_PUBLISH_TTL, publishCB, OC_LOW_QOS));
     EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
 
     itst::Callback deleteCB(&handleDeleteCB);
@@ -1274,5 +1274,27 @@ TEST_P(RDDiscoverTests, DeleteN)
 
 INSTANTIATE_TEST_CASE_P(ContentFormat, RDDiscoverTests,
         ::testing::Values(COAP_MEDIATYPE_APPLICATION_VND_OCF_CBOR, COAP_MEDIATYPE_APPLICATION_CBOR));
+
+TEST_P(RDDiscoverTests, TTLLapsedDeleteDevice)
+{
+    itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
+
+    OCResourceHandle handles[1];
+    EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light",
+                                            "oic.if.baseline", "/a/light", rdEntityHandler,
+                                            NULL, (OC_DISCOVERABLE | OC_OBSERVABLE)));
+    itst::Callback publishCB(&handlePublishCB);
+    EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId(NULL, "127.0.0.1", di[0], CT_ADAPTER_IP, handles,
+              1, 1, publishCB, OC_LOW_QOS));
+    EXPECT_EQ(OC_STACK_OK, publishCB.Wait(100));
+
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    itst::Callback discoverCB(&DeleteDeviceVerify);
+    EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res", NULL, 0,
+                    CT_DEFAULT, OC_HIGH_QOS, discoverCB, options, numOptions));
+    EXPECT_EQ(OC_STACK_OK, discoverCB.Wait(100));
+}
+
 #endif
 
index 42de22a..07bf6ea 100644 (file)
@@ -34,6 +34,7 @@
 #include "ocendpoint.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
+#include "oic_time.h"
 #include "cainterface.h"
 
 #define TAG "OIC_RI_RESOURCEDIRECTORY"
@@ -405,6 +406,105 @@ exit:
     return result;
 }
 
+static OCStackResult deleteResources(const char *deviceId, const int64_t *instanceIds, uint16_t nInstanceIds)
+{
+    char *delResource = NULL;
+    sqlite3_stmt *stmt = NULL;
+
+    OCStackResult result;
+    VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
+
+    if (!instanceIds || !nInstanceIds)
+    {
+        static const char delDevice[] = "DELETE FROM RD_DEVICE_LIST WHERE di=@deviceId";
+        int delDeviceSize = (int)sizeof(delDevice);
+
+        VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, delDevice, delDeviceSize, &stmt, NULL));
+        VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@deviceId"),
+                                        deviceId, (int)strlen(deviceId), SQLITE_STATIC));
+    }
+    else
+    {
+        static const char pre[] = "DELETE FROM RD_DEVICE_LINK_LIST "
+            "WHERE ins IN ("
+            "SELECT RD_DEVICE_LINK_LIST.ins FROM RD_DEVICE_LINK_LIST "
+            "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
+            "WHERE RD_DEVICE_LINK_LIST.ins IN (";
+        size_t inLen = nInstanceIds + (nInstanceIds - 1);
+        static const char post[] = "))";
+        size_t delResourceSize = sizeof(pre) + inLen + (sizeof(post) - 1);
+        delResource = OICCalloc(delResourceSize, 1);
+        VERIFY_NON_NULL(delResource);
+        OICStrcat(delResource, delResourceSize, pre);
+        OICStrcat(delResource, delResourceSize, "?");
+        for (uint16_t i = 1; i < nInstanceIds; ++i)
+        {
+            OICStrcat(delResource, delResourceSize, ",?");
+        }
+        OICStrcat(delResource, delResourceSize, post);
+        VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, delResource, (int)delResourceSize,
+                        &stmt, NULL));
+        for (uint16_t i = 0; i < nInstanceIds; ++i)
+        {
+            VERIFY_SQLITE(sqlite3_bind_int64(stmt, 1 + i, instanceIds[i]));
+        }
+    }
+
+    int res = sqlite3_step(stmt);
+    if (SQLITE_DONE != res)
+    {
+        result = OC_STACK_ERROR;
+        goto exit;
+    }
+    VERIFY_SQLITE(sqlite3_finalize(stmt));
+    stmt = NULL;
+
+    VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
+    result = OC_STACK_OK;
+
+exit:
+    OICFree(delResource);
+    sqlite3_finalize(stmt);
+    if (OC_STACK_OK != result)
+    {
+        sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
+    }
+    return result;
+}
+
+static OCStackResult DeleteExpiredResources()
+{
+    sqlite3_stmt *stmt = NULL;
+    OCStackResult result;
+
+    uint64_t ttl = OICGetCurrentTime(TIME_IN_US);
+    static const char lapsed[] = "SELECT di FROM RD_DEVICE_LIST WHERE ttl < @ttl";
+    int lapsedSize = (int)sizeof(lapsed);
+    VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, lapsed, lapsedSize, &stmt, NULL));
+    VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@ttl"),
+                                     (int64_t)ttl));
+
+    while (SQLITE_ROW == sqlite3_step(stmt))
+    {
+        const unsigned char *di = sqlite3_column_text(stmt, 0);
+        if (SQLITE_OK != deleteResources((const char *)di, NULL, 0))
+        {
+            OIC_LOG_V(WARNING, TAG, "Error in deleteResources, Error Message: %s", sqlite3_errmsg(gRDDB));
+        }
+        else
+        {
+            OIC_LOG_V(INFO, TAG, "Deleted resources with di=%s", di);
+        }
+    }
+    VERIFY_SQLITE(sqlite3_finalize(stmt));
+    stmt = NULL;
+    result = OC_STACK_OK;
+
+ exit:
+    sqlite3_finalize(stmt);
+    return result;
+}
+
 OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType,
         const char *resourceType, OCDiscoveryPayload **payload)
 {
@@ -434,13 +534,15 @@ OCStackResult OC_CALL OCRDDatabaseDiscoveryPayloadCreateWithEp(const char *inter
     {
         OIC_LOG_V(INFO, TAG, "SQLite debugging log initialized.");
     }
-    sqlite3_open_v2(OCRDDatabaseGetStorageFilename(), &gRDDB, SQLITE_OPEN_READONLY, NULL);
+    sqlite3_open_v2(OCRDDatabaseGetStorageFilename(), &gRDDB, SQLITE_OPEN_READWRITE, NULL);
     if (!gRDDB)
     {
         result = OC_STACK_ERROR;
         goto exit;
     }
 
+    DeleteExpiredResources();
+
     const char *serverID = OCGetServerInstanceIDString();
     const char input[] = "SELECT di, external_host FROM RD_DEVICE_LIST";
     int inputSize = (int)sizeof(input);
index 15bce8c..41a0086 100644 (file)
@@ -59,7 +59,7 @@ NSResult NSPublishResourceToCloud(char *serverAddress)
 
     OCResourceHandle resourceHandles[1] = { NotificationResource.handle };
     OCStackResult res = OCRDPublish(NULL, serverAddress, CT_ADAPTER_TCP, resourceHandles, 1,
-            &cbData, OC_LOW_QOS);
+            OIC_RD_PUBLISH_TTL, &cbData, OC_LOW_QOS);
 
     if (res != OC_STACK_OK)
     {