From 373416b35b7f4f333a01d16297baf698d8c5b2a6 Mon Sep 17 00:00:00 2001 From: "bg.chun" Date: Tue, 23 Aug 2016 19:06:01 +0900 Subject: [PATCH] [IOT-1207] Endpoint C++ API Provide public C++ api for map ocf endpoint flag to resource in server and change host of resource in client. Change-Id: I2f4892144c9732fb38162b7174812fa8c51ce02c Signed-off-by: bg.chun Reviewed-on: https://gerrit.iotivity.org/gerrit/10797 Tested-by: jenkins-iotivity Reviewed-by: Dave Thaler Reviewed-by: Dan Mihai Reviewed-by: Ashok Babu Channa --- resource/csdk/stack/src/ocstack.c | 79 ++++++++++++++ resource/examples/simpleclient.cpp | 41 +++++++ resource/include/IServerWrapper.h | 11 ++ resource/include/InProcServerWrapper.h | 10 ++ resource/include/OCPlatform.h | 90 ++++++++++++---- resource/include/OCPlatform_impl.h | 83 ++++++++++++--- resource/include/OCResource.h | 30 +++++- resource/include/OCSerialization.h | 58 +++++++++- resource/include/StringConstants.h | 1 + resource/src/InProcServerWrapper.cpp | 47 ++++++-- resource/src/OCException.cpp | 2 + resource/src/OCPlatform.cpp | 22 +++- resource/src/OCPlatform_impl.cpp | 19 ++++ resource/src/OCResource.cpp | 189 ++++++++++++++++++++++++++++++--- resource/unittests/OCExceptionTest.cpp | 6 +- resource/unittests/OCPlatformTest.cpp | 50 +++++++++ resource/unittests/OCResourceTest.cpp | 48 ++++++++- 17 files changed, 724 insertions(+), 62 deletions(-) diff --git a/resource/csdk/stack/src/ocstack.c b/resource/csdk/stack/src/ocstack.c index 401aacd..db9da9f 100644 --- a/resource/csdk/stack/src/ocstack.c +++ b/resource/csdk/stack/src/ocstack.c @@ -429,6 +429,14 @@ static void OCDefaultConnectionStateChangedHandler(const CAEndpoint_t *info, boo */ static void OCSetNetworkMonitorHandler(CAAdapterStateChangedCB adapterHandler, CAConnectionStateChangedCB connectionHandler); +/** + * Map zoneId to endpoint address which scope is ipv6 link-local. + * @param payload Discovery payload which has Endpoint information. + * @param ifindex index which indicate network interface. + */ +#ifndef WITH_ARDUINO +static OCStackResult OCMapZoneIdToLinkLocalEndpoint(OCDiscoveryPayload *payload, uint32_t ifindex); +#endif //----------------------------------------------------------------------------- // Internal functions @@ -1311,6 +1319,61 @@ OCStackResult HandleBatchResponse(char *requestUri, OCRepPayload **payload) return OC_STACK_INVALID_PARAM; } +#ifndef WITH_ARDUINO +OCStackResult OCMapZoneIdToLinkLocalEndpoint(OCDiscoveryPayload *payload, uint32_t ifindex) +{ + if (!payload) + { + OIC_LOG(ERROR, TAG, "Given argument payload is NULL!!"); + return OC_STACK_INVALID_PARAM; + } + + OCResourcePayload *curRes = payload->resources; + + while (curRes != NULL) + { + OCEndpointPayload* eps = curRes->eps; + + while (eps != NULL) + { + if (eps->family & OC_IP_USE_V6) + { + CATransportFlags_t scopeLevel; + if (CA_STATUS_OK == CAGetIpv6AddrScope(eps->addr, &scopeLevel)) + { + if (CA_SCOPE_LINK == scopeLevel) + { + char *zoneId = NULL; + if (OC_STACK_OK == OCGetLinkLocalZoneId(ifindex, &zoneId)) + { + assert(zoneId != NULL); + // put zoneId to end of addr + OICStrcat(eps->addr, OC_MAX_ADDR_STR_SIZE, "%"); + OICStrcat(eps->addr, OC_MAX_ADDR_STR_SIZE, zoneId); + OICFree(zoneId); + } + else + { + OIC_LOG(ERROR, TAG, "failed at parse zone-id for link-local address"); + return OC_STACK_ERROR; + } + } + } + else + { + OIC_LOG(ERROR, TAG, "failed at parse ipv6 scope level"); + return OC_STACK_ERROR; + } + } + eps = eps->next; + } + curRes = curRes->next; + } + + return OC_STACK_OK; +} +#endif + void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo) { OIC_LOG(DEBUG, TAG, "Enter OCHandleResponse"); @@ -1558,6 +1621,22 @@ void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* resp OCPayloadDestroy(response->payload); return; } + + // Check endpoints has link-local ipv6 address. + // if there is, map zone-id which parsed from ifindex +#ifndef WITH_ARDUINO + if (PAYLOAD_TYPE_DISCOVERY == response->payload->type) + { + OCDiscoveryPayload *disPayload = (OCDiscoveryPayload*)(response->payload); + if (OC_STACK_OK != + OCMapZoneIdToLinkLocalEndpoint(disPayload, response->devAddr.ifindex)) + { + OIC_LOG(ERROR, TAG, "failed at map zone-id for link-local address"); + OCPayloadDestroy(response->payload); + return; + } + } +#endif } else { diff --git a/resource/examples/simpleclient.cpp b/resource/examples/simpleclient.cpp index 0c0149e..6c287be 100644 --- a/resource/examples/simpleclient.cpp +++ b/resource/examples/simpleclient.cpp @@ -392,6 +392,47 @@ void foundResource(std::shared_ptr resource) std::cout << "\t\t" << resourceInterfaces << std::endl; } + // Get Resource current host + std::cout << "\tHost of resource: " << std::endl; + std::cout << "\t\t" << resource->host() << std::endl; + + // Get Resource Endpoint Infomation + std::cout << "\tList of resource endpoints: " << std::endl; + for(auto &resourceEndpoints : resource->getAllHosts()) + { + std::cout << "\t\t" << resourceEndpoints << std::endl; + } + + // If resource is found from ip based adapter. + if (std::string::npos != resource->host().find("coap://") || + std::string::npos != resource->host().find("coaps://") || + std::string::npos != resource->host().find("coap+tcp://") || + std::string::npos != resource->host().find("coaps+tcp://")) + { + for(auto &resourceEndpoints : resource->getAllHosts()) + { + if (resourceEndpoints.compare(resource->host()) != 0 && + std::string::npos == resourceEndpoints.find("coap+rfcomm")) + { + std::string newHost = resourceEndpoints; + + if (std::string::npos != newHost.find("tcp")) + { + TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_TCP; + } + else + { + TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_IP; + } + // Change Resource host if another host exists + std::cout << "\tChange host of resource endpoints" << std::endl; + std::cout << "\t\t" << "Current host is " + << resource->setHost(newHost) << std::endl; + break; + } + } + } + if(resourceURI == "/a/light") { if (resource->connectivityType() & TRANSPORT_TYPE_TO_USE) diff --git a/resource/include/IServerWrapper.h b/resource/include/IServerWrapper.h index 1025a15..ec3374a 100644 --- a/resource/include/IServerWrapper.h +++ b/resource/include/IServerWrapper.h @@ -51,6 +51,15 @@ namespace OC EntityHandler& entityHandler, uint8_t resourceProperty) = 0; + virtual OCStackResult registerResourceWithTps( + OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler& entityHandler, + uint8_t resourceProperty, + OCTpsSchemeFlags resourceTpsTypes) = 0; + // @deprecated: Use setPropertyValue instead. virtual OCStackResult registerDeviceInfo( const OCDeviceInfo deviceInfo) = 0; @@ -86,6 +95,8 @@ namespace OC virtual OCStackResult stop() = 0; virtual OCStackResult start() = 0; + + virtual OCStackResult getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps) = 0; }; } diff --git a/resource/include/InProcServerWrapper.h b/resource/include/InProcServerWrapper.h index 9762818..3d213bd 100644 --- a/resource/include/InProcServerWrapper.h +++ b/resource/include/InProcServerWrapper.h @@ -44,6 +44,15 @@ namespace OC EntityHandler& entityHandler, uint8_t resourceProperty); + virtual OCStackResult registerResourceWithTps( + OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler& entityHandler, + uint8_t resourceProperty, + OCTpsSchemeFlags resourceTpsTypes); + // @deprecated: Use setPropertyValue instead. virtual OCStackResult registerDeviceInfo( const OCDeviceInfo deviceInfo); @@ -80,6 +89,7 @@ namespace OC virtual OCStackResult start(); + virtual OCStackResult getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps); private: void processFunc(); std::thread m_processThread; diff --git a/resource/include/OCPlatform.h b/resource/include/OCPlatform.h index e4c2b0e..1f57b58 100644 --- a/resource/include/OCPlatform.h +++ b/resource/include/OCPlatform.h @@ -272,31 +272,37 @@ namespace OC QualityOfService QoS); /** + * This function returns flags of supported endpoint TPS on stack. + * + * @param[out] supportedTps Bit combinations of supported OCTpsSchemeFlags. + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps); + + /** * This API registers a resource with the server * @note This API applies to server side only. * * @param resourceHandle Upon successful registration, resourceHandle will be filled * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below - * @param resourceTypeName The resource type. Example: "light" + * @param resourceTypeName The resource type. Example: "core.light" * @param resourceInterface The resource interface (whether it is collection etc). * @param entityHandler entity handler callback. - * @param resourceProperty indicates the property of the resource. Defined in ocstack.h. + * @param resourceProperty indicates the property of the resource. Defined in octypes.h. * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource * setting resourceProperty as OC_OBSERVABLE will allow observation - * settings resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery and - * observation + * setting resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery + * and observation * * @return Returns ::OC_STACK_OK if success. - * @note "a/light" is a relative URI. - * Above relative URI will be prepended (by core) with a host IP + namespace "oic" - * Therefore, fully qualified URI format would be //HostIP-Address/namespace/relativeURI" - * Example, a relative URI: 'a/light' will result in a fully qualified URI: - * //192.168.1.1/oic/a/light" - * First parameter can take a relative URI and core will take care of preparing the fully - * qualified URI OR - * first parameter can take fully qualified URI and core will take that as is for further - * operations - * @note OCStackResult is defined in ocstack.h. + * @note "a/light" is a relative reference to URI. + * Above relative reference to URI will be prepended (by core) with a host IP + * Therefore, fully qualified URI format would be + * "CoAP(s)+protocol-URI-Scheme://HostIP-Address/relativeURI" + * Example, a relative reference to URI: 'a/light' will result in a fully qualified URI: + * "coap://192.168.1.1:5246/a/light", "coaps://192.168.1.1:5246/a/light" + * @note OCStackResult is defined in octypes.h. * @note entity handler callback : * When you set specific return value like OC_EH_CHANGED, OC_EH_CONTENT, * OC_EH_SLOW and etc in entity handler callback, @@ -313,6 +319,49 @@ namespace OC uint8_t resourceProperty); /** + * This API registers a resource with the server + * @note This API applies to server side only. + * + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below + * @param resourceTypeName The resource type. Example: "core.light" + * @param resourceInterface The resource interface (whether it is collection etc). + * @param entityHandler Entity handler callback. + * @param resourceProperty indicates the property of the resource. Defined in octypes.h. + * @param resourceTpsTypes Transport Protocol Suites(TPS) types of resource for + open resource to specific transport adapter (e.g., TCP, UDP) + with messaging protocol(e.g., COAP, COAPS). + Example: "OC_COAP | OC_COAP_TCP" + * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource + * setting resourceProperty as OC_OBSERVABLE will allow observation + * setting resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery + * and observation + * + * @return Returns ::OC_STACK_OK if success. + * @note "a/light" is a relative reference to URI. + * Above relative reference to URI will be prepended (by core) with a host IP + * Therefore, fully qualified URI format would be + * "CoAP(s)+protocol-URI-Scheme://HostIP-Address/relativeURI" + * Example, a relative reference to URI: 'a/light' will result in a fully qualified URI: + * "coap://192.168.1.1:5246/a/light", "coaps://192.168.1.1:5246/a/light" + * @note OCStackResult is defined in octypes.h. + * @note entity handler callback : + * When you set specific return value like OC_EH_CHANGED, OC_EH_CONTENT, + * OC_EH_SLOW and etc in entity handler callback, + * ocstack will be not send response automatically to client + * except for error return value like OC_EH_ERROR + * If you want to send response to client with specific result, + * OCDoResponse API should be called with the result value. + */ + OCStackResult registerResource(OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler entityHandler, + uint8_t resourceProperty, + OCTpsSchemeFlags resourceTpsTypes); + + /** * This API registers a resource with the server * @note This API applies to server & client side. * @@ -617,17 +666,18 @@ namespace OC * to be a Client or Client/Server. Otherwise, this will return an empty * shared ptr. * - * @param host a string containing a resolvable host address of the server - * holding the resource. Currently this should be in the format of - * coap://address:port for IPv4 and in the format of - * coap://[address%25ZoneID]:port for IPv6. In the future, we expect - * "coap:" section is removed from this format. + * @param host a string containing a resolvable "coap(s)", "coap(s)+protocol" uri scheme + * of the server holding the resource. + * Currently this should be in the format coap(s)://address:port or + * coap(s)+protocol://address:port, though in the future, we expect this to + * change to //address:port * * @param uri the rest of the resource's URI that will permit messages to be * properly routed. Example: /a/light * * @param connectivityType ::OCConnectivityType type of connectivity indicating the - * interface. Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. + * transport method and IP address scope. + * Example: CT_DEFAULT, CT_ADAPTER_IP, CT_ADAPTER_TCP. * if you want to use a specific Flag like IPv4, * you should apply OR operation for the flag in here. * Example: static_cast(CT_ADAPTER_TCP diff --git a/resource/include/OCPlatform_impl.h b/resource/include/OCPlatform_impl.h index 4923de0..6637c16 100644 --- a/resource/include/OCPlatform_impl.h +++ b/resource/include/OCPlatform_impl.h @@ -156,31 +156,87 @@ namespace OC std::vector& value); /** + * This function returns flags of supported endpoint TPS on stack. + * + * @param[out] supportedTps Bit combinations of supported OCTpsSchemeFlags. + * + * @return Returns ::OC_STACK_OK if success. + */ + OCStackResult getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps); + + /** + * This API registers a resource with the server + * @note This API applies to server side only. + * + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below + * @param resourceTypeName The resource type. Example: "core.light" + * @param resourceInterface The resource interface (whether it is collection etc). + * @param entityHandler Entity handler callback. + * @param resourceProperty indicates the property of the resource. Defined in octypes.h. + * @param resourceTpsTypes Transport Protocol Suites(TPS) types of resource for + open resource to specific transport adapter (e.g., TCP, UDP) + with messaging protocol(e.g., COAP, COAPS). + Example: "OC_COAP | OC_COAP_TCP" + * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource + * setting resourceProperty as OC_OBSERVABLE will allow observation + * setting resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery + * and observation + * + * @return Returns ::OC_STACK_OK if success. + * @note "a/light" is a relative reference to URI. + * Above relative reference to URI will be prepended (by core) with a host IP + * Therefore, fully qualified URI format would be + * "CoAP(s)+protocol-URI-Scheme://HostIP-Address/relativeURI" + * Example, a relative reference to URI: 'a/light' will result in a fully qualified URI: + * "coap://192.168.1.1:5246/a/light", "coaps://192.168.1.1:5246/a/light" + * @note OCStackResult is defined in octypes.h. + * @note entity handler callback : + * When you set specific return value like OC_EH_CHANGED, OC_EH_CONTENT, + * OC_EH_SLOW and etc in entity handler callback, + * ocstack will be not send response automatically to client + * except for error return value like OC_EH_ERROR + * If you want to send response to client with specific result, + * OCDoResponse API should be called with the result value. + */ + OCStackResult registerResource(OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler entityHandler, + uint8_t resourceProperty, + OCTpsSchemeFlags resourceTpsTypes); + + /** * This API registers a resource with the server * @note This API applies to server side only. * * @param resourceHandle Upon successful registration, resourceHandle will be filled * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below - * @param resourceTypeName The resource type. Example: "light" + * @param resourceTypeName The resource type. Example: "core.light" * @param resourceInterface The resource interface (whether it is collection etc). * @param entityHandler entity handler callback. - * @param resourceProperty indicates the property of the resource. Defined in ocstack.h. + * @param resourceProperty indicates the property of the resource. Defined in octypes.h. * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource * setting resourceProperty as OC_OBSERVABLE will allow observation - * settings resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery + * setting resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery * and observation * * @return Returns ::OC_STACK_OK if success. - * @note "a/light" is a relative URI. - * Above relative URI will be prepended (by core) with a host IP + namespace "oc" - * Therefore, fully qualified URI format would be //HostIP-Address/namespace/relativeURI" - * Example, a relative URI: 'a/light' will result in a fully qualified URI: - * //192.168.1.1/oic/a/light" - * First parameter can take a relative URI and core will take care of preparing the fully - * qualified URI OR - * first parameter can take fully qualified URI and core will take that as is for further - * operations - * @note OCStackResult is defined in ocstack.h. + * @note "a/light" is a relative reference to URI. + * Above relative reference to URI will be prepended (by core) with a host IP + * Therefore, fully qualified URI format would be + * "CoAP(s)+protocol-URI-Scheme://HostIP-Address/relativeURI" + * Example, a relative reference to URI: 'a/light' will result in a fully qualified URI: + * "coap://192.168.1.1:5246/a/light", "coaps://192.168.1.1:5246/a/light" + * @note OCStackResult is defined in octypes.h. + * @note entity handler callback : + * When you set specific return value like OC_EH_CHANGED, OC_EH_CONTENT, + * OC_EH_SLOW and etc in entity handler callback, + * ocstack will be not send response automatically to client + * except for error return value like OC_EH_ERROR + * If you want to send response to client with specific result, + * OCDoResponse API should be called with the result value. */ OCStackResult registerResource(OCResourceHandle& resourceHandle, std::string& resourceURI, @@ -260,6 +316,7 @@ namespace OC OCConnectivityType connectivityType, bool isObservable, const std::vector& resourceTypes, const std::vector& interfaces); + OCStackResult sendResponse(const std::shared_ptr pResponse); std::weak_ptr csdkLock(); diff --git a/resource/include/OCResource.h b/resource/include/OCResource.h index fd468f6..fbb324a 100644 --- a/resource/include/OCResource.h +++ b/resource/include/OCResource.h @@ -123,6 +123,7 @@ namespace OC m_resourceTypes(std::move(o.m_resourceTypes)), m_interfaces(std::move(o.m_interfaces)), m_children(std::move(m_children)), + m_endpoints(std::move(m_endpoints)), m_observeHandle(std::move(m_observeHandle)), m_headerOptions(std::move(m_headerOptions)) { @@ -485,6 +486,12 @@ namespace OC std::string host() const; /** + * Function to get the endpoints information of this resource + * @return std::vector endpoints information + */ + std::vector getAllHosts() const; + + /** * Function to get the URI for this resource * @return std::string resource URI */ @@ -503,6 +510,12 @@ namespace OC */ bool isObservable() const; + /** + * Function to change host of this reource + * @return std::string New host Address. + * not observable. + */ + std::string setHost(const std::string& host); #ifdef WITH_MQ /** * Function to provide ability to check if this resource is publisher or not @@ -654,7 +667,6 @@ namespace OC bool operator>=(const OCResource &other) const; private: - void setHost(const std::string& host); std::weak_ptr m_clientWrapper; std::string m_uri; OCResourceIdentifier m_resourceId; @@ -665,6 +677,7 @@ namespace OC std::vector m_resourceTypes; std::vector m_interfaces; std::vector m_children; + std::vector m_endpoints; OCDoHandle m_observeHandle; HeaderOptions m_headerOptions; @@ -676,11 +689,26 @@ namespace OC const std::vector& interfaces); OCResource(std::weak_ptr clientWrapper, + const OCDevAddr& devAddr, const std::string& uri, + const std::string& serverId, uint8_t property, + const std::vector& resourceTypes, + const std::vector& interfaces, + const std::vector& endpoints); + + OCResource(std::weak_ptr clientWrapper, const std::string& host, const std::string& uri, const std::string& serverId, OCConnectivityType connectivityType, uint8_t property, const std::vector& resourceTypes, const std::vector& interfaces); + + OCResource(std::weak_ptr clientWrapper, + const std::string& host, const std::string& uri, + const std::string& serverId, + OCConnectivityType connectivityType, uint8_t property, + const std::vector& resourceTypes, + const std::vector& interfaces, + const std::vector& endpoints); }; } // namespace OC diff --git a/resource/include/OCSerialization.h b/resource/include/OCSerialization.h index 96352a7..a3ee22b 100644 --- a/resource/include/OCSerialization.h +++ b/resource/include/OCSerialization.h @@ -19,12 +19,19 @@ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #include +#include +#include #include "ocpayload.h" #include "ocrandom.h" #include "oic_string.h" namespace OC { + static const char EP_ADDR_SPLIT[] = "://"; + static const char EP_PORT_SPLIT[] = ":"; + static const char EP_BRAKET_START[] = "["; + static const char EP_BRAKET_END[] = "]"; + class ListenOCContainer { private: @@ -39,6 +46,40 @@ namespace OC return strs; } + static std::vector EpsLLToVector(OCEndpointPayload* head) + { + std::vector strs; + while (head) + { + std::ostringstream endpoint; + endpoint << head->tps << EP_ADDR_SPLIT; + + switch (head->family) + { + case OC_DEFAULT_FLAGS: + // mac + endpoint << head->addr; + break; + + case OC_IP_USE_V4: + endpoint << head->addr << EP_PORT_SPLIT << head->port; + break; + + case OC_IP_USE_V6: + endpoint << EP_BRAKET_START << head->addr << EP_BRAKET_END + << EP_PORT_SPLIT << head->port; + break; + default: + head = head->next; + continue; + } + + strs.push_back(endpoint.str()); + head = head->next; + } + return strs; + } + public: ListenOCContainer(std::weak_ptr cw, OCDevAddr& devAddr, OCDiscoveryPayload* payload) @@ -56,6 +97,14 @@ namespace OC currentDevAddr.port = (res->port != 0) ? res->port : devAddr.port; + OCEndpointPayload* eps = res->eps; + std::vector epsVector; + if (eps) + { + //parsing eps from payload + epsVector = EpsLLToVector(eps); + } + if (payload->baseURI) { OCDevAddr rdPubAddr = currentDevAddr; @@ -73,7 +122,8 @@ namespace OC std::string(payload->sid), res->bitmap, StringLLToVector(res->types), - StringLLToVector(res->interfaces) + StringLLToVector(res->interfaces), + epsVector ))); } else @@ -84,7 +134,8 @@ namespace OC std::string(payload->sid), res->bitmap, StringLLToVector(res->types), - StringLLToVector(res->interfaces) + StringLLToVector(res->interfaces), + epsVector ))); #ifdef TCP_ADAPTER @@ -99,7 +150,8 @@ namespace OC std::string(payload->sid), res->bitmap, StringLLToVector(res->types), - StringLLToVector(res->interfaces) + StringLLToVector(res->interfaces), + epsVector ))); } #endif diff --git a/resource/include/StringConstants.h b/resource/include/StringConstants.h index ae7869c..c12e50e 100644 --- a/resource/include/StringConstants.h +++ b/resource/include/StringConstants.h @@ -131,6 +131,7 @@ namespace OC static const char PUBLISH_RESOURCE_FAILED[] = "Publish Resource failure"; static const char FORBIDDEN_REQ[] = "Forbidden request"; static const char INTERNAL_SERVER_ERROR[] = "Internal server error"; + static const char BAD_ENDPOINT[] = "Bad Endpoint"; } namespace Error diff --git a/resource/src/InProcServerWrapper.cpp b/resource/src/InProcServerWrapper.cpp index 774094d..67a44ca 100644 --- a/resource/src/InProcServerWrapper.cpp +++ b/resource/src/InProcServerWrapper.cpp @@ -435,7 +435,19 @@ namespace OC const std::string& resourceInterface, EntityHandler& eHandler, uint8_t resourceProperties) + { + return registerResourceWithTps(resourceHandle, resourceURI, resourceTypeName, + resourceInterface, eHandler, resourceProperties, OC_ALL); + } + OCStackResult InProcServerWrapper::registerResourceWithTps( + OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler& eHandler, + uint8_t resourceProperties, + OCTpsSchemeFlags resourceTpsTypes) { OCStackResult result = OC_STACK_ERROR; @@ -447,25 +459,27 @@ namespace OC if(NULL != eHandler) { - result = OCCreateResource(&resourceHandle, // OCResourceHandle *handle + result = OCCreateResourceWithEp(&resourceHandle, // OCResourceHandle *handle resourceTypeName.c_str(), // const char * resourceTypeName - resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix this + //const char * resourceInterfaceName //TODO fix this + resourceInterface.c_str(), resourceURI.c_str(), // const char * uri EntityHandlerWrapper, // OCEntityHandler entityHandler NULL, - resourceProperties // uint8_t resourceProperties - ); + resourceProperties, // uint8_t resourceProperties + resourceTpsTypes); // OCTpsSchemeFlags resourceTpsTypes } else { - result = OCCreateResource(&resourceHandle, // OCResourceHandle *handle + result = OCCreateResourceWithEp(&resourceHandle, // OCResourceHandle *handle resourceTypeName.c_str(), // const char * resourceTypeName - resourceInterface.c_str(), //const char * resourceInterfaceName //TODO fix this + //const char * resourceInterfaceName //TODO fix this + resourceInterface.c_str(), resourceURI.c_str(), // const char * uri NULL, // OCEntityHandler entityHandler NULL, - resourceProperties // uint8_t resourceProperties - ); + resourceProperties, // uint8_t resourceProperties + resourceTpsTypes); // OCTpsSchemeFlags resourceTpsTypes } if(result != OC_STACK_OK) @@ -689,6 +703,23 @@ namespace OC } } + OCStackResult InProcServerWrapper::getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps) + { + auto cLock = m_csdkLock.lock(); + OCStackResult result = OC_STACK_ERROR; + if (cLock) + { + std::lock_guard lock(*cLock); + supportedTps = OCGetSupportedEndpointTpsFlags(); + + if (OC_NO_TPS != supportedTps) + { + result = OC_STACK_OK; + } + } + return result; + } + InProcServerWrapper::~InProcServerWrapper() { try diff --git a/resource/src/OCException.cpp b/resource/src/OCException.cpp index d413fd9..34fe08f 100644 --- a/resource/src/OCException.cpp +++ b/resource/src/OCException.cpp @@ -119,6 +119,8 @@ std::string OC::OCException::reason(const OCStackResult sr) return OC::Exception::FORBIDDEN_REQ; case OC_STACK_INTERNAL_SERVER_ERROR: return OC::Exception::INTERNAL_SERVER_ERROR; + case OC_STACK_BAD_ENDPOINT: + return OC::Exception::BAD_ENDPOINT; } return OC::Exception::UNKNOWN_ERROR; diff --git a/resource/src/OCPlatform.cpp b/resource/src/OCPlatform.cpp index 80db44b..0fa1db3 100644 --- a/resource/src/OCPlatform.cpp +++ b/resource/src/OCPlatform.cpp @@ -187,12 +187,18 @@ namespace OC platformInfoHandler, QoS); } + OCStackResult getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps) + { + return OCPlatform_impl::Instance().getSupportedTransportsInfo(supportedTps); + } + OCStackResult registerResource(OCResourceHandle& resourceHandle, std::string& resourceURI, const std::string& resourceTypeName, const std::string& resourceInterface, EntityHandler entityHandler, - uint8_t resourceProperty) + uint8_t resourceProperty + ) { return OCPlatform_impl::Instance().registerResource(resourceHandle, resourceURI, resourceTypeName, resourceInterface, @@ -200,6 +206,20 @@ namespace OC } OCStackResult registerResource(OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler entityHandler, + uint8_t resourceProperty, + OCTpsSchemeFlags resourceTpsTypes) + { + return OCPlatform_impl::Instance().registerResource(resourceHandle, resourceURI, + resourceTypeName, resourceInterface, + entityHandler, resourceProperty, + resourceTpsTypes); + } + + OCStackResult registerResource(OCResourceHandle& resourceHandle, const std::shared_ptr< OCResource > resource) { return OCPlatform_impl::Instance().registerResource(resourceHandle, resource); diff --git a/resource/src/OCPlatform_impl.cpp b/resource/src/OCPlatform_impl.cpp index 7f7d412..b04e14e 100644 --- a/resource/src/OCPlatform_impl.cpp +++ b/resource/src/OCPlatform_impl.cpp @@ -355,6 +355,11 @@ namespace OC host, platformURI, connectivityType, platformInfoHandler, QoS); } + OCStackResult OCPlatform_impl::getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps) + { + return checked_guard(m_server, &IServerWrapper::getSupportedTransportsInfo, supportedTps); + } + OCStackResult OCPlatform_impl::registerResource(OCResourceHandle& resourceHandle, std::string& resourceURI, const std::string& resourceTypeName, @@ -367,6 +372,20 @@ namespace OC resourceInterface, entityHandler, resourceProperty); } + OCStackResult OCPlatform_impl::registerResource(OCResourceHandle& resourceHandle, + std::string& resourceURI, + const std::string& resourceTypeName, + const std::string& resourceInterface, + EntityHandler entityHandler, + uint8_t resourceProperty, + OCTpsSchemeFlags resourceTpsTypes) + { + return checked_guard(m_server, &IServerWrapper::registerResourceWithTps, + std::ref(resourceHandle), resourceURI, resourceTypeName, + resourceInterface, entityHandler, resourceProperty, + resourceTpsTypes); + } + OCStackResult OCPlatform_impl::registerDeviceInfo(const OCDeviceInfo deviceInfo) { return checked_guard(m_server, &IServerWrapper::registerDeviceInfo, deviceInfo); diff --git a/resource/src/OCResource.cpp b/resource/src/OCResource.cpp index d4ca4b2..f31c1e1 100644 --- a/resource/src/OCResource.cpp +++ b/resource/src/OCResource.cpp @@ -21,6 +21,11 @@ #include "iotivity_config.h" #include "OCResource.h" #include "OCUtilities.h" +#include "ocstack.h" +#include "oic_malloc.h" +#include "cacommon.h" +#include "cautilinterface.h" +#include "oic_string.h" #include #include @@ -73,15 +78,91 @@ OCResource::OCResource(std::weak_ptr clientWrapper, } OCResource::OCResource(std::weak_ptr clientWrapper, + const OCDevAddr& devAddr, const std::string& uri, + const std::string& serverId, uint8_t property, + const std::vector& resourceTypes, + const std::vector& interfaces, + const std::vector& endpoints) + : m_clientWrapper(clientWrapper), m_uri(uri), + m_resourceId(serverId, m_uri), m_devAddr(devAddr), + m_isCollection(false), m_property(property), + m_resourceTypes(resourceTypes), m_interfaces(interfaces), + m_endpoints(endpoints), + m_observeHandle(nullptr) +{ + m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE) + != m_interfaces.end(); + + if (m_uri.empty() || + resourceTypes.empty() || + interfaces.empty()|| + m_clientWrapper.expired()) + { + throw ResourceInitException(m_uri.empty(), resourceTypes.empty(), + interfaces.empty(), m_clientWrapper.expired(), false, false); + } +} + +OCResource::OCResource(std::weak_ptr clientWrapper, const std::string& host, const std::string& uri, const std::string& serverId, OCConnectivityType connectivityType, uint8_t property, const std::vector& resourceTypes, - const std::vector& interfaces) + const std::vector& interfaces, + const std::vector& endpoints) : m_clientWrapper(clientWrapper), m_uri(uri), m_resourceId(serverId, m_uri), m_isCollection(false), m_property(property), m_resourceTypes(resourceTypes), m_interfaces(interfaces), + m_endpoints(endpoints), + m_observeHandle(nullptr) +{ + m_devAddr = OCDevAddr{OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS, 0, {0}, 0, +#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) + {0} +#endif + }; + m_isCollection = std::find(m_interfaces.begin(), m_interfaces.end(), LINK_INTERFACE) + != m_interfaces.end(); + + if (m_uri.empty() || + resourceTypes.empty() || + interfaces.empty()|| + m_clientWrapper.expired()) + { + throw ResourceInitException(m_uri.empty(), resourceTypes.empty(), + interfaces.empty(), m_clientWrapper.expired(), false, false); + } + + if (uri.length() == 1 && uri[0] == '/') + { + throw ResourceInitException(m_uri.empty(), resourceTypes.empty(), + interfaces.empty(), m_clientWrapper.expired(), false, false); + } + + if (uri[0] != '/') + { + throw ResourceInitException(m_uri.empty(), resourceTypes.empty(), + interfaces.empty(), m_clientWrapper.expired(), false, false); + } + + // construct the devAddr from the pieces we have + m_devAddr.adapter = static_cast(connectivityType >> CT_ADAPTER_SHIFT); + m_devAddr.flags = static_cast(connectivityType & CT_MASK_FLAGS); + + this->setHost(host); +} + +OCResource::OCResource(std::weak_ptr clientWrapper, + const std::string& host, const std::string& uri, + const std::string& serverId, + OCConnectivityType connectivityType, uint8_t property, + const std::vector& resourceTypes, + const std::vector& interfaces) +: m_clientWrapper(clientWrapper), m_uri(uri), + m_resourceId(serverId, m_uri), + m_isCollection(false), m_property(property), + m_resourceTypes(resourceTypes), m_interfaces(interfaces), m_observeHandle(nullptr) { m_devAddr = OCDevAddr{OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS, 0, {0}, 0, @@ -124,35 +205,64 @@ OCResource::~OCResource() { } -void OCResource::setHost(const std::string& host) +std::string OCResource::setHost(const std::string& host) { size_t prefix_len; - if (host.compare(0, sizeof(COAP) - 1, COAP) == 0) - { - prefix_len = sizeof(COAP) - 1; - } - else if (host.compare(0, sizeof(COAPS) - 1, COAPS) == 0) + OCDevAddr new_devAddr; + memset(&new_devAddr, 0, sizeof(new_devAddr)); + new_devAddr.adapter = OC_DEFAULT_ADAPTER; + new_devAddr.flags = OC_DEFAULT_FLAGS; + + // init m_devAddr + m_devAddr = new_devAddr; + bool usingIpAddr = false; + + if (host.compare(0, sizeof(COAPS) - 1, COAPS) == 0) { + if (!OC_SECURE) + { + throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), + m_interfaces.empty(), m_clientWrapper.expired(), false, false); + } prefix_len = sizeof(COAPS) - 1; m_devAddr.flags = static_cast(m_devAddr.flags | OC_SECURE); + m_devAddr.adapter = OC_ADAPTER_IP; + usingIpAddr = true; + } + else if (host.compare(0, sizeof(COAP) - 1, COAP) == 0) + { + prefix_len = sizeof(COAP) - 1; + m_devAddr.adapter = OC_ADAPTER_IP; + usingIpAddr = true; } else if (host.compare(0, sizeof(COAP_TCP) - 1, COAP_TCP) == 0) { prefix_len = sizeof(COAP_TCP) - 1; + m_devAddr.adapter = OC_ADAPTER_TCP; + usingIpAddr = true; } else if (host.compare(0, sizeof(COAPS_TCP) - 1, COAPS_TCP) == 0) { + if (!OC_SECURE) + { + throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), + m_interfaces.empty(), m_clientWrapper.expired(), false, false); + } prefix_len = sizeof(COAPS_TCP) - 1; m_devAddr.flags = static_cast(m_devAddr.flags | OC_SECURE); + m_devAddr.adapter = OC_ADAPTER_TCP; + usingIpAddr = true; } else if (host.compare(0, sizeof(COAP_GATT) - 1, COAP_GATT) == 0) { prefix_len = sizeof(COAP_GATT) - 1; + m_devAddr.adapter = OC_ADAPTER_GATT_BTLE; } else if (host.compare(0, sizeof(COAP_RFCOMM) - 1, COAP_RFCOMM) == 0) { prefix_len = sizeof(COAP_RFCOMM) - 1; + m_devAddr.adapter = OC_ADAPTER_RFCOMM_BTEDR; } else { @@ -160,6 +270,21 @@ void OCResource::setHost(const std::string& host) m_interfaces.empty(), m_clientWrapper.expired(), false, false); } + // set flag + if (usingIpAddr) + { + if (host.find('[') != std::string::npos) + { + // ipv6 + m_devAddr.flags = static_cast(m_devAddr.flags | OC_IP_USE_V6); + } + else + { + // ipv4 + m_devAddr.flags = static_cast(m_devAddr.flags | OC_IP_USE_V4); + } + } + // remove 'coap://' or 'coaps://' or 'coap+tcp://' or 'coap+gatt://' or 'coap+rfcomm://' std::string host_token = host.substr(prefix_len); @@ -200,13 +325,47 @@ void OCResource::setHost(const std::string& host) m_interfaces.empty(), m_clientWrapper.expired(), false, false); } - OCStackResult result = OCDecodeAddressForRFC6874(m_devAddr.addr, - sizeof(m_devAddr.addr), ip6Addr.c_str(), nullptr); + if (std::string::npos != ip6Addr.find("%25")) + { + OCStackResult result = OCDecodeAddressForRFC6874(m_devAddr.addr, + sizeof(m_devAddr.addr), ip6Addr.c_str(), nullptr); - if (OC_STACK_OK != result) + if (OC_STACK_OK != result) + { + throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), + m_interfaces.empty(), m_clientWrapper.expired(), false, false); + } + } + else { - throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), - m_interfaces.empty(), m_clientWrapper.expired(), false, false); + // It means zone-id is missing, check ipv6Addr is link local + CATransportFlags_t scopeLevel; + CAResult_t caResult = CAGetIpv6AddrScope(ip6Addr.c_str(), &scopeLevel); + + if (CA_STATUS_OK != caResult) + { + throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), + m_interfaces.empty(), m_clientWrapper.expired(), false, false); + } + else + { + if (CA_SCOPE_LINK == scopeLevel) + { + { + // Given ip address is link-local scope without zone-id. + throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), + m_interfaces.empty(), m_clientWrapper.expired(), false, false); + } + } + else + { + if (!OICStrcpy(m_devAddr.addr, sizeof(m_devAddr.addr), ip6Addr.c_str())) + { + throw ResourceInitException(m_uri.empty(), m_resourceTypes.empty(), + m_interfaces.empty(), m_clientWrapper.expired(), false, false); + } + } + } } m_devAddr.port = static_cast(port); @@ -293,6 +452,7 @@ void OCResource::setHost(const std::string& host) m_devAddr.port = static_cast(port); } } + return this->host(); } OCStackResult OCResource::get(const QueryParamsMap& queryParametersMap, @@ -570,6 +730,11 @@ std::string OCResource::host() const return ss.str(); } +std::vector OCResource::getAllHosts() const +{ + return m_endpoints; +} + std::string OCResource::uri() const { return m_uri; diff --git a/resource/unittests/OCExceptionTest.cpp b/resource/unittests/OCExceptionTest.cpp index 742adcc..d2e5118 100644 --- a/resource/unittests/OCExceptionTest.cpp +++ b/resource/unittests/OCExceptionTest.cpp @@ -78,7 +78,8 @@ namespace OC OC_STACK_USER_DENIED_REQ, OC_STACK_NOT_ACCEPTABLE, OC_STACK_FORBIDDEN_REQ, - OC_STACK_INTERNAL_SERVER_ERROR + OC_STACK_INTERNAL_SERVER_ERROR, + OC_STACK_BAD_ENDPOINT }; std::string resultMessages[]= @@ -128,7 +129,8 @@ namespace OC OC::Exception::USER_DENIED_REQ, OC::Exception::NOT_ACCEPTABLE, OC::Exception::FORBIDDEN_REQ, - OC::Exception::INTERNAL_SERVER_ERROR + OC::Exception::INTERNAL_SERVER_ERROR, + OC::Exception::BAD_ENDPOINT }; TEST(OCExceptionTest, ReasonCodeMatches) { diff --git a/resource/unittests/OCPlatformTest.cpp b/resource/unittests/OCPlatformTest.cpp index 63ffecc..b71b627 100644 --- a/resource/unittests/OCPlatformTest.cpp +++ b/resource/unittests/OCPlatformTest.cpp @@ -174,6 +174,19 @@ namespace OCPlatformTest return resourceHandle; } + OCResourceHandle RegisterResource(std::string uri, OCTpsSchemeFlags resourceTpsTypes) + { + PlatformConfig cfg + { OC::ServiceType::OutOfProc, OC::ModeType::Server, "0.0.0.0", 0, + OC::QualityOfService::LowQos, &gps }; + OCPlatform::Configure(cfg); + EXPECT_EQ(OC_STACK_OK, OCPlatform::registerResource( + resourceHandle, uri, gResourceTypeName, + gResourceInterface, entityHandler, gResourceProperty, + resourceTpsTypes)); + return resourceHandle; + } + //Configure // Enable it when the stack throw an exception // https://jira.iotivity.org/browse/IOT-428 @@ -403,6 +416,37 @@ namespace OCPlatformTest gResourceInterface, entityHandler, gResourceProperty)); } + TEST(RegisterResourceTest, RegisterWithTpsType) + { + std::string uri = "/a/light7"; + std::string type = "core.light"; + uint8_t gResourceProperty = 0; + EXPECT_EQ(OC_STACK_OK, OCPlatform::registerResource( + resourceHandle, uri, type, + gResourceInterface, entityHandler, gResourceProperty , OC_COAP)); + } + + TEST(RegisterResourceTest, RegisterWithTpsTypeAll) + { + std::string uri = "/a/light8"; + std::string type = "core.light"; + uint8_t gResourceProperty = 0; + EXPECT_EQ(OC_STACK_OK, OCPlatform::registerResource( + resourceHandle, uri, type, + gResourceInterface, entityHandler, gResourceProperty, OC_ALL)); + } +#ifdef TCP_ADAPTER + TEST(RegisterResourceTest, RegisterWithTpsTypeBitComb) + { + std::string uri = "/a/light9"; + std::string type = "core.light"; + uint8_t gResourceProperty = 0; + EXPECT_EQ(OC_STACK_OK, OCPlatform::registerResource( + resourceHandle, uri, type, + gResourceInterface, entityHandler, gResourceProperty, (OCTpsSchemeFlags)(OC_COAP || OC_COAP_TCP))); + } +#endif + //UnregisterTest TEST(UnregisterTest, UnregisterZeroHandleValue) { @@ -803,6 +847,12 @@ namespace OCPlatformTest OC::QualityOfService::NaQos)); } + TEST(GetSupportedTransportsInfoTest, getSupportedTransportsInfoWithValidParm) + { + OCTpsSchemeFlags input = OC_NO_TPS; + EXPECT_EQ(OC_STACK_OK, OCPlatform::getSupportedTransportsInfo(input)); + } + //RegisterDeviceInfo test TEST(RegisterDeviceInfoTest, RegisterDeviceInfoWithValidParameters) { diff --git a/resource/unittests/OCResourceTest.cpp b/resource/unittests/OCResourceTest.cpp index fc4b40b..2139930 100644 --- a/resource/unittests/OCResourceTest.cpp +++ b/resource/unittests/OCResourceTest.cpp @@ -512,6 +512,42 @@ namespace OCResourceTest EXPECT_TRUE(resource->host() == "coap://[ffff::ffff%25eth0]:5000"); } + // EmptyHosts Test + TEST(HostsTest, EmptyHosts) + { + OCResource::Ptr resource = ConstructResourceObject("coap://192.168.1.2:5000", "/resource"); + EXPECT_TRUE(resource != NULL); + EXPECT_TRUE(resource->getAllHosts().empty()); + } + + // SetHost Test + TEST(SetHostTest, SetHost) + { + OCResource::Ptr resource = ConstructResourceObject("coap://192.168.1.2:5000", "/resource"); + EXPECT_TRUE(resource != NULL); + EXPECT_TRUE(resource->host() == "coap://192.168.1.2:5000"); + EXPECT_TRUE(resource->setHost("coap://192.168.1.1:5000") == "coap://192.168.1.1:5000"); + } + + // SetHost Test2 + TEST(SetHostTest, SetHost2) + { + OCResource::Ptr resource = ConstructResourceObject("coap://192.168.1.2:5000", "/resource"); + EXPECT_TRUE(resource != NULL); + EXPECT_TRUE(resource->host() == "coap://192.168.1.2:5000"); + EXPECT_TRUE(resource->setHost("coap://[3731:54:65fe:2::a7]:32787") == + "coap://[3731:54:65fe:2::a7]:32787"); + } + + // SetHost Test3 + TEST(SetHostTest, SetHost3) + { + OCResource::Ptr resource = ConstructResourceObject("coap://[3731:54:65fe:2::a7]:32787", "/resource"); + EXPECT_TRUE(resource != NULL); + EXPECT_TRUE(resource->host() == "coap://[3731:54:65fe:2::a7]:32787"); + EXPECT_TRUE(resource->setHost("coap://192.168.1.2:5000") == "coap://192.168.1.2:5000"); + } + //Uri Test TEST(UriTest, Uri) { @@ -521,11 +557,19 @@ namespace OCResourceTest } //ConnectivityType Test - TEST(ConnectivityTypeTest, ConnectivityType) + TEST(ConnectivityTypeTest, ConnectivityTypeIpv4) { OCResource::Ptr resource = ConstructResourceObject("coap://192.168.1.2:5000", "/resource"); EXPECT_TRUE(resource != NULL); - EXPECT_TRUE(resource->connectivityType() == CT_DEFAULT); + EXPECT_TRUE(resource->connectivityType() == (CT_ADAPTER_IP | CT_IP_USE_V4)); + } + + //ConnectivityType Test + TEST(ConnectivityTypeTest, ConnectivityTypeIpv6) + { + OCResource::Ptr resource = ConstructResourceObject("coap://[fe80::52b7:c3ff:fead:dc0d%25eth0]:5000", "/resource"); + EXPECT_TRUE(resource != NULL); + EXPECT_TRUE(resource->connectivityType() == (CT_ADAPTER_IP | CT_IP_USE_V6)); } //IsObservable Test -- 2.7.4