From 534200bc97abb740e8e11502a9b32c6f8b6af356 Mon Sep 17 00:00:00 2001 From: Todd Malsbary Date: Mon, 21 Nov 2016 12:01:33 -0800 Subject: [PATCH] Resource directory related fixes. - Use the passed in ID in OCRDPublishWithDeviceId(), - Set the size of the CBOR array to the length of the discovery payload list in OCConvertDiscoveryPayload(), - Return all local and published resources in response to GET /oic/res, - Set the di and baseURI correctly in discovery payloads, - Only return resources that match the intersection of 'rt' and 'if' queries. - Add missing calls to ROLLBACK in error paths. Change-Id: Ib1ad770fec8ec6f9eafff0e5f864ee115f1ba5b5 Signed-off-by: Todd Malsbary Reviewed-on: https://gerrit.iotivity.org/gerrit/14581 Tested-by: jenkins-iotivity Reviewed-by: Habib Virji --- .../resource-directory/src/internal/rd_database.c | 4 + .../resource-directory/unittests/rddatabase.cpp | 32 +- .../csdk/resource-directory/unittests/rdtests.cpp | 801 ++++++++++++++++++++- resource/csdk/stack/include/ocstack.h | 8 +- resource/csdk/stack/src/ocpayloadconvert.c | 7 +- resource/csdk/stack/src/ocresource.c | 34 +- resource/csdk/stack/src/oicresourcedirectory.c | 352 +++++---- 7 files changed, 1071 insertions(+), 167 deletions(-) diff --git a/resource/csdk/resource-directory/src/internal/rd_database.c b/resource/csdk/resource-directory/src/internal/rd_database.c index 024ffe0..abcb367 100644 --- a/resource/csdk/resource-directory/src/internal/rd_database.c +++ b/resource/csdk/resource-directory/src/internal/rd_database.c @@ -181,6 +181,7 @@ static int storeResourceType(char **link, size_t size, uint8_t rowid) } if (sqlite3_step(stmtRT) != SQLITE_DONE) { + sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL); sqlite3_finalize(stmtRT); return res; } @@ -215,6 +216,7 @@ static int storeInterfaceType(char **link, size_t size, uint8_t rowid) } if (sqlite3_step(stmtIF) != SQLITE_DONE) { + sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL); res = sqlite3_finalize(stmtIF); return res; } @@ -280,6 +282,7 @@ static int storeLinkPayload(OCRepPayload *rdPayload, int64_t rowid) if (sqlite3_step(stmt) != SQLITE_DONE) { + sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL); sqlite3_finalize(stmt); return res; } @@ -344,6 +347,7 @@ OCStackResult OCRDDatabaseStoreResources(OCRepPayload *payload, const OCDevAddr if (sqlite3_step(stmt) != SQLITE_DONE) { + sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL); sqlite3_finalize(stmt); return OC_STACK_ERROR; } diff --git a/resource/csdk/resource-directory/unittests/rddatabase.cpp b/resource/csdk/resource-directory/unittests/rddatabase.cpp index a4dfcc8..97207e9 100644 --- a/resource/csdk/resource-directory/unittests/rddatabase.cpp +++ b/resource/csdk/resource-directory/unittests/rddatabase.cpp @@ -96,9 +96,9 @@ TEST_F(RDDatabaseTests, PublishDatabase) // itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); EXPECT_EQ(OC_STACK_OK, OCRDDatabaseInit(NULL)); OCRepPayload *repPayload = OCRepPayloadCreate(); - EXPECT_TRUE(repPayload != NULL); - const char *deviceId = OCGetServerInstanceIDString(); - EXPECT_TRUE(deviceId != NULL); + ASSERT_TRUE(repPayload != NULL); + const char *deviceId = "7a960f46-a52e-4837-bd83-460b1a6dd56b"; + ASSERT_TRUE(deviceId != NULL); EXPECT_TRUE(OCRepPayloadSetPropString(repPayload, OC_RSRVD_DEVICE_ID, deviceId)); EXPECT_TRUE(OCRepPayloadSetPropInt(repPayload, OC_RSRVD_DEVICE_TTL, 86400)); OCDevAddr address; @@ -155,19 +155,21 @@ TEST_F(RDDatabaseTests, PublishDatabase) OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)repPayload); EXPECT_EQ(OC_STACK_OK, OCRDDatabaseStoreResources(repPayload, &address)); - OCDiscoveryPayload *discPayload = OCDiscoveryPayloadCreate(); - EXPECT_TRUE(discPayload != NULL); - EXPECT_EQ(discPayload->base.type, PAYLOAD_TYPE_DISCOVERY); - EXPECT_EQ(OC_STACK_OK, OCRDDatabaseCheckResources(NULL, "core.light", discPayload)); + + OCDiscoveryPayload *discPayload = NULL; + EXPECT_EQ(OC_STACK_OK, OCRDDatabaseDiscoveryPayloadCreate(NULL, "core.light", &discPayload)); + OCDiscoveryPayloadDestroy(discPayload); + discPayload = NULL; + EXPECT_EQ(OC_STACK_OK, OCRDDatabaseDiscoveryPayloadCreate(OC_RSRVD_INTERFACE_DEFAULT, NULL, &discPayload)); + OCDiscoveryPayloadDestroy(discPayload); + discPayload = NULL; + EXPECT_EQ(OC_STACK_OK, OCRDDatabaseDiscoveryPayloadCreate(NULL, "core.light", &discPayload)); OCDiscoveryPayloadDestroy(discPayload); - OCDiscoveryPayload *discPayload1 = OCDiscoveryPayloadCreate(); - EXPECT_EQ(OC_STACK_OK, OCRDDatabaseCheckResources(OC_RSRVD_INTERFACE_DEFAULT, NULL, discPayload1)); - OCDiscoveryPayloadDestroy(discPayload1); - OCDiscoveryPayload *discPayload2 = OCDiscoveryPayloadCreate(); - EXPECT_EQ(OC_STACK_OK, OCRDDatabaseCheckResources(NULL, "core.light", discPayload2)); - OCDiscoveryPayloadDestroy(discPayload2); - OCDiscoveryPayload *discPayload3 = OCDiscoveryPayloadCreate(); - EXPECT_EQ(OC_STACK_OK, OCRDDatabaseCheckResources(OC_RSRVD_INTERFACE_DEFAULT, "core.light", discPayload3)); + discPayload = NULL; + EXPECT_EQ(OC_STACK_OK, OCRDDatabaseDiscoveryPayloadCreate(OC_RSRVD_INTERFACE_DEFAULT, "core.light", &discPayload)); + OCDiscoveryPayloadDestroy(discPayload); + discPayload = NULL; + EXPECT_EQ(OC_STACK_OK, OCRDDatabaseDeleteDevice(deviceId)); EXPECT_EQ(OC_STACK_OK, OCRDDatabaseClose()); } diff --git a/resource/csdk/resource-directory/unittests/rdtests.cpp b/resource/csdk/resource-directory/unittests/rdtests.cpp index 50909ad..3973c81 100644 --- a/resource/csdk/resource-directory/unittests/rdtests.cpp +++ b/resource/csdk/resource-directory/unittests/rdtests.cpp @@ -22,9 +22,12 @@ extern "C" { #include "rd_client.h" #include "rd_server.h" + #include "ocpayload.h" #include "ocstack.h" #include "logger.h" #include "oic_malloc.h" + #include "oic_string.h" + #include "payload_logging.h" } #include "gtest/gtest.h" @@ -131,7 +134,7 @@ TEST_F(RDTests, CreateRDResource) EXPECT_EQ(OC_STACK_OK, OCRDStart()); OCCallbackData cbData; - cbData.cb = &handleDiscoveryCB;; + cbData.cb = &handleDiscoveryCB; cbData.cd = NULL; cbData.context = (void*) DEFAULT_CONTEXT_VALUE; EXPECT_EQ(OC_STACK_OK, OCRDDiscover(CT_ADAPTER_IP, &cbData, OC_LOW_QOS)); @@ -291,3 +294,799 @@ TEST_F(RDTests, RDDeleteSpecificResource) 1, &cbData, OC_LOW_QOS)); } #endif + +#if (defined(RD_SERVER) && defined(RD_CLIENT)) +class Callback +{ + public: + Callback(OCClientResponseHandler cb) + : m_cb(cb), m_called(false) + { + m_cbData.cb = &Callback::handler; + m_cbData.cd = NULL; + m_cbData.context = this; + } + void Wait() + { + while (!m_called) + { + OCProcess(); + } + } + operator OCCallbackData *() + { + return &m_cbData; + } + private: + OCCallbackData m_cbData; + OCClientResponseHandler m_cb; + bool m_called; + static OCStackApplicationResult handler(void *ctx, OCDoHandle handle, + OCClientResponse *clientResponse) + { + Callback *callback = (Callback *) ctx; + OCStackApplicationResult result = callback->m_cb(NULL, handle, clientResponse); + callback->m_called = true; + return result; + } +}; + +class RDDiscoverTests : public testing::Test +{ + protected: + virtual void SetUp() + { + remove("RD.db"); + EXPECT_EQ(OC_STACK_OK, OCInit("127.0.0.1", 5683, OC_CLIENT_SERVER)); + EXPECT_EQ(OC_STACK_OK, OCRDStart()); + } + + virtual void TearDown() + { + OCStop(); + remove("RD.db"); + } + public: + static const unsigned char *di[3]; +}; +const unsigned char *RDDiscoverTests::di[3] = +{ + (const unsigned char *) "7a960f46-a52e-4837-bd83-460b1a6dd56b", + (const unsigned char *) "983656a7-c7e5-49c2-a201-edbeb7606fb5", + (const unsigned char *) "9338c0b2-2373-4324-ba78-17c0ef79506d" +}; + +static OCStackApplicationResult DiscoverAllResourcesVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + bool foundId = false; + bool foundLight = false; + bool foundLight2 = false; + for (OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; payload; + payload = payload->next) + { + if (!strcmp((const char *) RDDiscoverTests::di[0], payload->sid)) + { + foundId = true; + for (OCResourcePayload *resource = payload->resources; resource; resource = resource->next) + { + if (!strcmp("/a/light", resource->uri)) + { + foundLight = true; + } + if (!strcmp("/a/light2", resource->uri)) + { + foundLight2 = true; + } + } + } + } + EXPECT_TRUE(foundId); + EXPECT_TRUE(foundLight); + EXPECT_TRUE(foundLight2); + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DiscoverAllResources) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[2]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.baseline", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light", + "oic.if.baseline", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publishCB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, handles, + 2, publishCB, OC_LOW_QOS)); + publishCB.Wait(); + + Callback discoverCB(&DiscoverAllResourcesVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res", NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult ResourceQueryMatchesLocalAndRemoteVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + // Verify that only resources with the queried type are present in the response + for (OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; payload; + payload = payload->next) + { + EXPECT_TRUE(payload->resources != NULL); + if (payload->resources) + { + EXPECT_TRUE(payload->resources->next == NULL); + EXPECT_STREQ("/a/light", payload->resources->uri); + EXPECT_STREQ("core.light", payload->resources->types->value); + EXPECT_TRUE(payload->resources->types->next == NULL); + } + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, ResourceQueryMatchesLocalAndRemote) +{ + 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))); + Callback publishCB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, handles, + 1, publishCB, OC_LOW_QOS)); + publishCB.Wait(); + + Callback discoverCB(&ResourceQueryMatchesLocalAndRemoteVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult ResourceQueryMatchesLocalOnlyVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_STREQ(OCGetServerInstanceIDString(), payload->sid); + EXPECT_TRUE(payload->next == NULL); + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, ResourceQueryMatchesLocalOnly) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[2]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.baseline", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light2", + "oic.if.baseline", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publishCB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publishCB, OC_LOW_QOS)); + publishCB.Wait(); + + OIC_LOG(INFO, TAG, "Published"); + + Callback discoverCB(&ResourceQueryMatchesLocalOnlyVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult ResourceQueryMatchesRemoteOnlyVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_STREQ((const char *)RDDiscoverTests::di[0], payload->sid); + EXPECT_TRUE(payload->next == NULL); + } + return OC_STACK_DELETE_TRANSACTION; +} + +static void SetStringArray(OCRepPayload *payload, const char *name, const char *value) +{ + size_t dim[MAX_REP_ARRAY_DEPTH] = {1, 0, 0}; + char **ss = (char **)OICMalloc(sizeof(char *) * 1); + ss[0] = OICStrdup(value); + OCRepPayloadSetStringArray(payload, name, (const char **)ss, dim); +} + +TEST_F(RDDiscoverTests, ResourceQueryMatchesRemoteOnly) +{ + 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))); + OCRepPayload *repPayload = OCRepPayloadCreate(); + ASSERT_TRUE(repPayload != NULL); + EXPECT_TRUE(OCRepPayloadSetPropString(repPayload, OC_RSRVD_DEVICE_ID, (const char *)di[0])); + EXPECT_TRUE(OCRepPayloadSetPropInt(repPayload, OC_RSRVD_DEVICE_TTL, 86400)); + OCDevAddr address; + address.port = 54321; + OICStrcpy(address.addr,MAX_ADDR_STR_SIZE, "192.168.1.1"); + + std::string resourceURI_light = "/a/light"; + std::string resourceTypeName_light = "core.light2"; + + const OCRepPayload *linkArr[1]; + size_t dimensions[MAX_REP_ARRAY_DEPTH] = {1, 0, 0}; + + OCRepPayload *link = OCRepPayloadCreate(); + OCRepPayloadSetPropString(link, OC_RSRVD_HREF, resourceURI_light.c_str()); + SetStringArray(link, OC_RSRVD_RESOURCE_TYPE, resourceTypeName_light.c_str()); + SetStringArray(link, OC_RSRVD_INTERFACE, OC_RSRVD_INTERFACE_DEFAULT); + OCRepPayloadSetPropInt(link, OC_RSRVD_INS, 0); + SetStringArray(link, OC_RSRVD_MEDIA_TYPE, DEFAULT_MESSAGE_TYPE); + OCRepPayload *policy = OCRepPayloadCreate(); + OCRepPayloadSetPropInt(policy, OC_RSRVD_BITMAP, OC_DISCOVERABLE); + OCRepPayloadSetPropObjectAsOwner(link, OC_RSRVD_POLICY, policy); + linkArr[0] = link; + + OCRepPayloadSetPropObjectArray(repPayload, OC_RSRVD_LINKS, linkArr, dimensions); + + OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)repPayload); + + Callback publishCB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_POST, "127.0.0.1/oic/rd?rt=oic.wk.rdpub", NULL, + (OCPayload *)repPayload, CT_DEFAULT, OC_HIGH_QOS, publishCB, NULL, 0)); + publishCB.Wait(); + + Callback discoverCB(&ResourceQueryMatchesRemoteOnlyVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light2", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult DatabaseHas0ResourceQueryMatchesVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next == NULL); + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DatabaseHas0ResourceQueryMatches) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.baseline", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light2", + "oic.if.baseline", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light3", + "oic.if.baseline", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light4", + "oic.if.baseline", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + Callback publish1CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2], + 1, publish1CB, OC_LOW_QOS)); + publish1CB.Wait(); + Callback publish2CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3], + 1, publish2CB, OC_LOW_QOS)); + publish2CB.Wait(); + + Callback discoverCB(&DatabaseHas0ResourceQueryMatchesVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult DatabaseHas1ResourceQueryMatchVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next != NULL); + if (payload->next) + { + payload = payload->next; + EXPECT_TRUE(payload->resources != NULL); + if (payload->resources) + { + EXPECT_TRUE(payload->resources->next == NULL); + EXPECT_STREQ("/a/light2", payload->resources->uri); + EXPECT_STREQ("core.light2", payload->resources->types->value); + EXPECT_TRUE(payload->resources->types->next == NULL); + } + payload = payload->next; + EXPECT_TRUE(payload == NULL); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DatabaseHas1ResourceQueryMatch) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.baseline", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light2", + "oic.if.baseline", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light3", + "oic.if.baseline", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light4", + "oic.if.baseline", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + Callback publish1CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2], + 1, publish1CB, OC_LOW_QOS)); + publish1CB.Wait(); + Callback publish2CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3], + 1, publish2CB, OC_LOW_QOS)); + publish2CB.Wait(); + + Callback discoverCB(&DatabaseHas1ResourceQueryMatchVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light2", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult DatabaseHasNResourceQueryMatchesVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next != NULL); + if (payload->next) + { + payload = payload->next; + for (int i = 0; i < 3; ++i) + { + EXPECT_TRUE(payload->resources != NULL); + if (payload->resources) + { + EXPECT_TRUE(payload->resources->next == NULL); + EXPECT_STREQ("core.light", payload->resources->types->value); + EXPECT_TRUE(payload->resources->types->next == NULL); + } + payload = payload->next; + } + EXPECT_TRUE(payload == NULL); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DatabaseHasNResourceQueryMatches) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.baseline", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light", + "oic.if.baseline", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light", + "oic.if.baseline", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light", + "oic.if.baseline", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + Callback publish1CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2], + 1, publish1CB, OC_LOW_QOS)); + publish1CB.Wait(); + Callback publish2CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3], + 1, publish2CB, OC_LOW_QOS)); + publish2CB.Wait(); + + Callback discoverCB(&DatabaseHasNResourceQueryMatchesVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult DatabaseHas0InterfaceQueryMatchesVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next == NULL); + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DatabaseHas0InterfaceQueryMatches) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.one", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light2", + "oic.if.two", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light3", + "oic.if.three", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light4", + "oic.if.four", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + Callback publish1CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2], + 1, publish1CB, OC_LOW_QOS)); + publish1CB.Wait(); + Callback publish2CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3], + 1, publish2CB, OC_LOW_QOS)); + publish2CB.Wait(); + + Callback discoverCB(&DatabaseHas0InterfaceQueryMatchesVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=oic.if.one", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult DatabaseHas1InterfaceQueryMatchVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next != NULL); + if (payload->next) + { + payload = payload->next; + for (int i = 0; i < 1; ++i) + { + EXPECT_TRUE(payload->resources != NULL); + if (payload->resources) + { + EXPECT_TRUE(payload->resources->next == NULL); + EXPECT_STREQ("/a/light2", payload->resources->uri); + bool foundInterface = false; + for (OCStringLL *iface = payload->resources->interfaces; iface; iface = iface->next) + { + if (!strcmp("oic.if.two", iface->value)) + { + foundInterface = true; + } + } + EXPECT_TRUE(foundInterface); + } + payload = payload->next; + } + EXPECT_TRUE(payload == NULL); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DatabaseHas1InterfaceQueryMatch) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.one", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light2", + "oic.if.two", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light3", + "oic.if.three", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light4", + "oic.if.four", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + Callback publish1CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2], + 1, publish1CB, OC_LOW_QOS)); + publish1CB.Wait(); + Callback publish2CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3], + 1, publish2CB, OC_LOW_QOS)); + publish2CB.Wait(); + + Callback discoverCB(&DatabaseHas1InterfaceQueryMatchVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=oic.if.two", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult DatabaseHasNInterfaceQueryMatchesVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next != NULL); + if (payload->next) + { + payload = payload->next; + for (int i = 0; i < 3; ++i) + { + EXPECT_TRUE(payload->resources != NULL); + if (payload->resources) + { + EXPECT_TRUE(payload->resources->next == NULL); + bool foundInterface = false; + for (OCStringLL *iface = payload->resources->interfaces; iface; iface = iface->next) + { + if (!strcmp("oic.if.a", iface->value)) + { + foundInterface = true; + } + } + EXPECT_TRUE(foundInterface); + } + payload = payload->next; + } + EXPECT_TRUE(payload == NULL); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, DatabaseHasNInterfaceQueryMatches) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.a", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light", + "oic.if.a", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light", + "oic.if.a", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light", + "oic.if.a", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 1, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + Callback publish1CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[1], CT_ADAPTER_IP, &handles[2], + 1, publish1CB, OC_LOW_QOS)); + publish1CB.Wait(); + Callback publish2CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[2], CT_ADAPTER_IP, &handles[3], + 1, publish2CB, OC_LOW_QOS)); + publish2CB.Wait(); + + Callback discoverCB(&DatabaseHasNInterfaceQueryMatchesVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=oic.if.a", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult ResourceAndInterfaceQueryMatchVerify(void *ctx, + OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(response->payload != NULL); + if (response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->next != NULL); + if (payload->next) + { + payload = payload->next; + for (int i = 0; i < 1; ++i) + { + EXPECT_TRUE(payload->resources != NULL); + if (payload->resources) + { + EXPECT_TRUE(payload->resources->next == NULL); + EXPECT_STREQ("/a/light2", payload->resources->uri); + EXPECT_STREQ("core.light2", payload->resources->types->value); + EXPECT_TRUE(payload->resources->types->next == NULL); + bool foundInterface = false; + for (OCStringLL *iface = payload->resources->interfaces; iface; iface = iface->next) + { + if (!strcmp("oic.if.two", iface->value)) + { + foundInterface = true; + } + } + EXPECT_TRUE(foundInterface); + } + payload = payload->next; + } + EXPECT_TRUE(payload == NULL); + } + } + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, ResourceAndInterfaceQueryMatch) +{ + itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); + + OCResourceHandle handles[4]; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[0], "core.light", + "oic.if.a", "/a/light", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[1], "core.light2", + "oic.if.two", "/a/light2", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[2], "core.light3", + "oic.if.two", "/a/light3", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles[3], "core.light2", + "oic.if.a", "/a/light4", rdEntityHandler, + NULL, (OC_DISCOVERABLE | OC_OBSERVABLE))); + Callback publish0CB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, &handles[1], + 3, publish0CB, OC_LOW_QOS)); + publish0CB.Wait(); + + Callback discoverCB(&ResourceAndInterfaceQueryMatchVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light2&if=oic.if.two", + NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} + +static OCStackApplicationResult BaselineVerify(void *ctx, OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + OCDiscoveryPayload *payload = (OCDiscoveryPayload *) response->payload; + EXPECT_TRUE(payload->type != NULL); + EXPECT_TRUE(payload->iface != NULL); + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(RDDiscoverTests, Baseline) +{ + 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))); + Callback publishCB(&handlePublishCB); + EXPECT_EQ(OC_STACK_OK, OCRDPublishWithDeviceId("127.0.0.1", di[0], CT_ADAPTER_IP, handles, + 1, publishCB, OC_LOW_QOS)); + publishCB.Wait(); + + Callback discoverCB(&BaselineVerify); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=oic.if.baseline", NULL, 0, + CT_DEFAULT, + OC_HIGH_QOS, discoverCB, NULL, 0)); + discoverCB.Wait(); +} +#endif diff --git a/resource/csdk/stack/include/ocstack.h b/resource/csdk/stack/include/ocstack.h index 565fe19..0591483 100644 --- a/resource/csdk/stack/include/ocstack.h +++ b/resource/csdk/stack/include/ocstack.h @@ -708,13 +708,13 @@ OCResourceHandle OCGetResourceHandleAtUri(const char *uri); * * @param interfaceType is the interface type that is queried. * @param resourceType is the resource type that is queried. -* @param discPayload is NULL if no resource found or else OCDiscoveryPayload with the details -* about the resource. +* @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 OCRDDatabaseCheckResources(const char *interfaceType, const char *resourceType, - OCDiscoveryPayload *discPayload); +OCStackResult OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType, const char *resourceType, + OCDiscoveryPayload **discPayload); #endif //#endif // DIRECT_PAIRING diff --git a/resource/csdk/stack/src/ocpayloadconvert.c b/resource/csdk/stack/src/ocpayloadconvert.c index 5c2d083..26be51b 100755 --- a/resource/csdk/stack/src/ocpayloadconvert.c +++ b/resource/csdk/stack/src/ocpayloadconvert.c @@ -244,8 +244,13 @@ static int64_t OCConvertDiscoveryPayload(OCDiscoveryPayload *payload, uint8_t *o */ // Open the main root array + size_t arrayCount = 0; + for (OCDiscoveryPayload *temp = payload; temp; temp = temp->next) + { + arrayCount++; + } CborEncoder rootArray; - err |= cbor_encoder_create_array(&encoder, &rootArray, 1); + err |= cbor_encoder_create_array(&encoder, &rootArray, arrayCount); VERIFY_CBOR_SUCCESS(TAG, err, "Failed creating discovery root array"); while (payload && payload->resources) diff --git a/resource/csdk/stack/src/ocresource.c b/resource/csdk/stack/src/ocresource.c index 7632064..ac38105 100755 --- a/resource/csdk/stack/src/ocresource.c +++ b/resource/csdk/stack/src/ocresource.c @@ -1260,29 +1260,30 @@ static OCStackResult EHRequest(OCEntityHandlerRequest *ehRequest, OCPayloadType #ifdef RD_SERVER /** - * Find resource at the resource directory server. This resource is not local resource but a - * remote resource. + * Find resources at the resource directory server. These resources are not local resources but + * remote resources. * - * @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. + * @return ::OC_STACK_OK if any resources are found else ::OC_STACK_NO_RESOURCE. + * In case if RD server is not started, it returns ::OC_STACK_NO_RESOURCE. */ -static OCStackResult findResourceAtRD(const OCResource* resource, const char *interfaceQuery, - const char *resourceTypeQuery, OCDiscoveryPayload *discPayload) +static OCStackResult findResourcesAtRD(const char *interfaceQuery, + const char *resourceTypeQuery, OCDiscoveryPayload **discPayload) { - if (strcmp(resource->uri, OC_RSRVD_RD_URI) == 0) + OCStackResult result = OC_STACK_NO_RESOURCE; + if (OCGetResourceHandleAtUri(OC_RSRVD_RD_URI) != NULL) { - if (OC_STACK_OK == OCRDDatabaseCheckResources(interfaceQuery, resourceTypeQuery, discPayload)) - { - return OC_STACK_OK; - } + result = OCRDDatabaseDiscoveryPayloadCreate(interfaceQuery, resourceTypeQuery, + (*discPayload) ? &(*discPayload)->next : discPayload); } - - return OC_STACK_NO_RESOURCE; + if ((*discPayload) && (*discPayload)->resources) + { + result = OC_STACK_OK; + } + return result; } #endif @@ -1476,12 +1477,17 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource if (discPayload->resources == NULL) { discoveryResult = OC_STACK_NO_RESOURCE; + OCPayloadDestroy(payload); + payload = NULL; } if (networkInfo) { OICFree(networkInfo); } +#ifdef RD_SERVER + discoveryResult = findResourcesAtRD(interfaceQuery, resourceTypeQuery, (OCDiscoveryPayload **)&payload); +#endif } else if (virtualUriInRequest == OC_DEVICE_URI) { diff --git a/resource/csdk/stack/src/oicresourcedirectory.c b/resource/csdk/stack/src/oicresourcedirectory.c index 7e8e6b9..e8e1eac 100644 --- a/resource/csdk/stack/src/oicresourcedirectory.c +++ b/resource/csdk/stack/src/oicresourcedirectory.c @@ -27,6 +27,7 @@ #include "octypes.h" #include "ocstack.h" +#include "ocrandom.h" #include "logger.h" #include "ocpayload.h" #include "oic_malloc.h" @@ -43,16 +44,17 @@ static sqlite3 *gRDDB = NULL; -static const uint8_t uri_index = 2; -static const uint8_t p_index = 5; -static const uint8_t mt_index = 7; -static const uint8_t d_index = 8; +/* Column indices of RD_DEVICE_LINK_LIST table */ +static const uint8_t ins_index = 0; +static const uint8_t uri_index = 1; +static const uint8_t p_index = 4; +static const uint8_t d_index = 7; -static const uint8_t rt_value_index = 1; -static const uint8_t rt_link_id_index = 2; +/* Column indices of RD_LINK_RT table */ +static const uint8_t rt_value_index = 0; -static const uint8_t if_value_index = 1; -static const uint8_t if_link_id_index = 2; +/* Column indices of RD_LINK_IF table */ +static const uint8_t if_value_index = 0; #define VERIFY_SQLITE(arg) \ if (SQLITE_OK != (arg)) \ @@ -112,158 +114,244 @@ static OCStackResult appendStringLL(OCStringLL **type, const unsigned char *valu return OC_STACK_OK; } -OCStackResult OCRDDatabaseCheckResources(const char *interfaceType, const char *resourceType, - OCDiscoveryPayload *discPayload) +/* stmt is of form "SELECT * FROM RD_DEVICE_LINK_LIST ..." */ +static OCStackResult ResourcePayloadCreate(sqlite3_stmt *stmt, OCDiscoveryPayload *discPayload) { - if (initializeDatabase(NULL) != OC_STACK_OK) - { - return OC_STACK_INTERNAL_SERVER_ERROR; - } - if (!interfaceType && !resourceType) + int res = sqlite3_step(stmt); + if (SQLITE_ROW != res) { - return OC_STACK_INVALID_QUERY; + return OC_STACK_NO_RESOURCE; } - OCResourcePayload *resourcePayload = (OCResourcePayload *)OICCalloc(1, sizeof(OCResourcePayload)); - if (!resourcePayload) - { - return OC_STACK_NO_MEMORY; - } - - if (resourceType) + OCStackResult result = OC_STACK_OK; + OCResourcePayload *resourcePayload = NULL; + while (SQLITE_ROW == res) { - sqlite3_stmt *stmt = 0; - const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST INNER JOIN RD_LINK_RT ON " \ - "RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID WHERE RD_LINK_RT.rt LIKE ? "; + resourcePayload = (OCResourcePayload *)OICCalloc(1, sizeof(OCResourcePayload)); + if (!resourcePayload) + { + result = OC_STACK_NO_MEMORY; + goto exit; + } - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); - VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, resourceType, strlen(resourceType) + 1, SQLITE_STATIC)); + int id = sqlite3_column_int(stmt, ins_index); + const unsigned char *uri = sqlite3_column_text(stmt, uri_index); + int bitmap = sqlite3_column_int(stmt, p_index); + int deviceId = sqlite3_column_int(stmt, d_index); + OIC_LOG_V(DEBUG, TAG, " %s %d", uri, deviceId); + resourcePayload->uri = OICStrdup((char *)uri); + if (!resourcePayload->uri) + { + result = OC_STACK_NO_MEMORY; + goto exit; + } - int res = sqlite3_step (stmt); - if (res == SQLITE_ROW || res == SQLITE_DONE) + sqlite3_stmt *stmtRT = 0; + const char *rt = "SELECT rt FROM RD_LINK_RT WHERE LINK_ID=?"; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, rt, -1, &stmtRT, NULL)); + VERIFY_SQLITE(sqlite3_bind_int(stmtRT, 1, id)); + while (SQLITE_ROW == sqlite3_step(stmtRT)) { - int id = sqlite3_column_int(stmt, 0); - const unsigned char *uri = sqlite3_column_text(stmt, uri_index - 1); - int bitmap = sqlite3_column_int(stmt, p_index - 1); - int deviceId = sqlite3_column_int(stmt, d_index - 1); - OIC_LOG_V(DEBUG, TAG, " %s %d", uri, deviceId); - resourcePayload->uri = OICStrdup((char *)uri); - if (!resourcePayload->uri) + const unsigned char *rt1 = sqlite3_column_text(stmtRT, rt_value_index); + result = appendStringLL(&resourcePayload->types, rt1); + if (OC_STACK_OK != result) { - OCDiscoveryResourceDestroy(resourcePayload); - return OC_STACK_NO_MEMORY; + goto exit; } - res = sqlite3_reset(stmt); - VERIFY_SQLITE(res); + } + VERIFY_SQLITE(sqlite3_finalize(stmtRT)); - sqlite3_stmt *stmtRT = 0; - const char *rt = "SELECT rt FROM RD_LINK_RT WHERE LINK_ID=?"; - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, rt, -1, &stmtRT, NULL)); - VERIFY_SQLITE(sqlite3_bind_int(stmtRT, 1, id)); - while (SQLITE_ROW == sqlite3_step(stmtRT)) + sqlite3_stmt *stmtIF = 0; + const char *itf = "SELECT if FROM RD_LINK_IF WHERE LINK_ID=?"; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, itf, -1, &stmtIF, NULL)); + VERIFY_SQLITE(sqlite3_bind_int(stmtIF, 1, id)); + while (SQLITE_ROW == sqlite3_step(stmtIF)) + { + const unsigned char *itf = sqlite3_column_text(stmtIF, if_value_index); + result = appendStringLL(&resourcePayload->interfaces, itf); + if (OC_STACK_OK != result) { - const unsigned char *rt1 = sqlite3_column_text(stmtRT, (rt_value_index - 1)); - appendStringLL(&resourcePayload->types, rt1); + goto exit; } + } + VERIFY_SQLITE(sqlite3_finalize(stmtIF)); - sqlite3_stmt *stmtIF = 0; - const char *itf = "SELECT if FROM RD_LINK_IF WHERE LINK_ID=?"; - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, itf, -1, &stmtIF, NULL)); - VERIFY_SQLITE(sqlite3_bind_int(stmtIF, 1, id)); - while (SQLITE_ROW == sqlite3_step(stmtIF)) - { - const unsigned char *itf = sqlite3_column_text(stmtIF, (if_value_index - 1)); - appendStringLL(&resourcePayload->interfaces, itf); - } + resourcePayload->bitmap = bitmap & (OC_OBSERVABLE | OC_DISCOVERABLE); + resourcePayload->secure = (bitmap & OC_SECURE) != 0; - resourcePayload->bitmap = bitmap & (OC_OBSERVABLE | OC_DISCOVERABLE); - resourcePayload->secure = (bitmap & OC_SECURE) != 0; + const char *address = "SELECT di, address FROM RD_DEVICE_LIST " + "INNER JOIN RD_DEVICE_LINK_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID = RD_DEVICE_LIST.ID " + "WHERE RD_DEVICE_LINK_LIST.DEVICE_ID=?"; + const uint8_t di_index = 0; + const uint8_t address_index = 1; - const char *address = "SELECT di, address FROM RD_DEVICE_LIST INNER JOIN RD_DEVICE_LINK_LIST ON " \ - "RD_DEVICE_LINK_LIST.DEVICE_ID = RD_DEVICE_LIST.ID WHERE RD_DEVICE_LINK_LIST.DEVICE_ID=?"; + sqlite3_stmt *stmt1 = 0; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, address, -1, &stmt1, NULL)); + VERIFY_SQLITE(sqlite3_bind_int(stmt1, 1, deviceId)); - sqlite3_stmt *stmt1 = 0; - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, address, -1, &stmt1, NULL)); - VERIFY_SQLITE(sqlite3_bind_int(stmt1, 1, deviceId)); - // TODO: Right now, we have a bug where discovery payload can only send one device information. - res = sqlite3_step(stmt1); - if (res == SQLITE_ROW || res == SQLITE_DONE) + res = sqlite3_step(stmt1); + if (SQLITE_ROW == res || SQLITE_DONE == res) + { + const unsigned char *di = sqlite3_column_text(stmt1, di_index); + const unsigned char *address = sqlite3_column_text(stmt1, address_index); + OIC_LOG_V(DEBUG, TAG, " %s %s", di, address); + discPayload->baseURI = OICStrdup((char *)address); + if (!discPayload->baseURI) + { + result = OC_STACK_NO_MEMORY; + goto exit; + } + discPayload->sid = OICStrdup((char *)di); + if (!discPayload->sid) { - const unsigned char *di = sqlite3_column_text(stmt1, 0); - const unsigned char *address = sqlite3_column_text(stmt1, 1); - OIC_LOG_V(DEBUG, TAG, " %s %s", di, address); - (discPayload)->baseURI = OICStrdup((char *)address); - (discPayload)->sid = OICStrdup((char *)di); + result = OC_STACK_NO_MEMORY; + goto exit; } - OCDiscoveryPayloadAddNewResource(discPayload, resourcePayload); } + VERIFY_SQLITE(sqlite3_finalize(stmt1)); + OCDiscoveryPayloadAddNewResource(discPayload, resourcePayload); + res = sqlite3_step(stmt); } - if (interfaceType) +exit: + if (OC_STACK_OK != result) { - sqlite3_stmt *stmt = 0; - const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST INNER JOIN RD_LINK_IF ON " \ - "RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID WHERE RD_LINK_IF.if LIKE ? "; + OCDiscoveryResourceDestroy(resourcePayload); + } + return result; +} - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); - VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, interfaceType, strlen(interfaceType) + 1, SQLITE_STATIC)); +static OCStackResult CheckResources(const char *interfaceType, const char *resourceType, + OCDiscoveryPayload *discPayload) +{ + if (initializeDatabase(NULL) != OC_STACK_OK) + { + return OC_STACK_INTERNAL_SERVER_ERROR; + } + if (!interfaceType && !resourceType) + { + return OC_STACK_INVALID_QUERY; + } + if (!discPayload || !discPayload->sid) + { + return OC_STACK_INTERNAL_SERVER_ERROR; + } - int res = sqlite3_step (stmt); - if (res == SQLITE_ROW || res == SQLITE_DONE) + OCStackResult result = OC_STACK_OK; + sqlite3_stmt *stmt = 0; + if (resourceType) + { + if (!interfaceType || 0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_LL)) { - int id = sqlite3_column_int(stmt, 0); - const unsigned char *uri = sqlite3_column_text(stmt, uri_index - 1); - int bitmap = sqlite3_column_int(stmt, p_index - 1); - int deviceId = sqlite3_column_int(stmt, d_index - 1); - OIC_LOG_V(DEBUG, TAG, " %s %d", uri, deviceId); - resourcePayload->uri = OICStrdup((char *)uri); - if (!resourcePayload->uri) - { - OCDiscoveryResourceDestroy(resourcePayload); - return OC_STACK_NO_MEMORY; - } - VERIFY_SQLITE(sqlite3_reset(stmt)); - - sqlite3_stmt *stmtRT = 0; - const char *rt = "SELECT rt FROM RD_LINK_RT WHERE LINK_ID=?"; - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, rt, -1, &stmtRT, NULL)); - VERIFY_SQLITE(sqlite3_bind_int(stmtRT, 1, id)); - while (SQLITE_ROW == sqlite3_step(stmtRT)) - { - const unsigned char *rt1 = sqlite3_column_text(stmtRT, (rt_value_index - 1)); - appendStringLL(&resourcePayload->types, rt1); - } - - sqlite3_stmt *stmtIF = 0; - const char *itf = "SELECT if FROM RD_LINK_IF WHERE LINK_ID=?"; - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, itf, -1, &stmtIF, NULL)); - VERIFY_SQLITE(sqlite3_bind_int(stmtIF, 1, id)); - while (SQLITE_ROW == sqlite3_step (stmtIF)) - { - const unsigned char *itf = sqlite3_column_text(stmtIF, (if_value_index - 1)); - appendStringLL(&resourcePayload->interfaces, itf); - } - - resourcePayload->bitmap = bitmap & (OC_OBSERVABLE | OC_DISCOVERABLE); - resourcePayload->secure = ((bitmap & OC_SECURE) != 0); + const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST " + "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID " + "INNER JOIN RD_LINK_RT ON RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID " + "WHERE RD_DEVICE_LIST.di LIKE ?1 AND RD_LINK_RT.rt LIKE ?2"; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid) + 1, + SQLITE_STATIC)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 2, resourceType, strlen(resourceType) + 1, SQLITE_STATIC)); + } + else + { + const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST " + "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID " + "INNER JOIN RD_LINK_RT ON RD_DEVICE_LINK_LIST.INS=RD_LINK_RT.LINK_ID " + "INNER JOIN RD_LINK_IF ON RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID " + "WHERE RD_DEVICE_LIST.di LIKE ?1 AND RD_LINK_RT.rt LIKE ?2 AND RD_LINK_IF.if LIKE ?3"; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid) + 1, + SQLITE_STATIC)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 2, resourceType, strlen(resourceType) + 1, SQLITE_STATIC)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 3, interfaceType, strlen(interfaceType) + 1, SQLITE_STATIC)); + } + result = ResourcePayloadCreate(stmt, discPayload); + } + else if (interfaceType) + { + if (0 == strcmp(interfaceType, OC_RSRVD_INTERFACE_LL)) + { + const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST " + "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID " + "WHERE RD_DEVICE_LIST.di LIKE ?1"; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid) + 1, + SQLITE_STATIC)); + } + else + { + const char *input = "SELECT * FROM RD_DEVICE_LINK_LIST " + "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID " + "INNER JOIN RD_LINK_IF ON RD_DEVICE_LINK_LIST.INS=RD_LINK_IF.LINK_ID " + "WHERE RD_DEVICE_LIST.di LIKE ?1 AND RD_LINK_IF.if LIKE ?2"; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, discPayload->sid, strlen(discPayload->sid) + 1, + SQLITE_STATIC)); + VERIFY_SQLITE(sqlite3_bind_text(stmt, 2, interfaceType, strlen(interfaceType) + 1, SQLITE_STATIC)); + } + result = ResourcePayloadCreate(stmt, discPayload); + } + if (stmt) + { + VERIFY_SQLITE(sqlite3_finalize(stmt)); + } + return result; +} - const char *address = "SELECT di, address FROM RD_DEVICE_LIST INNER JOIN RD_DEVICE_LINK_LIST ON " \ - "RD_DEVICE_LINK_LIST.DEVICE_ID = RD_DEVICE_LIST.ID WHERE RD_DEVICE_LINK_LIST.DEVICE_ID=?"; +OCStackResult OCRDDatabaseDiscoveryPayloadCreate(const char *interfaceType, + const char *resourceType, + OCDiscoveryPayload **payload) +{ + OCStackResult result = OC_STACK_NO_RESOURCE; + OCDiscoveryPayload *head = NULL; + OCDiscoveryPayload **tail = &head; - sqlite3_stmt *stmt1 = 0; - VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, address, -1, &stmt1, NULL)); - VERIFY_SQLITE(sqlite3_bind_int(stmt1, 1, deviceId)); + if (*payload) + { + /* + * This is an error of the caller, return here instead of touching the + * caller provided payload. + */ + OIC_LOG_V(ERROR, TAG, "Payload is already allocated"); + return OC_STACK_INTERNAL_SERVER_ERROR; + } + if (initializeDatabase(NULL) != OC_STACK_OK) + { + goto exit; + } - res = sqlite3_step(stmt1); - if (res == SQLITE_ROW || res == SQLITE_DONE) - { - const unsigned char *di = sqlite3_column_text(stmt1, 0); - const unsigned char *address = sqlite3_column_text(stmt1, 1); - OIC_LOG_V(DEBUG, TAG, " %s %s", di, address); - (discPayload)->baseURI = OICStrdup((char *)address); - (discPayload)->sid = OICStrdup((char *)di); - } - OCDiscoveryPayloadAddNewResource(discPayload, resourcePayload); + const char *serverID = OCGetServerInstanceIDString(); + sqlite3_stmt *stmt = 0; + const char *input = "SELECT di FROM RD_DEVICE_LIST"; + const uint8_t di_index = 0; + VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, -1, &stmt, NULL)); + while (SQLITE_ROW == sqlite3_step(stmt)) + { + const unsigned char *di = sqlite3_column_text(stmt, di_index); + if (0 == strcmp((const char *)di, serverID)) + { + continue; + } + *tail = OCDiscoveryPayloadCreate(); + VERIFY_PARAM_NON_NULL(TAG, *tail, "Failed creating discovery payload."); + (*tail)->sid = (char *)OICCalloc(1, UUID_STRING_SIZE); + VERIFY_PARAM_NON_NULL(TAG, (*tail)->sid, "Failed adding device id to discovery payload."); + memcpy((*tail)->sid, di, UUID_STRING_SIZE); + result = CheckResources(interfaceType, resourceType, *tail); + if (OC_STACK_OK == result) + { + tail = &(*tail)->next; + } + else + { + OCPayloadDestroy((OCPayload *) *tail); + *tail = NULL; } } - return OC_STACK_OK; + VERIFY_SQLITE(sqlite3_finalize(stmt)); + *payload = head; + return result; +exit: + OCPayloadDestroy((OCPayload *) *tail); + *payload = NULL; + return OC_STACK_INTERNAL_SERVER_ERROR; } #endif -- 2.7.4