From 787da23d0040e499153a0be2ac3ffb8ea001055f Mon Sep 17 00:00:00 2001 From: Habib Virji Date: Tue, 6 Dec 2016 17:51:04 +0000 Subject: [PATCH] /oic/res error response for query handling - Stop the error response on invalid multicast /oic/res request. - An error message is sent in case of unicast. - In case of empty query for interface and resource type,, it sends an error message. - Add unit tests to test the callback returned value. BUG: https://jira.iotivity.org/browse/IOT-1650 Change-Id: I2f5902f46030d28ebcc8dc28c7e2f4fbcb6a1716 Signed-off-by: Habib Virji Reviewed-on: https://gerrit.iotivity.org/gerrit/15197 Tested-by: jenkins-iotivity Reviewed-by: Dan Mihai Reviewed-by: Uze Choi --- resource/csdk/include/octypes.h | 3 - resource/csdk/stack/include/payload_logging.h | 30 +-- resource/csdk/stack/src/ocpayload.c | 1 - resource/csdk/stack/src/ocpayloadconvert.c | 2 +- resource/csdk/stack/src/ocpayloadparse.c | 18 +- resource/csdk/stack/src/ocresource.c | 151 ++++++++------- resource/csdk/stack/src/ocstack.c | 86 ++++++--- resource/csdk/stack/test/stacktests.cpp | 266 ++++++++++++++++++++++++++ 8 files changed, 424 insertions(+), 133 deletions(-) diff --git a/resource/csdk/include/octypes.h b/resource/csdk/include/octypes.h index 0769d4f..f4e5ec1 100755 --- a/resource/csdk/include/octypes.h +++ b/resource/csdk/include/octypes.h @@ -1531,9 +1531,6 @@ typedef struct OCDiscoveryPayload /** Name */ char *name; - /** HREF */ - char *uri; - /** Resource Type */ OCStringLL *type; diff --git a/resource/csdk/stack/include/payload_logging.h b/resource/csdk/stack/include/payload_logging.h index 39914ce..e77baaf 100644 --- a/resource/csdk/stack/include/payload_logging.h +++ b/resource/csdk/stack/include/payload_logging.h @@ -203,13 +203,21 @@ INLINE_API void OCPayloadLogRep(LogLevel level, OCRepPayload* payload) } } +static void OCStringLLPrint(LogLevel level, OCStringLL *type) +{ + for (OCStringLL *strll = type; strll; strll = strll->next) + { + OIC_LOG_V(level, PL_TAG, "\t\t %s", strll->value); + } +} + INLINE_API void OCPayloadLogDiscovery(LogLevel level, OCDiscoveryPayload* payload) { OIC_LOG(level, PL_TAG, "Payload Type: Discovery"); while(payload && payload->resources) { - OIC_LOG_V(level, PL_TAG, "\tSID: %s", payload->sid); + OIC_LOG_V(level, PL_TAG, "\tDI: %s", payload->sid); if (payload->baseURI) { OIC_LOG_V(level, PL_TAG, "\tBase URI:%s", payload->baseURI); @@ -218,21 +226,17 @@ INLINE_API void OCPayloadLogDiscovery(LogLevel level, OCDiscoveryPayload* payloa { OIC_LOG_V(level, PL_TAG, "\tNAME: %s", payload->name); } - if (payload->uri) - { - OIC_LOG_V(level, PL_TAG, "\tURI: %s", payload->uri); - } + if (payload->type) { - for (OCStringLL *strll = payload->type; strll; strll = strll->next) - { - OIC_LOG_V(level, PL_TAG, "\tResource Type: %s", strll->value); - } + OIC_LOG(level, PL_TAG, "\tResource Type:"); + OCStringLLPrint(level, payload->type); } - OIC_LOG(level, PL_TAG, "\tInterface:"); - for (OCStringLL *itf = payload->iface; itf; itf = itf->next) + + if (payload->iface) { - OIC_LOG_V(level, PL_TAG, "\t\t%s", itf->value); + OIC_LOG(level, PL_TAG, "\tInterface:"); + OCStringLLPrint(level, payload->iface); } OCResourcePayload* res = payload->resources; @@ -240,7 +244,7 @@ INLINE_API void OCPayloadLogDiscovery(LogLevel level, OCDiscoveryPayload* payloa uint32_t i = 1; while(res) { - OIC_LOG_V(level, PL_TAG, "\tResource #%d", i); + OIC_LOG_V(level, PL_TAG, "\tLink#%d", i); OIC_LOG_V(level, PL_TAG, "\tURI:%s", res->uri); OIC_LOG(level, PL_TAG, "\tResource Types:"); OCStringLL* strll = res->types; diff --git a/resource/csdk/stack/src/ocpayload.c b/resource/csdk/stack/src/ocpayload.c index 640ab72..c52be01 100644 --- a/resource/csdk/stack/src/ocpayload.c +++ b/resource/csdk/stack/src/ocpayload.c @@ -2063,7 +2063,6 @@ void OCDiscoveryPayloadDestroy(OCDiscoveryPayload* payload) } OICFree(payload->sid); OICFree(payload->baseURI); - OICFree(payload->uri); OCFreeOCStringLL(payload->type); OICFree(payload->name); OCFreeOCStringLL(payload->iface); diff --git a/resource/csdk/stack/src/ocpayloadconvert.c b/resource/csdk/stack/src/ocpayloadconvert.c index aab39d3..b1d756f 100755 --- a/resource/csdk/stack/src/ocpayloadconvert.c +++ b/resource/csdk/stack/src/ocpayloadconvert.c @@ -121,7 +121,7 @@ OCStackResult OCConvertPayload(OCPayload* payload, uint8_t** outPayload, size_t* if (err == CborNoError) { - if ((curSize < INIT_SIZE) && + if ((curSize < INIT_SIZE) && (PAYLOAD_TYPE_SECURITY != payload->type)) { uint8_t *out2 = (uint8_t *)OICRealloc(out, curSize); diff --git a/resource/csdk/stack/src/ocpayloadparse.c b/resource/csdk/stack/src/ocpayloadparse.c index d18f33f..4d0dbaa 100755 --- a/resource/csdk/stack/src/ocpayloadparse.c +++ b/resource/csdk/stack/src/ocpayloadparse.c @@ -230,20 +230,12 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload **outPayload, CborValue * VERIFY_CBOR_SUCCESS(TAG, err, "to find base uri value"); } - // HREF - Not a mandatory field - err = cbor_value_map_find_value(&rootMap, OC_RSRVD_HREF, &curVal); - if (cbor_value_is_text_string(&curVal)) - { - err = cbor_value_dup_text_string(&curVal, &(temp->uri), &len, NULL); - VERIFY_CBOR_SUCCESS(TAG, err, "to find uri value"); - } - // RT - Not a mandatory field err = cbor_value_map_find_value(&rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal); if (cbor_value_is_valid(&curVal)) { err = OCParseStringLL(&rootMap, OC_RSRVD_RESOURCE_TYPE, &temp->type); - VERIFY_CBOR_SUCCESS(TAG, err, "to find base uri value"); + VERIFY_CBOR_SUCCESS(TAG, err, "to find resource type"); } // IF - Not a mandatory field @@ -251,13 +243,7 @@ static OCStackResult OCParseDiscoveryPayload(OCPayload **outPayload, CborValue * if (cbor_value_is_valid(&curVal)) { err = OCParseStringLL(&rootMap, OC_RSRVD_INTERFACE, &temp->iface); - } - if (!temp->iface) - { - if (!OCResourcePayloadAddStringLL(&temp->iface, OC_RSRVD_INTERFACE_LL)) - { - err = CborErrorOutOfMemory; - } + VERIFY_CBOR_SUCCESS(TAG, err, "to find interface"); } // Name - Not a mandatory field diff --git a/resource/csdk/stack/src/ocresource.c b/resource/csdk/stack/src/ocresource.c index 4ab4c92..02c4142 100755 --- a/resource/csdk/stack/src/ocresource.c +++ b/resource/csdk/stack/src/ocresource.c @@ -520,7 +520,7 @@ OCStackResult GetIntrospectionDataFromPS(char **data, size_t *size) size_t fileSize = 0; OCStackResult ret = OC_STACK_ERROR; OCPersistentStorage *ps = NULL; - + if (!data || *data || !size) { return OC_STACK_INVALID_PARAM; @@ -538,7 +538,7 @@ OCStackResult GetIntrospectionDataFromPS(char **data, size_t *size) if (fileSize) { // allocate one more byte to accomodate null terminator for string we are reading. - fsData = (uint8_t *)OICCalloc(1, fileSize + 1); + fsData = (uint8_t *)OICCalloc(1, fileSize + 1); if (!fsData) { OIC_LOG(ERROR, TAG, "Could not allocate memory for introspection data"); @@ -641,7 +641,7 @@ OCRepPayload *BuildUrlInfoWithProtocol(const char *protocol) result = OC_STACK_ERROR; goto exit; } - + exit: if (result != OC_STACK_OK) { @@ -665,8 +665,8 @@ OCStackResult AddProtocolToLL(OCStringLL **protoLL, const char *protocol) } if (cur) { - // The intent of the protocol list is to collect all unique protocols available on this - // endpoint. Set an error that can be used to skip processing this protocol further as + // The intent of the protocol list is to collect all unique protocols available on this + // endpoint. Set an error that can be used to skip processing this protocol further as // it already exists in the list. return OC_STACK_INVALID_PARAM; } @@ -840,9 +840,9 @@ OCStackResult BuildIntrospectionResponseRepresentation(const OCResource *resourc proto = proto->next; i++; } - if (!OCRepPayloadSetPropObjectArrayAsOwner(tempPayload, - OC_RSRVD_INTROSPECTION_URL_INFO, - urlInfoPayload, + if (!OCRepPayloadSetPropObjectArrayAsOwner(tempPayload, + OC_RSRVD_INTROSPECTION_URL_INFO, + urlInfoPayload, dimensions)) { OIC_LOG_V(ERROR, TAG, "Unable to add urlInfo object to introspection payload "); @@ -876,7 +876,7 @@ exit: } } FreeProtocolLL(protoLL); - + return OC_STACK_OK; } @@ -1114,12 +1114,20 @@ static bool resourceMatchesRTFilter(OCResource *resource, char *resourceTypeFilt return false; } - // Null or empty is analogous to no filter. - if (resourceTypeFilter == NULL || *resourceTypeFilter == 0) + // Null is analogous to no filter.i.e. query is of form /oic/res?if=oic.if.baseline or /oic/res, + // without rt query. + if (NULL == resourceTypeFilter) { return true; } + // Empty resourceType filter is analogous to error query + // It is an error as query is of form /oic/res?rt= + if (0 == strlen(resourceTypeFilter)) + { + return false; + } + for (OCResourceType *rtPtr = resource->rsrcType; rtPtr; rtPtr = rtPtr->next) { if (0 == strcmp(rtPtr->resourcetypename, resourceTypeFilter)) @@ -1139,12 +1147,20 @@ static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter) return false; } - // Null or empty is analogous to no filter. - if (interfaceFilter == NULL || *interfaceFilter == 0) + // Null is analogous to no filter i.e. query is of form /oic/res?rt=core.light or /oic/res, + // without if query. + if (NULL == interfaceFilter) { return true; } + // Empty interface filter is analogous to error query + // It is an error as query is of form /oic/res?if= + if (0 == strlen(interfaceFilter)) + { + return false; + } + for (OCResourceInterface *ifPtr = resource->rsrcInterface; ifPtr; ifPtr = ifPtr->next) { if (0 == strcmp(ifPtr->name, interfaceFilter) || @@ -1282,7 +1298,7 @@ static OCStackResult discoveryPayloadCreateAndAddDeviceId(OCPayload **payload) { if (*payload) { - OIC_LOG_V(DEBUG, TAG, "Payload is already allocated"); + OIC_LOG(DEBUG, TAG, "Payload is already allocated"); return OC_STACK_OK; } @@ -1317,10 +1333,13 @@ exit: */ static OCStackResult addDiscoveryBaselineCommonProperties(OCDiscoveryPayload *discPayload) { - discPayload->uri = OICStrdup(OC_RSRVD_WELL_KNOWN_URI); - VERIFY_PARAM_NON_NULL(TAG, discPayload->uri, "Failed adding href to discovery payload."); + if (!discPayload) + { + OIC_LOG(ERROR, TAG, "Payload is not allocated"); + return OC_STACK_INVALID_PARAM; + } - OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, "deviceName", (void **)&discPayload->name); + OCGetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, (void **)&discPayload->name); discPayload->type = (OCStringLL*)OICCalloc(1, sizeof(OCStringLL)); VERIFY_PARAM_NON_NULL(TAG, discPayload->type, "Failed adding rt to discovery payload."); @@ -1337,6 +1356,14 @@ exit: return OC_STACK_NO_MEMORY; } +static bool isUnicast(OCServerRequest *request) +{ + bool isMulticast = request->devAddr.flags & OC_MULTICAST; + return (isMulticast == false && + (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) && + (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE)); +} + static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource) { if (!request || !resource) @@ -1378,15 +1405,6 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource #endif ) { - if (request->method == OC_REST_PUT || request->method == OC_REST_POST || - request->method == OC_REST_DELETE) - { - OIC_LOG_V(ERROR, TAG, "Resource : %s not permitted for method: %d", - request->resourceUrl, request->method); - discoveryResult = OC_STACK_UNAUTHORIZED_REQ; - goto exit; - } - char *interfaceQuery = NULL; char *resourceTypeQuery = NULL; @@ -1403,24 +1421,19 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query, &interfaceQuery, &resourceTypeQuery); VERIFY_SUCCESS(discoveryResult); + if (!interfaceQuery && !resourceTypeQuery) { // If no query is sent, default interface is used i.e. oic.if.ll. interfaceQuery = OICStrdup(OC_RSRVD_INTERFACE_LL); } - bool baselineQuery = false; - if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT)) - { - baselineQuery = true; - } - discoveryResult = discoveryPayloadCreateAndAddDeviceId(&payload); VERIFY_PARAM_NON_NULL(TAG, payload, "Failed creating Discovery Payload."); VERIFY_SUCCESS(discoveryResult); OCDiscoveryPayload *discPayload = (OCDiscoveryPayload *)payload; - if (baselineQuery) + if (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_DEFAULT)) { discoveryResult = addDiscoveryBaselineCommonProperties(discPayload); VERIFY_SUCCESS(discoveryResult); @@ -1431,23 +1444,13 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource #endif for (; resource && discoveryResult == OC_STACK_OK; resource = resource->next) { - discoveryResult = OC_STACK_NO_RESOURCE; -#ifdef RD_SERVER - discoveryResult = findResourceAtRD(resource, interfaceQuery, resourceTypeQuery, - discPayload); -#endif - if (OC_STACK_NO_RESOURCE == discoveryResult) + // This case will handle when no resource type and it is oic.if.ll. + // Do not assume check if the query is ll + if (!resourceTypeQuery && + (interfaceQuery && 0 == strcmp(interfaceQuery, OC_RSRVD_INTERFACE_LL))) { - // This case will handle when no resource type and it is oic.if.ll. - if (!resourceTypeQuery && !baselineQuery && (resource->resourceProperties & prop)) - { - discoveryResult = BuildVirtualResourceResponse(resource, - discPayload, - &request->devAddr, - networkInfo, - infoSize); - } - else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery)) + // Only include discoverable type + if (resource->resourceProperties & prop) { discoveryResult = BuildVirtualResourceResponse(resource, discPayload, @@ -1455,10 +1458,18 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource networkInfo, infoSize); } - else - { - discoveryResult = OC_STACK_OK; - } + } + else if (includeThisResourceInResponse(resource, interfaceQuery, resourceTypeQuery)) + { + discoveryResult = BuildVirtualResourceResponse(resource, + discPayload, + &request->devAddr, + networkInfo, + infoSize); + } + else + { + discoveryResult = OC_STACK_OK; } } if (discPayload->resources == NULL) @@ -1548,25 +1559,28 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource OIC_LOG_PAYLOAD(DEBUG, payload); if(discoveryResult == OC_STACK_OK) { + SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK); } - else if(((request->devAddr.flags & OC_MULTICAST) == false) && - (request->devAddr.adapter != OC_ADAPTER_RFCOMM_BTEDR) && - (request->devAddr.adapter != OC_ADAPTER_GATT_BTLE)) + else // Error handling { - OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request", - discoveryResult, virtualUriInRequest); - SendNonPersistantDiscoveryResponse(request, resource, NULL, - (discoveryResult == OC_STACK_NO_RESOURCE) ? + if (isUnicast(request)) + { + OIC_LOG_V(ERROR, TAG, "Sending a (%d) error to (%d) discovery request", + discoveryResult, virtualUriInRequest); + SendNonPersistantDiscoveryResponse(request, resource, NULL, + (discoveryResult == OC_STACK_NO_RESOURCE) ? OC_EH_RESOURCE_NOT_FOUND : OC_EH_ERROR); - } - else - { - // Ignoring the discovery request as per RFC 7252, Section #8.2 - OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send."); - // the request should be removed. - // since it never remove and causes a big memory waste. - FindAndDeleteServerRequest(request); + } + else // Multicast + { + // Ignoring the discovery request as per RFC 7252, Section #8.2 + OIC_LOG(INFO, TAG, "Silently ignoring the request since no useful data to send."); + // the request should be removed. + // since it never remove and causes a big memory waste. + FindAndDeleteServerRequest(request); + } + discoveryResult = OC_STACK_CONTINUE; } } @@ -1585,6 +1599,7 @@ exit: { OICFree(dataModelVersions); } + // To ignore the message, OC_STACK_CONTINUE is sent return discoveryResult; } diff --git a/resource/csdk/stack/src/ocstack.c b/resource/csdk/stack/src/ocstack.c index 1cdd4da..88bb0c7 100644 --- a/resource/csdk/stack/src/ocstack.c +++ b/resource/csdk/stack/src/ocstack.c @@ -1350,7 +1350,7 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp OIC_LOG(ERROR, TAG, "Allocating memory for response failed"); return; } - + response->devAddr.adapter = OC_DEFAULT_ADAPTER; response->sequenceNumber = MAX_SEQUENCE_NUMBER + 1; CopyEndpointToDevAddr(endPoint, &response->devAddr); @@ -1460,16 +1460,22 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp OICFree(response); return; } - - if(OC_STACK_OK != OCParsePayload(&response->payload, + // In case of error, still want application to receive the error message. + if (OCResultToSuccess(response->result)) + { + if (OC_STACK_OK != OCParsePayload(&response->payload, type, responseInfo->info.payload, responseInfo->info.payloadSize)) + { + OIC_LOG(ERROR, TAG, "Error converting payload"); + OCPayloadDestroy(response->payload); + return; + } + } + else { - OIC_LOG(ERROR, TAG, "Error converting payload"); - OCPayloadDestroy(response->payload); - OICFree(response); - return; + response->resourceUri = OICStrdup(cbNode->requestUri); } } @@ -1536,16 +1542,14 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp if (OC_REST_DISCOVER == cbNode->method) { OCDiscoveryPayload *payload = (OCDiscoveryPayload*) response->payload; - if (!payload) + // Payload can be empty in case of error message. + if (payload && payload->sid) { - OIC_LOG(INFO, TAG, "discovery payload is invalid"); - return; + OICStrcpy(response->devAddr.remoteId, sizeof(response->devAddr.remoteId), + payload->sid); + OIC_LOG_V(INFO, TAG, "Device ID of response : %s", + response->devAddr.remoteId); } - - OICStrcpy(response->devAddr.remoteId, sizeof(response->devAddr.remoteId), - payload->sid); - OIC_LOG_V(INFO, TAG, "Device ID of response : %s", - response->devAddr.remoteId); } OCStackApplicationResult appFeedback = cbNode->callBack(cbNode->context, @@ -4628,6 +4632,7 @@ OCStackResult deleteResource(OCResource *resource) deleteResourceElements(temp); OICFree(temp); + temp = NULL; return OC_STACK_OK; } else @@ -4647,37 +4652,54 @@ void deleteResourceElements(OCResource *resource) return; } - OICFree(resource->uri); - deleteResourceType(resource->rsrcType); - deleteResourceInterface(resource->rsrcInterface); - OCDeleteResourceAttributes(resource->rsrcAttributes); + if (resource->uri) + { + OICFree(resource->uri); + } + if (resource->rsrcType) + { + deleteResourceType(resource->rsrcType); + } + if (resource->rsrcInterface) + { + deleteResourceInterface(resource->rsrcInterface); + } + if (resource->rsrcChildResourcesHead) + { + OICFree(resource->rsrcChildResourcesHead); + } + if (resource->rsrcAttributes) + { + OCDeleteResourceAttributes(resource->rsrcAttributes); + } } void deleteResourceType(OCResourceType *resourceType) { - OCResourceType *pointer = resourceType; OCResourceType *next = NULL; - while (pointer) + for (OCResourceType *pointer = resourceType; pointer; pointer = next) { next = pointer->next; - OICFree(pointer->resourcetypename); + if (pointer->resourcetypename) + { + OICFree(pointer->resourcetypename); + } OICFree(pointer); - pointer = next; } } void deleteResourceInterface(OCResourceInterface *resourceInterface) { - OCResourceInterface *pointer = resourceInterface; OCResourceInterface *next = NULL; - - while (pointer) + for (OCResourceInterface *pointer = resourceInterface; pointer; pointer = next) { next = pointer->next; - OICFree(pointer->name); + if (pointer->name) + { + OICFree(pointer->name); + } OICFree(pointer); - pointer = next; } } @@ -4691,11 +4713,14 @@ void OCDeleteResourceAttributes(OCAttribute *rsrcAttributes) { OCFreeOCStringLL((OCStringLL *)pointer->attrValue); } - else + else if (pointer->attrValue) { OICFree(pointer->attrValue); } - OICFree(pointer->attrName); + if (pointer->attrName) + { + OICFree(pointer->attrName); + } OICFree(pointer); } } @@ -5439,4 +5464,3 @@ OCStackResult OCGetDeviceOwnedState(bool *isOwned) } return ret; } - diff --git a/resource/csdk/stack/test/stacktests.cpp b/resource/csdk/stack/test/stacktests.cpp index 3b401c2..3d6f6a3 100644 --- a/resource/csdk/stack/test/stacktests.cpp +++ b/resource/csdk/stack/test/stacktests.cpp @@ -27,6 +27,7 @@ extern "C" #include "logger.h" #include "oic_malloc.h" #include "oic_string.h" + #include "oic_time.h" } #include "gtest/gtest.h" @@ -70,6 +71,7 @@ static char pinNumber; static OCDPDev_t peer; std::chrono::seconds const SHORT_TEST_TIMEOUT = std::chrono::seconds(5); +std::chrono::seconds const LONG_TEST_TIMEOUT = std::chrono::seconds(450); //----------------------------------------------------------------------------- // Callback functions @@ -176,6 +178,60 @@ uint8_t InitResourceIndex() return 0; #endif } + +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(long waitTime) + { + uint64_t startTime = OICGetCurrentTime(TIME_IN_MS); + while (!m_called) + { + uint64_t currTime = OICGetCurrentTime(TIME_IN_MS); + long elapsed = (long)((currTime - startTime) / MS_PER_SEC); + if (elapsed > waitTime) + { + m_called = true; + } + 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 OCDiscoverTests : public testing::Test +{ + protected: + virtual void SetUp() + { + EXPECT_EQ(OC_STACK_OK, OCInit("127.0.0.1", 5683, OC_CLIENT_SERVER)); + } + + virtual void TearDown() + { + OCStop(); + } +}; //----------------------------------------------------------------------------- // Tests //----------------------------------------------------------------------------- @@ -2241,3 +2297,213 @@ TEST(StackEndpoints, OCGetSupportedEndpointTpsFlags) EXPECT_EQ(OC_STACK_OK, OCStop()); } + +static OCStackApplicationResult DiscoverBaselineResource(void *ctx, OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(NULL != response->payload); + if (NULL != response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + + OCDiscoveryPayload *payload = (OCDiscoveryPayload *)response->payload; + EXPECT_TRUE(NULL != payload->sid); + EXPECT_STREQ("StackTest", payload->name); + EXPECT_STREQ(OC_RSRVD_RESOURCE_TYPE_RES, payload->type->value); + EXPECT_STREQ(OC_RSRVD_INTERFACE_LL, payload->iface->value); + EXPECT_STREQ(OC_RSRVD_INTERFACE_DEFAULT, payload->iface->next->value); + + for (OCResourcePayload *resource = payload->resources; resource; resource = resource->next) + { + if (0 == strcmp("/a/light", resource->uri)) + { + EXPECT_STREQ("/a/light", resource->uri); + EXPECT_STREQ("core.light", resource->types->value); + EXPECT_EQ(NULL, resource->types->next); + EXPECT_STREQ("oic.if.baseline", resource->interfaces->value); + EXPECT_EQ(NULL, resource->interfaces->next); + EXPECT_TRUE(resource->bitmap & OC_DISCOVERABLE); + EXPECT_FALSE(resource->secure); + EXPECT_EQ(0, resource->port); + EXPECT_EQ(NULL, resource->next); + } + } + } + + return OC_STACK_DELETE_TRANSACTION; +} + +static OCStackApplicationResult DiscoverLinkedListResource(void *ctx, OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(NULL != response->payload); + if (NULL != response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + + OCDiscoveryPayload *payload = (OCDiscoveryPayload *)response->payload; + EXPECT_NE((char *)NULL, payload->sid); + EXPECT_EQ(NULL, payload->name); + EXPECT_EQ(NULL, payload->type); + EXPECT_EQ(NULL, payload->iface); + + for (OCResourcePayload *resource = payload->resources; resource; resource = resource->next) + { + if (0 == strcmp("/a/light", resource->uri)) + { + EXPECT_STREQ("/a/light", resource->uri); + EXPECT_STREQ("core.light", resource->types->value); + EXPECT_EQ(NULL, resource->types->next); + EXPECT_STREQ("oic.if.baseline", resource->interfaces->value); + EXPECT_EQ(NULL, resource->interfaces->next); + EXPECT_TRUE(resource->bitmap & OC_DISCOVERABLE); + EXPECT_FALSE(resource->secure); + EXPECT_EQ(0, resource->port); + EXPECT_EQ(NULL, resource->next); + } + } + } + return OC_STACK_DELETE_TRANSACTION; +} + + +static OCStackApplicationResult DiscoverResourceTypeResponse(void *ctx, OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_EQ(OC_STACK_OK, response->result); + EXPECT_TRUE(NULL != response->payload); + if (NULL != response->payload) + { + EXPECT_EQ(PAYLOAD_TYPE_DISCOVERY, response->payload->type); + + OCDiscoveryPayload *payload = (OCDiscoveryPayload *)response->payload; + EXPECT_NE((char *)NULL, payload->sid); + EXPECT_EQ(NULL, payload->name); + EXPECT_EQ(NULL, payload->type); + EXPECT_EQ(NULL, payload->iface); + EXPECT_TRUE(NULL != payload->resources); + + OCResourcePayload *resource = payload->resources; + + if (0 == strcmp("/a/light", resource->uri)) + { + EXPECT_STREQ("/a/light", resource->uri); + EXPECT_STREQ("core.light", resource->types->value); + EXPECT_EQ(NULL, resource->types->next); + EXPECT_STREQ("oic.if.baseline", resource->interfaces->value); + EXPECT_EQ(NULL, resource->interfaces->next); + EXPECT_TRUE(resource->bitmap & OC_DISCOVERABLE); + EXPECT_FALSE(resource->secure); + EXPECT_EQ(0, resource->port); + EXPECT_EQ(NULL, resource->next); + } + } + + return OC_STACK_DELETE_TRANSACTION; +} + +static OCStackApplicationResult DiscoverUnicastErrorResponse(void *ctx, OCDoHandle handle, + OCClientResponse *response) +{ + OC_UNUSED(ctx); + OC_UNUSED(handle); + EXPECT_NE(OC_STACK_OK, response->result); + EXPECT_TRUE(NULL == response->payload); + + return OC_STACK_DELETE_TRANSACTION; +} + +TEST_F(OCDiscoverTests, DiscoverResourceWithValidQueries) +{ + itst::DeadmanTimer killSwitch(LONG_TEST_TIMEOUT); + + OCResourceHandle handles; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles, "core.light", "oic.if.baseline", "/a/light", + entityHandler, NULL, OC_DISCOVERABLE)); + OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME, "StackTest"); + + Callback discoverBaselineCB(&DiscoverBaselineResource); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=oic.if.baseline", NULL, + 0, CT_DEFAULT, OC_HIGH_QOS, discoverBaselineCB, NULL, 0)); + discoverBaselineCB.Wait(100); + + Callback discoverDefaultCB(&DiscoverLinkedListResource); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res", NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverDefaultCB, NULL, 0)); + discoverDefaultCB.Wait(100); + + Callback discoverLinkedListCB(&DiscoverLinkedListResource); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=oic.if.ll", NULL, 0, + CT_DEFAULT, OC_HIGH_QOS, discoverLinkedListCB, NULL, 0)); + discoverLinkedListCB.Wait(100); + + Callback discoverRTCB(&DiscoverResourceTypeResponse); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=core.light", NULL, 0, + CT_DEFAULT, OC_HIGH_QOS, discoverRTCB, NULL, 0)); + discoverRTCB.Wait(100); +} + +TEST_F(OCDiscoverTests, DiscoverResourceWithInvalidQueries) +{ + itst::DeadmanTimer killSwitch(LONG_TEST_TIMEOUT); + + OCResourceHandle handles; + EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handles, "core.light", "oic.if.baseline", "/a/light", + entityHandler, NULL, OC_DISCOVERABLE)); + OCSetPropertyValue(PAYLOAD_TYPE_DEVICE, "deviceName", "StackTest"); + + Callback discoverRTInvalidCB(&DiscoverUnicastErrorResponse); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=invalid", NULL, 0, + CT_DEFAULT, OC_HIGH_QOS, discoverRTInvalidCB, NULL, 0)); + discoverRTInvalidCB.Wait(10); + + Callback discoverRTEmptyCB(&DiscoverUnicastErrorResponse); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?rt=", NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverRTEmptyCB, NULL, 0)); + discoverRTEmptyCB.Wait(10); + + Callback discoverIfInvalidCB(&DiscoverUnicastErrorResponse); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=invalid", NULL, 0, + CT_DEFAULT, OC_HIGH_QOS, discoverIfInvalidCB, NULL, 0)); + discoverIfInvalidCB.Wait(10); + + Callback discoverIfEmptyCB(&DiscoverUnicastErrorResponse); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, "/oic/res?if=", NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverIfEmptyCB, NULL, 0)); + discoverIfEmptyCB.Wait(10); + + // Unicast + char targetUri[MAX_URI_LENGTH * 2] ={ 0, }; + + Callback discoverUnicastIfInvalidCB(&DiscoverUnicastErrorResponse); + snprintf(targetUri, MAX_URI_LENGTH * 2, "127.0.0.1/oic/res?if=invalid"); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, targetUri, NULL, 0, + CT_DEFAULT, OC_HIGH_QOS, discoverUnicastIfInvalidCB, NULL, 0)); + discoverUnicastIfInvalidCB.Wait(10); + + Callback discoverUnicastIfEmptyCB(&DiscoverUnicastErrorResponse); + snprintf(targetUri, MAX_URI_LENGTH * 2, "127.0.0.1/oic/res?if="); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, targetUri, NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverUnicastIfEmptyCB, NULL, 0)); + discoverUnicastIfEmptyCB.Wait(10); + + Callback discoverUnicastRTInvalidCB(&DiscoverUnicastErrorResponse); + snprintf(targetUri, MAX_URI_LENGTH * 2, "127.0.0.1/oic/res?rt=invalid"); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, targetUri, NULL, 0, + CT_DEFAULT, OC_HIGH_QOS, discoverUnicastRTInvalidCB, NULL, 0)); + discoverUnicastRTInvalidCB.Wait(10); + + Callback discoverUnicastRTEmptyCB(&DiscoverUnicastErrorResponse); + snprintf(targetUri, MAX_URI_LENGTH * 2, "127.0.0.1/oic/res?rt="); + EXPECT_EQ(OC_STACK_OK, OCDoResource(NULL, OC_REST_DISCOVER, targetUri, NULL, 0, CT_DEFAULT, + OC_HIGH_QOS, discoverUnicastRTEmptyCB, NULL, 0)); + discoverUnicastRTEmptyCB.Wait(10); +} -- 2.7.4