typedef struct OCResourcePayload
{
char* uri;
+ char* rel;
OCStringLL* types;
OCStringLL* interfaces;
uint8_t bitmap;
#ifndef OC_OBSERVE_H
#define OC_OBSERVE_H
+#include "ocserverrequest.h"
+
/** Maximum number of observers to reach */
#define MAX_OBSERVER_FAILED_COMM (2)
CAHeaderOption_t *options,
uint8_t * numOptions);
+/**
+ * Handle registering/deregistering of observers of virtual resources. Currently only the
+ * well-known virtual resource (/oic/res) may be observable.
+ *
+ * @param request a virtual resource server request
+ *
+ * @return ::OC_STACK_OK on success, ::OC_STACK_DUPLICATE_REQUEST when registering a duplicate
+ * observer, some other value upon failure.
+ */
+OCStackResult
+HandleVirtualObserveRequest(OCServerRequest *request);
+
+
#endif //OC_OBSERVE_H
} ResourceHandling;
/**
+ * This function returns the virtual resource of the given URI.
+ * @return the virtual resource or ::OC_UNKNOWN_URI
+ */
+OCVirtualResources GetTypeOfVirtualURI(const char* resourceUri);
+
+/**
* Default entity handler (ie. callback) to be used for resources with
* no entity handler.
*/
OCResourceProperty OCGetResourceProperties(OCResourceHandle handle);
/**
+ * This function sets the properties of the resource specified by handle.
+ *
+ * @param handle Handle of resource.
+ * @param resourceProperties Properties supported by resource.
+ * Example: ::OC_DISCOVERABLE|::OC_OBSERVABLE.
+ *
+ * @return ::OC_STACK_OK on success, some other value upon failure.
+ */
+OCStackResult OCSetResourceProperties(OCResourceHandle handle, uint8_t resourceProperties);
+
+/**
+ * This function removes the properties of the resource specified by handle.
+ *
+ * @param handle Handle of resource.
+ * @param resourceProperties Properties not supported by resource.
+ * Example: ::OC_DISCOVERABLE|::OC_OBSERVABLE.
+ *
+ * @return ::OC_STACK_OK on success, some other value upon failure.
+ */
+OCStackResult OCClearResourceProperties(OCResourceHandle handle, uint8_t resourceProperties);
+
+/**
* This function gets the number of resource types of the resource.
*
* @param handle Handle of resource.
{
OIC_LOG_V(level, PL_TAG, "\tLink#%d", i);
OIC_LOG_V(level, PL_TAG, "\tURI:%s", res->uri);
+ if (res->rel)
+ {
+ OIC_LOG_V(level, PL_TAG, "\tRelation:%s", res->rel);
+ }
OIC_LOG(level, PL_TAG, "\tResource Types:");
OCStringLL* strll = res->types;
while(strll)
{
OCStackResult result = OC_STACK_ERROR;
OCServerRequest * request = NULL;
- OCEntityHandlerRequest ehRequest = {0};
- OCEntityHandlerResult ehResult = OC_EH_ERROR;
result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
0, observer->resource->sequenceNum, qos,
request->observeResult = OC_STACK_OK;
if (result == OC_STACK_OK)
{
- result = FormOCEntityHandlerRequest(
- &ehRequest,
- (OCRequestHandle) request,
- request->method,
- &request->devAddr,
- (OCResourceHandle) observer->resource,
- request->query,
- PAYLOAD_TYPE_REPRESENTATION,
- request->payload,
- request->payloadSize,
- request->numRcvdVendorSpecificHeaderOptions,
- request->rcvdVendorSpecificHeaderOptions,
- OC_OBSERVE_NO_OPTION,
- 0,
- request->coapID);
+ ResourceHandling resHandling = OC_RESOURCE_VIRTUAL;
+ OCResource *resource = NULL;
+ result = DetermineResourceHandling (request, &resHandling, &resource);
if (result == OC_STACK_OK)
{
- ehResult = observer->resource->entityHandler(OC_REQUEST_FLAG, &ehRequest,
- observer->resource->entityHandlerCallbackParam);
- if (ehResult == OC_EH_ERROR)
- {
- FindAndDeleteServerRequest(request);
- }
+ result = ProcessRequest(resHandling, resource, request);
// Reset Observer TTL.
observer->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
}
- OCPayloadDestroy(ehRequest.payload);
}
}
}
return OC_STACK_OK;
}
+
+OCStackResult
+HandleVirtualObserveRequest(OCServerRequest *request)
+{
+ OCStackResult result = OC_STACK_OK;
+ if (request->notificationFlag)
+ {
+ // The request is to send an observe payload, not register/deregister an observer
+ goto exit;
+ }
+ OCVirtualResources virtualUriInRequest;
+ virtualUriInRequest = GetTypeOfVirtualURI(request->resourceUrl);
+ if (virtualUriInRequest != OC_WELL_KNOWN_URI)
+ {
+ // OC_WELL_KNOWN_URI is currently the only virtual resource that may be observed
+ goto exit;
+ }
+ OCResource *resourcePtr;
+ resourcePtr = FindResourceByUri(OC_RSRVD_WELL_KNOWN_URI);
+ if (NULL == resourcePtr)
+ {
+ OIC_LOG(FATAL, TAG, "Well-known URI not found.");
+ result = OC_STACK_ERROR;
+ goto exit;
+ }
+ if (request->observationOption == OC_OBSERVE_REGISTER)
+ {
+ OIC_LOG(INFO, TAG, "Observation registration requested");
+ ResourceObserver *obs = GetObserverUsingToken (request->requestToken,
+ request->tokenLength);
+ if (obs)
+ {
+ OIC_LOG (INFO, TAG, "Observer with this token already present");
+ OIC_LOG (INFO, TAG, "Possibly re-transmitted CON OBS request");
+ OIC_LOG (INFO, TAG, "Not adding observer. Not responding to client");
+ OIC_LOG (INFO, TAG, "The first request for this token is already ACKED.");
+ result = OC_STACK_DUPLICATE_REQUEST;
+ goto exit;
+ }
+ OCObservationId obsId;
+ result = GenerateObserverId(&obsId);
+ if (result == OC_STACK_OK)
+ {
+ result = AddObserver ((const char*)(request->resourceUrl),
+ (const char *)(request->query),
+ obsId, request->requestToken, request->tokenLength,
+ resourcePtr, request->qos, request->acceptFormat,
+ request->acceptVersion, &request->devAddr);
+ }
+ if (result == OC_STACK_OK)
+ {
+ OIC_LOG(INFO, TAG, "Added observer successfully");
+ request->observeResult = OC_STACK_OK;
+ }
+ else if (result == OC_STACK_RESOURCE_ERROR)
+ {
+ OIC_LOG(INFO, TAG, "The Resource is not active, discoverable or observable");
+ request->observeResult = OC_STACK_ERROR;
+ }
+ else
+ {
+ // The error in observeResult for the request will be used when responding to this
+ // request by omitting the observation option/sequence number.
+ request->observeResult = OC_STACK_ERROR;
+ OIC_LOG(ERROR, TAG, "Observer Addition failed");
+ }
+ }
+ else if (request->observationOption == OC_OBSERVE_DEREGISTER)
+ {
+ OIC_LOG(INFO, TAG, "Deregistering observation requested");
+ result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
+ if (result == OC_STACK_OK)
+ {
+ OIC_LOG(INFO, TAG, "Removed observer successfully");
+ request->observeResult = OC_STACK_OK;
+ // There should be no observe option header for de-registration response.
+ // Set as an invalid value here so we can detect it later and remove the field in response.
+ request->observationOption = MAX_SEQUENCE_NUMBER + 1;
+ }
+ else
+ {
+ request->observeResult = OC_STACK_ERROR;
+ OIC_LOG(ERROR, TAG, "Observer Removal failed");
+ }
+ }
+ // Whether the observe request succeeded or failed, the request is processed as normal
+ // and excludes/includes the OBSERVE option depending on request->observeResult
+ result = OC_STACK_OK;
+
+exit:
+ return result;
+}
return NULL;
}
+ // relation is always the default unless the resource is the well known URI
+ if (0 == strcmp(res->uri, OC_RSRVD_WELL_KNOWN_URI))
+ {
+ pl->rel = OICStrdup("self");
+
+ if (!pl->rel)
+ {
+ OCDiscoveryResourceDestroy(pl);
+ return NULL;
+ }
+ }
+
// types
OCResourceType* typePtr = res->rsrcType;
}
OICFree(payload->uri);
+ OICFree(payload->rel);
OCFreeOCStringLL(payload->types);
OCFreeOCStringLL(payload->interfaces);
OCDiscoveryEndpointDestroy(payload->eps);
for (size_t i = 0; i < resourceCount; ++i)
{
CborEncoder linkMap;
+ size_t linkMapLen;
OCResourcePayload *resource = OCDiscoveryPayloadGetResource(payload, i);
VERIFY_PARAM_NON_NULL(TAG, resource, "Failed retrieving resource");
// resource map inside the links array.
- if (resource->eps)
+ linkMapLen = resource->eps ? LINKS_MAP_LEN_WITH_EPS : LINKS_MAP_LEN_WITHOUT_EPS;
+ if (resource->rel)
{
- err |= cbor_encoder_create_map(&linkArray, &linkMap, LINKS_MAP_LEN_WITH_EPS);
- VERIFY_CBOR_SUCCESS(TAG, err, "Failed creating links map");
- }
- else
- {
- err |= cbor_encoder_create_map(&linkArray, &linkMap, LINKS_MAP_LEN_WITHOUT_EPS);
- VERIFY_CBOR_SUCCESS(TAG, err, "Failed creating links map");
+ ++linkMapLen;
}
+ err |= cbor_encoder_create_map(&linkArray, &linkMap, linkMapLen);
+ VERIFY_CBOR_SUCCESS(TAG, err, "Failed creating links map");
// Below are insertions of the resource properties into the map.
// Uri
resource->uri);
VERIFY_CBOR_SUCCESS(TAG, err, "Failed adding uri to links map");
+ // Rel - Not a mandatory field
+ if (resource->rel)
+ {
+ err |= AddTextStringToMap(&linkMap, OC_RSRVD_REL, sizeof(OC_RSRVD_REL) - 1,
+ resource->rel);
+ VERIFY_CBOR_SUCCESS(TAG, err, "Failed adding rel to links map");
+ }
+
// Resource Type
if (resource->types)
{
err = cbor_value_dup_text_string(&curVal, &(resource->uri), &len, NULL);
VERIFY_CBOR_SUCCESS(TAG, err, "to find href value");
+ // Rel - Not a mandatory field
+ err = cbor_value_map_find_value(&resourceMap, OC_RSRVD_REL, &curVal);
+ VERIFY_CBOR_SUCCESS(TAG, err, "to find rel tag");
+ if (cbor_value_is_valid(&curVal))
+ {
+ err = cbor_value_dup_text_string(&curVal, &(resource->rel), &len, NULL);
+ VERIFY_CBOR_SUCCESS(TAG, err, "to find rel value");
+ }
+
// ResourceTypes
err = OCParseStringLL(&resourceMap, OC_RSRVD_RESOURCE_TYPE, &resource->types);
VERIFY_CBOR_SUCCESS(TAG, err, "to find resource type tag/value");
return eCode;
}
-static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
+OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
{
if (strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_URI) == 0)
{
request->payloadSize,
request->numRcvdVendorSpecificHeaderOptions,
request->rcvdVendorSpecificHeaderOptions,
- (OCObserveAction)request->observationOption,
+ (OCObserveAction)(request->notificationFlag ? OC_OBSERVE_NO_OPTION :
+ request->observationOption),
(OCObservationId)0,
request->coapID);
}
return OC_STACK_UNAUTHORIZED_REQ;
}
+ discoveryResult = HandleVirtualObserveRequest(request);
+ if (discoveryResult == OC_STACK_DUPLICATE_REQUEST)
+ {
+ // server requests are usually free'd when the response is sent out
+ // for the request in ocserverrequest.c : HandleSingleResponse()
+ // Since we are making an early return and not responding, the server request
+ // needs to be deleted.
+ FindAndDeleteServerRequest (request);
+ discoveryResult = OC_STACK_OK;
+ goto exit;
+ }
+ else if (discoveryResult != OC_STACK_OK)
+ {
+ goto exit;
+ }
+
// Step 1: Generate the response to discovery request
if (virtualUriInRequest == OC_WELL_KNOWN_URI
#ifdef MQ_BROKER
static OCResourceHandle deviceResource = {0};
static OCResourceHandle introspectionResource = {0};
static OCResourceHandle introspectionPayloadResource = {0};
+static OCResourceHandle wellKnownResource = {0};
#ifdef MQ_BROKER
static OCResourceHandle brokerResource = {0};
#endif
return (OCResourceProperty)-1;
}
+OCStackResult OCSetResourceProperties(OCResourceHandle handle, uint8_t resourceProperties)
+{
+ OCResource *resource = NULL;
+
+ resource = findResource((OCResource *) handle);
+ if (resource == NULL)
+ {
+ OIC_LOG(ERROR, TAG, "Resource not found");
+ return OC_STACK_NO_RESOURCE;
+ }
+ resource->resourceProperties = (OCResourceProperty) (resource->resourceProperties | resourceProperties);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCClearResourceProperties(OCResourceHandle handle, uint8_t resourceProperties)
+{
+ OCResource *resource = NULL;
+
+ resource = findResource((OCResource *) handle);
+ if (resource == NULL)
+ {
+ OIC_LOG(ERROR, TAG, "Resource not found");
+ return OC_STACK_NO_RESOURCE;
+ }
+ resource->resourceProperties = (OCResourceProperty) (resource->resourceProperties & ~resourceProperties);
+ return OC_STACK_OK;
+}
+
OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
uint8_t *numResourceTypes)
{
if(result == OC_STACK_OK)
{
+ result = OCCreateResource(&wellKnownResource,
+ OC_RSRVD_RESOURCE_TYPE_RES,
+ OC_RSRVD_INTERFACE_LL,
+ OC_RSRVD_WELL_KNOWN_URI,
+ NULL,
+ NULL,
+ 0);
+ if(result == OC_STACK_OK)
+ {
+ result = BindResourceInterfaceToResource((OCResource *)wellKnownResource,
+ OC_RSRVD_INTERFACE_DEFAULT);
+ }
+ }
+
+ if(result == OC_STACK_OK)
+ {
CreateResetProfile();
result = OCCreateResource(&deviceResource,
OC_RSRVD_RESOURCE_TYPE_DEVICE,
}
memset(&platformResource, 0, sizeof(platformResource));
memset(&deviceResource, 0, sizeof(deviceResource));
+ memset(&wellKnownResource, 0, sizeof(wellKnownResource));
#ifdef MQ_BROKER
memset(&brokerResource, 0, sizeof(brokerResource));
#endif
EXPECT_EQ(OC_STACK_OK, OCStop());
}
+TEST(StackResource, SetResourceProperties)
+{
+ itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
+ OIC_LOG(INFO, TAG, "Starting SetResourceProperties test");
+ InitStack(OC_SERVER);
+
+ OCResourceHandle handle;
+ EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle,
+ "core.led",
+ "core.rw",
+ "/a/led",
+ 0,
+ NULL,
+ 0));
+
+ EXPECT_EQ(OC_STACK_OK, OCSetResourceProperties(handle, OC_DISCOVERABLE|OC_OBSERVABLE));
+#ifdef MQ_PUBLISHER
+ EXPECT_EQ(OC_ACTIVE|OC_DISCOVERABLE|OC_OBSERVABLE|OC_MQ_PUBLISHER, OCGetResourceProperties(handle));
+#else
+ EXPECT_EQ(OC_ACTIVE|OC_DISCOVERABLE|OC_OBSERVABLE, OCGetResourceProperties(handle));
+#endif
+
+ EXPECT_EQ(OC_STACK_OK, OCDeleteResource(handle));
+
+ EXPECT_EQ(OC_STACK_OK, OCStop());
+}
+
+TEST(StackResource, ClearResourceProperties)
+{
+ itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);
+ OIC_LOG(INFO, TAG, "Starting ClearResourceProperties test");
+ InitStack(OC_SERVER);
+
+ OCResourceHandle handle;
+ EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle,
+ "core.led",
+ "core.rw",
+ "/a/led",
+ 0,
+ NULL,
+ OC_DISCOVERABLE|OC_OBSERVABLE));
+
+ EXPECT_EQ(OC_STACK_OK, OCClearResourceProperties(handle, OC_DISCOVERABLE|OC_OBSERVABLE));
+#ifdef MQ_PUBLISHER
+ EXPECT_EQ(OC_ACTIVE|OC_MQ_PUBLISHER, OCGetResourceProperties(handle));
+#else
+ EXPECT_EQ(OC_ACTIVE, OCGetResourceProperties(handle));
+#endif
+
+ EXPECT_EQ(OC_STACK_OK, OCDeleteResource(handle));
+
+ EXPECT_EQ(OC_STACK_OK, OCStop());
+}
+
TEST(StackResource, StackTestResourceDiscoverOneResourceBad)
{
itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT);