//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+// Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
+// causes header files to expose definitions
+// corresponding to the POSIX.1-2001 base
+// specification (excluding the XSI extension).
+// For POSIX.1-2001 base specification,
+// Refer http://pubs.opengroup.org/onlinepubs/009695399/
#define _POSIX_C_SOURCE 200112L
+#include "ocresource.h"
#include <string.h>
-#include "ocstack.h"
-#include "ocstackconfig.h"
-#include "ocstackinternal.h"
#include "ocresourcehandler.h"
#include "ocobserve.h"
#include "occollection.h"
-#include "occoap.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
#include "logger.h"
-#include "debug.h"
#include "cJSON.h"
+#include "ocpayload.h"
+
+#include "cacommon.h"
+#include "cainterface.h"
+
/// Module Name
#define TAG PCF("ocresource")
TAG, PCF(#arg " is NULL")); return (retVal); } }
extern OCResource *headResource;
-static cJSON *savedDeviceInfo = NULL;
-
-static const char * VIRTUAL_RSRCS[] = {
- "/oc/core",
- "/oc/core/d",
- "/oc/core/types/d",
- #ifdef WITH_PRESENCE
- "/oc/presence"
- #endif
-};
+static OCPlatformInfo savedPlatformInfo = {};
+static OCDeviceInfo savedDeviceInfo = {};
//-----------------------------------------------------------------------------
// Default resource entity handler function
//-----------------------------------------------------------------------------
OCEntityHandlerResult defaultResourceEHandler(OCEntityHandlerFlag flag,
- OCEntityHandlerRequest * request) {
- TODO ("Implement me!!!!");
+ OCEntityHandlerRequest * request, void* callbackParam)
+{
+ //TODO ("Implement me!!!!");
// TODO: remove silence unused param warnings
(void) flag;
(void) request;
+ (void) callbackParam;
return OC_EH_OK; // Making sure that the Default EH and the Vendor EH have matching signatures
}
-static OCStackResult ValidateUrlQuery (unsigned char *url, unsigned char *query,
- uint8_t *filterOn, char **filterValue)
+/* This method will retrieve the port at which the secure resource is hosted */
+static OCStackResult GetSecurePortInfo(OCDevAddr *endpoint, uint16_t *port)
{
- char *filterParam;
-
- OC_LOG(INFO, TAG, PCF("Entering ValidateUrlQuery"));
- if (!url)
- return OC_STACK_INVALID_URI;
-
- if (strcmp ((char *)url, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0 ||
- strcmp ((char *)url, GetVirtualResourceUri(OC_DEVICE_URI)) == 0) {
- *filterOn = STACK_RES_DISCOVERY_NOFILTER;
- if (query && *query) {
- char* strTokPtr;
- filterParam = strtok_r((char *)query, "=", &strTokPtr);
- *filterValue = strtok_r(NULL, " ", &strTokPtr);
- if (!(*filterValue)) {
- return OC_STACK_INVALID_QUERY;
- } else if (strcmp (filterParam, OC_RSRVD_INTERFACE) == 0) {
- // Resource discovery with interface filter
- *filterOn = STACK_RES_DISCOVERY_IF_FILTER;
- } else if (strcmp (filterParam, OC_RSRVD_RESOURCE_TYPE) == 0) {
- // Resource discovery with resource type filter
- *filterOn = STACK_RES_DISCOVERY_RT_FILTER;
- } else if (strcmp (filterParam, OC_RSRVD_DEVICE_ID) == 0) {
- //Device ID filter
- *filterOn = STACK_DEVICE_DISCOVERY_DI_FILTER;
- } else if (strcmp (filterParam, OC_RSRVD_DEVICE_NAME) == 0) {
- //Device Name filter
- *filterOn = STACK_DEVICE_DISCOVERY_DN_FILTER;
- } else {
- // Other filter types not supported
- return OC_STACK_INVALID_QUERY;
- }
+ uint16_t p = 0;
+
+ if (endpoint->adapter == OC_ADAPTER_IP)
+ {
+ if (endpoint->flags & OC_IP_USE_V6)
+ {
+ p = caglobals.ip.u6s.port;
+ }
+ else if (endpoint->flags & OC_IP_USE_V4)
+ {
+ p = caglobals.ip.u4s.port;
}
}
- #ifdef WITH_PRESENCE
- else if (strcmp((char *)url, GetVirtualResourceUri(OC_PRESENCE)) == 0) {
- //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
- OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request"));
- *filterOn = STACK_RES_DISCOVERY_NOFILTER;
- }
- #endif
- else {
- // Other URIs not yet supported
- return OC_STACK_INVALID_URI;
- }
- OC_LOG(INFO, TAG, PCF("Exiting ValidateUrlQuery"));
+
+ *port = p;
return OC_STACK_OK;
}
-OCStackResult BuildVirtualResourceResponse(OCResource *resourcePtr, uint8_t filterOn,
- char *filterValue, char * out, uint16_t *remaining)
+/*
+ * Function will extract 0, 1 or 2 filters from query.
+ * More than 2 filters or unsupported filters will result in error.
+ * If both filters are of the same supported type, the 2nd one will be picked.
+ * Resource and device filters in the SAME query are NOT validated
+ * and resources will likely not clear filters.
+ */
+static OCStackResult ExtractFiltersFromQuery(char *query, char **filterOne, char **filterTwo)
{
- OCResourceType *resourceTypePtr;
- OCResourceInterface *interfacePtr;
- cJSON *resObj, *propObj, *rtArray;
- char *jsonStr;
- uint8_t encodeRes = 0;
- OCStackResult ret = OC_STACK_OK;
- uint16_t jsonLen;
- OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponse"));
- resObj = cJSON_CreateObject();
+ char *key = NULL;
+ char *value = NULL;
+ char *restOfQuery = NULL;
+ int numKeyValuePairsParsed = 0;
+
+ *filterOne = NULL;
+ *filterTwo = NULL;
+
+ OC_LOG_V(INFO, TAG, "Extracting params from %s", query);
- if (resourcePtr)
+ char *keyValuePair = strtok_r (query, OC_QUERY_SEPARATOR, &restOfQuery);
+
+ while(keyValuePair)
{
- encodeRes = 0;
- if (filterOn == STACK_RES_DISCOVERY_RT_FILTER) {
- resourceTypePtr = resourcePtr->rsrcType;
- while (resourceTypePtr) {
- if (strcmp (resourceTypePtr->resourcetypename, filterValue) == 0) {
- encodeRes = 1;
- break;
- }
- resourceTypePtr = resourceTypePtr->next;
- }
- } else if (filterOn == STACK_RES_DISCOVERY_IF_FILTER) {
- interfacePtr = resourcePtr->rsrcInterface;
- while (interfacePtr) {
- if (strcmp (interfacePtr->name, filterValue) == 0) {
- encodeRes = 1;
- break;
- }
- interfacePtr = interfacePtr->next;
- }
- } else if (filterOn == STACK_RES_DISCOVERY_NOFILTER) {
- encodeRes = 1;
- } else {
- //TODO: Unsupported query filter
+ if (numKeyValuePairsParsed >= 2)
+ {
+ OC_LOG(ERROR, TAG, PCF("More than 2 queries params in URI."));
return OC_STACK_INVALID_QUERY;
}
- if (encodeRes) {
- // Add URIs
- cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resourcePtr->uri));
-
- cJSON_AddItemToObject (resObj, "prop", propObj = cJSON_CreateObject());
- // Add resource types
- cJSON_AddItemToObject (propObj, OC_RSRVD_RESOURCE_TYPE, rtArray = cJSON_CreateArray());
- resourceTypePtr = resourcePtr->rsrcType;
- while (resourceTypePtr) {
- cJSON_AddItemToArray (rtArray,
- cJSON_CreateString(resourceTypePtr->resourcetypename));
- resourceTypePtr = resourceTypePtr->next;
- }
- // Add interface types
- cJSON_AddItemToObject (propObj, OC_RSRVD_INTERFACE, rtArray = cJSON_CreateArray());
- interfacePtr = resourcePtr->rsrcInterface;
- while (interfacePtr) {
- cJSON_AddItemToArray (rtArray, cJSON_CreateString(interfacePtr->name));
- interfacePtr = interfacePtr->next;
- }
- // If resource is observable, set observability flag.
- // Resources that are not observable will not have the flag.
- if (resourcePtr->resourceProperties & OC_OBSERVABLE) {
- cJSON_AddItemToObject (propObj, OC_RSRVD_OBSERVABLE,
- cJSON_CreateNumber(OC_RESOURCE_OBSERVABLE));
- }
- // Set secure flag for secure resources
- if (resourcePtr->resourceProperties & OC_SECURE) {
- uint16_t port;
- cJSON_AddNumberToObject (propObj, OC_RSRVD_SECURE, OC_RESOURCE_SECURE);
- //Set the IP port also as secure resources are hosted on a different port
- if (OCGetResourceEndPointInfo (resourcePtr, &port) == OC_STACK_OK) {
- cJSON_AddNumberToObject (propObj, OC_RSRVD_HOSTING_PORT, port);
- }
- }
+ key = strtok_r(keyValuePair, OC_KEY_VALUE_DELIMITER, &value);
+ if (!key || !value)
+ {
+ return OC_STACK_INVALID_QUERY;
+ }
+ else if (strcmp (key, OC_RSRVD_INTERFACE) == 0)
+ {
+ *filterOne = value; // if
+ }
+ else if (strcmp (key, OC_RSRVD_RESOURCE_TYPE) == 0)
+ {
+ *filterTwo = value; // rt
+ }
+ else
+ {
+ OC_LOG_V(ERROR, TAG, "Unsupported query key: %s", key);
+ return OC_STACK_INVALID_QUERY;
}
+ ++numKeyValuePairsParsed;
+
+ keyValuePair = strtok_r(NULL, OC_QUERY_SEPARATOR, &restOfQuery);
}
- jsonStr = cJSON_PrintUnformatted (resObj);
- jsonLen = strlen(jsonStr);
- if (jsonLen < *remaining)
+ OC_LOG_V(INFO, TAG, "Extracted params %s and %s.", *filterOne, *filterTwo);
+ return OC_STACK_OK;
+}
+
+static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
+{
+ if (strcmp(uriInRequest, OC_RSRVD_WELL_KNOWN_URI) == 0)
{
- strcpy(out, jsonStr);
- *remaining = *remaining - jsonLen;
+ return OC_WELL_KNOWN_URI;
}
- else
+ else if (strcmp(uriInRequest, OC_RSRVD_DEVICE_URI) == 0)
+ {
+ return OC_DEVICE_URI;
+ }
+ else if (strcmp(uriInRequest, OC_RSRVD_PLATFORM_URI) == 0)
+ {
+ return OC_PLATFORM_URI;
+ }
+ else if (strcmp(uriInRequest, OC_RSRVD_RESOURCE_TYPES_URI) == 0)
{
- ret = OC_STACK_ERROR;
+ return OC_RESOURCE_TYPES_URI;
}
- cJSON_Delete (resObj);
- free (jsonStr);
+#ifdef WITH_PRESENCE
+ else if (strcmp(uriInRequest, OC_RSRVD_PRESENCE_URI) == 0)
+ {
+ return OC_PRESENCE;
+ }
+#endif //WITH_PRESENCE
+ return OC_UNKNOWN_URI;
+}
- OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponse"));
- return ret;
+static OCStackResult getQueryParamsForFiltering (OCVirtualResources uri, char *query,
+ char **filterOne, char **filterTwo)
+{
+ if(!filterOne || !filterTwo)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
+ *filterOne = NULL;
+ *filterTwo = NULL;
+
+ #ifdef WITH_PRESENCE
+ if (uri == OC_PRESENCE)
+ {
+ //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
+ OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request for virtual resource."));
+ return OC_STACK_OK;
+ }
+ #endif
+
+ OCStackResult result = OC_STACK_OK;
+
+ if (query && *query)
+ {
+ result = ExtractFiltersFromQuery(query, filterOne, filterTwo);
+ }
+
+ return result;
}
-OCStackResult BuildVirtualResourceResponseForDevice(uint8_t filterOn, char *filterValue,
- char *out, uint16_t *remaining)
+OCStackResult BuildResponseRepresentation(const OCResource *resourcePtr,
+ OCRepPayload** payload)
{
- OCStackResult ret = OC_STACK_ERROR;
+ OCRepPayload *tempPayload = OCRepPayloadCreate();
- if (savedDeviceInfo != NULL)
+ if (!resourcePtr)
{
- char *jsonStr = NULL;
- uint16_t jsonLen = 0;
- cJSON *repObj = cJSON_GetObjectItem(savedDeviceInfo, "rep");
+ OCRepPayloadDestroy(tempPayload);
+ return OC_STACK_INVALID_PARAM;
+ }
- OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponseForDevice"));
+ if(!tempPayload)
+ {
+ return OC_STACK_NO_MEMORY;
+ }
- if (filterOn == STACK_DEVICE_DISCOVERY_DI_FILTER)
- {
- if((cJSON_GetObjectItem(repObj,"di") != NULL) &&
- strcmp(cJSON_GetObjectItem(repObj,"di")->valuestring, filterValue) == 0)
- {
- ret = OC_STACK_OK;
- }
- }
- else if (filterOn == STACK_DEVICE_DISCOVERY_DN_FILTER)
- {
- if((cJSON_GetObjectItem(repObj,"dn") != NULL) &&
- strcmp(cJSON_GetObjectItem(repObj,"dn")->valuestring, filterValue) == 0)
- {
- ret = OC_STACK_OK;
- }
- }
- else if (filterOn == STACK_RES_DISCOVERY_NOFILTER)
- {
- ret = OC_STACK_OK;
- }
- else
- {
- ret = OC_STACK_INVALID_QUERY;
- }
+ OCRepPayloadSetUri(tempPayload, resourcePtr->uri);
- if (ret == OC_STACK_OK)
- {
- jsonStr = cJSON_PrintUnformatted (savedDeviceInfo);
+ OCResourceType *resType = resourcePtr->rsrcType;
+ while(resType)
+ {
+ OCRepPayloadAddResourceType(tempPayload, resType->resourcetypename);
+ resType = resType->next;
+ }
- if(jsonStr)
- {
- jsonLen = strlen(jsonStr);
+ OCResourceInterface *resInterface = resourcePtr->rsrcInterface;
+ while(resInterface)
+ {
+ OCRepPayloadAddInterface(tempPayload, resInterface->name);
+ resInterface = resInterface->next;
+ }
- if (jsonLen < *remaining)
- {
- strncpy(out, jsonStr, (jsonLen + 1));
- *remaining = *remaining - jsonLen;
- ret = OC_STACK_OK;
- }
- else
- {
- ret = OC_STACK_ERROR;
- }
+ OCAttribute *resAttrib = resourcePtr->rsrcAttributes;
+ while(resAttrib)
+ {
+ OCRepPayloadSetPropString(tempPayload, resAttrib->attrName,
+ resAttrib->attrValue);
+ resAttrib = resAttrib->next;
+ }
- free(jsonStr);
- }
- else
- {
- ret = OC_STACK_ERROR;
- }
- }
- else
- {
- ret = OC_STACK_INVALID_DEVICE_INFO;
- }
+ if(!*payload)
+ {
+ *payload = tempPayload;
}
else
{
- //error so that stack won't respond with empty payload
- ret = OC_STACK_INVALID_DEVICE_INFO;
+ OCRepPayloadAppend(*payload, tempPayload);
}
- OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponseForDevice"));
- return ret;
+ return OC_STACK_OK;
}
-TODO ("Does it make sense to make this method as inline")
-const char * GetVirtualResourceUri( OCVirtualResources resource)
+OCStackResult BuildVirtualResourceResponse(const OCResource *resourcePtr,
+ OCDiscoveryPayload *payload, OCDevAddr *devAddr)
{
- if (resource < OC_MAX_VIRTUAL_RESOURCES)
+ if (!resourcePtr || !payload)
{
- return VIRTUAL_RSRCS[resource];
+ return OC_STACK_INVALID_PARAM;
+ }
+ uint16_t port = 0;
+ if (resourcePtr->resourceProperties & OC_SECURE)
+ {
+ if (GetSecurePortInfo(devAddr, &port) != OC_STACK_OK)
+ {
+ port = 0;
+ }
}
- return NULL;
+ OCDiscoveryPayloadAddResource(payload, resourcePtr, port);
+ return OC_STACK_OK;
}
-uint8_t IsVirtualResource(const char* resourceUri)
+
+uint8_t IsCollectionResource (OCResource *resource)
{
- for (int i = 0; i < OC_MAX_VIRTUAL_RESOURCES; i++)
+ if(!resource)
{
- if (strcmp(resourceUri, GetVirtualResourceUri((OCVirtualResources)i)) == 0)
- {
- return 1;
- }
+ return 0;
}
- return 0;
-}
-uint8_t IsCollectionResource (OCResource *resource)
-{
for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
{
if (resource->rsrcResources[i])
OCResource *FindResourceByUri(const char* resourceUri)
{
+ if(!resourceUri)
+ {
+ return NULL;
+ }
+
OCResource * pointer = headResource;
- while (pointer) {
- if (strcmp(resourceUri, pointer->uri) == 0) {
+ while (pointer)
+ {
+ if (strcmp(resourceUri, pointer->uri) == 0)
+ {
return pointer;
}
pointer = pointer->next;
}
- OC_LOG(INFO, TAG, PCF("Resource not found"));
+ OC_LOG_V(INFO, TAG, "Resource %s not found", resourceUri);
return NULL;
}
-OCStackResult DetermineResourceHandling (OCServerRequest *request,
+OCStackResult DetermineResourceHandling (const OCServerRequest *request,
ResourceHandling *handling,
OCResource **resource)
{
+ if(!request || !handling || !resource)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
- OC_LOG(INFO, TAG, PCF("Entering DetermineResourceHandling"));
+ OC_LOG_V(INFO, TAG, "DetermineResourceHandling for %s", request->resourceUrl);
// Check if virtual resource
- if (IsVirtualResource((const char*)request->resourceUrl))
+ if (GetTypeOfVirtualURI(request->resourceUrl) != OC_UNKNOWN_URI)
{
+ OC_LOG_V (INFO, TAG, "%s is virtual", request->resourceUrl);
*handling = OC_RESOURCE_VIRTUAL;
*resource = headResource;
return OC_STACK_OK;
}
- if (NULL == request->resourceUrl || (strlen((const char*)(request->resourceUrl)) == 0))
+ if (strlen((const char*)(request->resourceUrl)) == 0)
{
// Resource URL not specified
*handling = OC_RESOURCE_NOT_SPECIFIED;
- return OC_STACK_OK;
+ return OC_STACK_NO_RESOURCE;
}
else
{
return OC_STACK_NO_RESOURCE;
}
- // secure resource will entertain only authorized requests
- if ((resourcePtr->resourceProperties & OC_SECURE) && (request->secured == 0))
- {
- OC_LOG(INFO, TAG, PCF("Un-authorized request. Ignore it!"));
- return OC_STACK_RESOURCE_ERROR;
- }
-
if (IsCollectionResource (resourcePtr))
{
// Collection resource
{
*handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
return OC_STACK_OK;
- } else {
+ }
+ else
+ {
*handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
return OC_STACK_OK;
}
- } else {
+ }
+ else
+ {
// Resource not a collection
if (resourcePtr->entityHandler != defaultResourceEHandler)
{
*handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
return OC_STACK_OK;
- } else {
+ }
+ else
+ {
*handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
return OC_STACK_OK;
}
case OC_EH_RESOURCE_DELETED:
result = OC_STACK_RESOURCE_DELETED;
break;
+ case OC_EH_RESOURCE_NOT_FOUND:
+ result = OC_STACK_NO_RESOURCE;
+ break;
default:
result = OC_STACK_ERROR;
}
return result;
}
-static OCStackResult
-HandleVirtualResource (OCServerRequest *request, OCResource* resource)
+static bool resourceMatchesRTFilter(OCResource *resource, char *resourceTypeFilter)
{
- OCStackResult result = OC_STACK_ERROR;
- char *filterValue = NULL;
- uint8_t filterOn = 0;
- uint16_t remaining = 0;
- unsigned char * ptr = NULL;
- uint8_t firstLoopDone = 0;
- unsigned char discoveryResBuf[MAX_RESPONSE_LENGTH] = {0};
+ if (!resource)
+ {
+ return false;
+ }
- OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
+ // Null or empty is analogous to no filter.
+ if (resourceTypeFilter == NULL || *resourceTypeFilter == 0)
+ {
+ return true;
+ }
- result = ValidateUrlQuery (request->resourceUrl,
- request->query, &filterOn,
- &filterValue);
+ OCResourceType *resourceTypePtr = resource->rsrcType;
- if (result == OC_STACK_OK)
+ while (resourceTypePtr)
{
- if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0)
+ if (strcmp (resourceTypePtr->resourcetypename, resourceTypeFilter) == 0)
{
- ptr = discoveryResBuf;
- remaining = MAX_RESPONSE_LENGTH;
+ return true;
+ }
+ resourceTypePtr = resourceTypePtr->next;
+ }
- while(resource)
- {
- if((resource->resourceProperties & OC_ACTIVE)
- && (resource->resourceProperties & OC_DISCOVERABLE))
- {
- // if there is data on the buffer, we have already added a response,
- // so we need to add a comma before we do anything
- if(firstLoopDone
- && remaining >= (sizeof(OC_JSON_SEPARATOR)+1))
- {
- *ptr = OC_JSON_SEPARATOR;
- ptr++;
- remaining--;
- }
- firstLoopDone = 1;
- result = BuildVirtualResourceResponse(resource, filterOn, filterValue,
- (char*)ptr, &remaining);
+ OC_LOG_V(INFO, TAG, PCF("%s does not contain rt=%s."), resource->uri, resourceTypeFilter);
+ return false;
+}
- if (result != OC_STACK_OK)
- {
- // if this failed, we need to remove the comma added above.
- if(!firstLoopDone)
- {
- ptr--;
- *ptr = '\0';
- remaining++;
- }
- break;
- }
- ptr += strlen((char *)ptr);
- *(ptr + 1) = '\0';
- }
- resource = resource->next;
- }
+static bool resourceMatchesIFFilter(OCResource *resource, char *interfaceFilter)
+{
+ if (!resource)
+ {
+ return false;
+ }
- if(strlen((const char *)discoveryResBuf) > 0)
- {
- OCEntityHandlerResponse response = {0};
+ // Null or empty is analogous to no filter.
+ if (interfaceFilter == NULL || *interfaceFilter == 0)
+ {
+ return true;
+ }
- response.ehResult = OC_EH_OK;
- response.payload = discoveryResBuf;
- response.payloadSize = strlen((const char *)discoveryResBuf) + 1;
- response.persistentBufferFlag = 0;
- response.requestHandle = (OCRequestHandle) request;
- response.resourceHandle = (OCResourceHandle) resource;
+ OCResourceInterface *interfacePtr = resource->rsrcInterface;
- result = OCDoResponse(&response);
- }
+ while (interfacePtr)
+ {
+ if (strcmp (interfacePtr->name, interfaceFilter) == 0)
+ {
+ return true;
}
- else if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_DEVICE_URI)) == 0)
+ interfacePtr = interfacePtr->next;
+ }
+
+ OC_LOG_V(INFO, TAG, PCF("%s does not contain if=%s."), resource->uri, interfaceFilter);
+ return false;
+}
+
+/*
+ * If the filters are null, they will be assumed to NOT be present
+ * and the resource will not be matched against them.
+ * Function will return true if all non null AND non empty filters passed in find a match.
+ */
+static bool includeThisResourceInResponse(OCResource *resource,
+ char *interfaceFilter,
+ char *resourceTypeFilter)
+{
+ if (!resource)
+ {
+ OC_LOG(ERROR, TAG, PCF("Invalid resource"));
+ return false;
+ }
+
+ if ( resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
+ {
+ /*
+ * At least one valid filter should be available to
+ * include the resource in discovery response
+ */
+ if (!((interfaceFilter && *interfaceFilter ) ||
+ (resourceTypeFilter && *resourceTypeFilter)))
{
- remaining = MAX_RESPONSE_LENGTH;
- ptr = discoveryResBuf;
+ OC_LOG_V(INFO, TAG, PCF("%s no query string for EXPLICIT_DISCOVERABLE \
+ resource"), resource->uri);
+ return false;
+ }
+ }
+ else if ( !(resource->resourceProperties & OC_ACTIVE) ||
+ !(resource->resourceProperties & OC_DISCOVERABLE))
+ {
+ OC_LOG_V(INFO, TAG, PCF("%s not ACTIVE or DISCOVERABLE"), resource->uri);
+ return false;
+ }
+
+ return resourceMatchesIFFilter(resource, interfaceFilter) &&
+ resourceMatchesRTFilter(resource, resourceTypeFilter);
+
+}
+
+OCStackResult SendNonPersistantDiscoveryResponse(OCServerRequest *request, OCResource *resource,
+ OCPayload *discoveryPayload, OCEntityHandlerResult ehResult)
+{
+ OCEntityHandlerResponse response = {};
+
+ response.ehResult = ehResult;
+ response.payload = discoveryPayload;
+ response.persistentBufferFlag = 0;
+ response.requestHandle = (OCRequestHandle) request;
+ response.resourceHandle = (OCResourceHandle) resource;
+
+ return OCDoResponse(&response);
+}
+
+static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource* resource)
+{
+ if (!request || !resource)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
- result = BuildVirtualResourceResponseForDevice(filterOn, filterValue,
- (char*)ptr, &remaining);
+ OCStackResult discoveryResult = OC_STACK_ERROR;
- if(result == OC_STACK_OK)
+ bool bMulticast = false; // Was the discovery request a multicast request?
+ OCPayload* payload = NULL;
+
+ OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
+
+ OCVirtualResources virtualUriInRequest = GetTypeOfVirtualURI (request->resourceUrl);
+
+ // Step 1: Generate the response to discovery request
+ if (virtualUriInRequest == OC_WELL_KNOWN_URI)
+ {
+ char *filterOne = NULL;
+ char *filterTwo = NULL;
+
+ discoveryResult = getQueryParamsForFiltering (virtualUriInRequest, request->query,
+ &filterOne, &filterTwo);
+
+ if (discoveryResult == OC_STACK_OK)
+ {
+ payload = (OCPayload*)OCDiscoveryPayloadCreate();
+
+ if(payload)
{
- ptr += strlen((char*)ptr);
+ for(;resource && discoveryResult == OC_STACK_OK; resource = resource->next)
+ {
+ if(includeThisResourceInResponse(resource, filterOne, filterTwo))
+ {
+ discoveryResult = BuildVirtualResourceResponse(resource,
+ (OCDiscoveryPayload*)payload,
+ &request->devAddr);
+ }
+ }
+ // Set discoveryResult appropriately if no 'valid' resources are available.
+ if (((OCDiscoveryPayload*)payload)->resources == NULL)
+ {
+ discoveryResult = OC_STACK_NO_RESOURCE;
+ }
}
-
- if(remaining < MAX_RESPONSE_LENGTH)
+ else
{
- OCEntityHandlerResponse response = {0};
+ discoveryResult = OC_STACK_NO_MEMORY;
+ }
+ }
+ else
+ {
+ OC_LOG_V(ERROR, TAG, "Error (%d) parsing query.", discoveryResult);
+ }
+ }
+ else if (virtualUriInRequest == OC_DEVICE_URI)
+ {
+ payload = (OCPayload*)OCDevicePayloadCreate(OC_RSRVD_DEVICE_URI,
+ OCGetServerInstanceID(), savedDeviceInfo.deviceName,
+ OC_SPEC_VERSION, OC_DATA_MODEL_VERSION);
+ if (!payload)
+ {
+ discoveryResult = OC_STACK_NO_MEMORY;
+ }
+ else
+ {
+ discoveryResult = OC_STACK_OK;
+ }
+ }
+ else if (virtualUriInRequest == OC_PLATFORM_URI)
+ {
+ payload = (OCPayload*)OCPlatformPayloadCreate(
+ OC_RSRVD_PLATFORM_URI,
+ &savedPlatformInfo);
+ if (!payload)
+ {
+ discoveryResult = OC_STACK_NO_MEMORY;
+ }
+ else
+ {
+ discoveryResult = OC_STACK_OK;
+ }
+ }
- response.ehResult = OC_EH_OK;
- response.payload = discoveryResBuf;
- response.payloadSize = strlen((const char *)discoveryResBuf) + 1;
- response.persistentBufferFlag = 0;
- response.requestHandle = (OCRequestHandle) request;
- response.resourceHandle = (OCResourceHandle) resource;
+ /**
+ * Step 2: Send the discovery response
+ *
+ * Iotivity should respond to discovery requests in below manner:
+ * 1)If query filter matching fails and discovery request is multicast,
+ * it should NOT send any response.
+ * 2)If query filter matching fails and discovery request is unicast,
+ * it should send an error(RESOURCE_NOT_FOUND - 404) response.
+ * 3)If Server does not have any 'DISCOVERABLE' resources and discovery
+ * request is multicast, it should NOT send any response.
+ * 4)If Server does not have any 'DISCOVERABLE' resources and discovery
+ * request is unicast, it should send an error(RESOURCE_NOT_FOUND - 404) response.
+ */
- result = OCDoResponse(&response);
- }
+ #ifdef WITH_PRESENCE
+ if ((virtualUriInRequest == OC_PRESENCE) &&
+ (resource->resourceProperties & OC_ACTIVE))
+ {
+ // Presence uses observer notification api to respond via SendPresenceNotification.
+ SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
+ }
+ else
+ #endif
+ {
+ if(discoveryResult == OC_STACK_OK)
+ {
+ SendNonPersistantDiscoveryResponse(request, resource, payload, OC_EH_OK);
+ }
+ else if(bMulticast == false)
+ {
+ OC_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);
}
- #ifdef WITH_PRESENCE
else
{
- if(resource->resourceProperties & OC_ACTIVE){
- SendPresenceNotification(NULL);
- }
+ // Ignoring the discovery request as per RFC 7252, Section #8.2
+ OC_LOG_V(INFO, TAG, "Silently ignoring the request since device does not have \
+ any useful data to send");
}
- #endif
}
- result = OC_STACK_VIRTUAL_DO_NOT_HANDLE;
- return result;
+
+ OCPayloadDestroy(payload);
+
+ return OC_STACK_OK;
}
static OCStackResult
HandleDefaultDeviceEntityHandler (OCServerRequest *request)
{
+ if(!request)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
OCStackResult result = OC_STACK_OK;
OCEntityHandlerResult ehResult = OC_EH_ERROR;
- OCEntityHandlerRequest ehRequest = {0};
+ OCEntityHandlerRequest ehRequest = {};
OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithDefaultDeviceEntityHandler"));
- result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
- request->method, (OCResourceHandle) NULL, request->query,
- request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
- request->rcvdVendorSpecificHeaderOptions, (OCObserveAction)request->observationOption, (OCObservationId)0);
+ result = FormOCEntityHandlerRequest(&ehRequest,
+ (OCRequestHandle) request,
+ request->method,
+ &request->devAddr,
+ (OCResourceHandle) NULL, request->query,
+ request->payload,
+ request->payloadSize,
+ request->numRcvdVendorSpecificHeaderOptions,
+ request->rcvdVendorSpecificHeaderOptions,
+ (OCObserveAction)request->observationOption,
+ (OCObservationId)0);
VERIFY_SUCCESS(result, OC_STACK_OK);
// At this point we know for sure that defaultDeviceHandler exists
ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
- (char*) request->resourceUrl);
+ (char*) request->resourceUrl, defaultDeviceHandlerCallbackParameter);
if(ehResult == OC_EH_SLOW)
{
OC_LOG(INFO, TAG, PCF("This is a slow resource"));
OCResource *resource,
uint8_t collectionResource)
{
+ if(!request || ! resource)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+
OCStackResult result = OC_STACK_ERROR;
OCEntityHandlerResult ehResult = OC_EH_ERROR;
OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
ResourceObserver *resObs = NULL;
- OCEntityHandlerRequest ehRequest = {0};
+ OCEntityHandlerRequest ehRequest = {};
OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithEntityHandler"));
- result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
- request->method, (OCResourceHandle) resource, request->query,
- request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
- request->rcvdVendorSpecificHeaderOptions,
- (OCObserveAction)request->observationOption, 0);
+
+ result = FormOCEntityHandlerRequest(&ehRequest,
+ (OCRequestHandle)request,
+ request->method,
+ &request->devAddr,
+ (OCResourceHandle)resource,
+ request->query,
+ request->payload,
+ request->payloadSize,
+ request->numRcvdVendorSpecificHeaderOptions,
+ request->rcvdVendorSpecificHeaderOptions,
+ (OCObserveAction)request->observationOption,
+ 0);
VERIFY_SUCCESS(result, OC_STACK_OK);
if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
OC_LOG(INFO, TAG, PCF("No observation requested"));
ehFlag = OC_REQUEST_FLAG;
}
- else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER &&
- !collectionResource)
+ else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER && !collectionResource)
{
- OC_LOG(INFO, TAG, PCF("Registering observation requested"));
+ OC_LOG(INFO, TAG, PCF("Observation registration requested"));
+
result = GenerateObserverId(&ehRequest.obsInfo.obsId);
VERIFY_SUCCESS(result, OC_STACK_OK);
result = AddObserver ((const char*)(request->resourceUrl),
(const char *)(request->query),
- ehRequest.obsInfo.obsId, &request->requestToken,
- &request->requesterAddr, resource, request->qos);
+ ehRequest.obsInfo.obsId, request->requestToken, request->tokenLength,
+ resource, request->qos,
+ &request->devAddr);
+
if(result == OC_STACK_OK)
{
- OC_LOG(DEBUG, TAG, PCF("Added observer successfully"));
+ OC_LOG(INFO, TAG, PCF("Added observer successfully"));
request->observeResult = OC_STACK_OK;
ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
}
else
{
result = OC_STACK_OK;
+
+ // 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;
- OC_LOG(DEBUG, TAG, PCF("Observer Addition failed"));
+ OC_LOG(ERROR, TAG, PCF("Observer Addition failed"));
ehFlag = OC_REQUEST_FLAG;
}
!collectionResource)
{
OC_LOG(INFO, TAG, PCF("Deregistering observation requested"));
- resObs = GetObserverUsingToken (&request->requestToken);
+
+ resObs = GetObserverUsingToken (request->requestToken, request->tokenLength);
+
if (NULL == resObs)
{
// Stack does not contain this observation request
ehRequest.obsInfo.obsId = resObs->observeId;
ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
- result = DeleteObserverUsingToken (&request->requestToken);
+ result = DeleteObserverUsingToken (request->requestToken, request->tokenLength);
+
if(result == OC_STACK_OK)
{
- OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
+ OC_LOG(INFO, TAG, PCF("Removed observer successfully"));
request->observeResult = OC_STACK_OK;
}
else
{
result = OC_STACK_OK;
request->observeResult = OC_STACK_ERROR;
- OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
+ OC_LOG(ERROR, TAG, PCF("Observer Removal failed"));
}
}
else
goto exit;
}
- ehResult = resource->entityHandler(ehFlag, &ehRequest);
+ ehResult = resource->entityHandler(ehFlag, &ehRequest, resource->entityHandlerCallbackParam);
if(ehResult == OC_EH_SLOW)
{
OC_LOG(INFO, TAG, PCF("This is a slow resource"));
HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
OCResource *resource)
{
- OCStackResult result = OC_STACK_ERROR;
- OCEntityHandlerRequest ehRequest = {0};
+ if(!request || !resource)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
- result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
- request->method, (OCResourceHandle) resource, request->query,
- request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
- request->rcvdVendorSpecificHeaderOptions,
- (OCObserveAction)request->observationOption, (OCObservationId) 0);
+ OCStackResult result = OC_STACK_ERROR;
+ OCEntityHandlerRequest ehRequest = {};
+
+ result = FormOCEntityHandlerRequest(&ehRequest,
+ (OCRequestHandle)request,
+ request->method,
+ &request->devAddr,
+ (OCResourceHandle)resource,
+ request->query,
+ request->payload,
+ request->payloadSize,
+ request->numRcvdVendorSpecificHeaderOptions,
+ request->rcvdVendorSpecificHeaderOptions,
+ (OCObserveAction)request->observationOption,
+ (OCObservationId)0);
if(result != OC_STACK_OK)
{
return result;
return ret;
}
-void DeleteDeviceInfo()
+void DeletePlatformInfo()
{
- if(savedDeviceInfo)
- {
- cJSON_Delete(savedDeviceInfo);
- }
-}
+ OC_LOG(INFO, TAG, PCF("Deleting platform info."));
-OCStackResult SaveDeviceInfo(OCDeviceInfo deviceInfo)
-{
- DeleteDeviceInfo();
+ OICFree(savedPlatformInfo.platformID);
+ savedPlatformInfo.platformID = NULL;
- savedDeviceInfo = cJSON_CreateObject();
- cJSON *repObj = NULL;
+ OICFree(savedPlatformInfo.manufacturerName);
+ savedPlatformInfo.manufacturerName = NULL;
- cJSON_AddItemToObject (savedDeviceInfo, OC_RSRVD_HREF,
- cJSON_CreateString(GetVirtualResourceUri(OC_DEVICE_URI)));
+ OICFree(savedPlatformInfo.manufacturerUrl);
+ savedPlatformInfo.manufacturerUrl = NULL;
- cJSON_AddItemToObject (savedDeviceInfo, "rep", repObj = cJSON_CreateObject());
+ OICFree(savedPlatformInfo.modelNumber);
+ savedPlatformInfo.modelNumber = NULL;
- if (deviceInfo.contentType)
- {
- cJSON_AddItemToObject (repObj, "ct",
- cJSON_CreateString(deviceInfo.contentType));
- }
+ OICFree(savedPlatformInfo.dateOfManufacture);
+ savedPlatformInfo.dateOfManufacture = NULL;
- if (deviceInfo.dateOfManufacture)
- {
- cJSON_AddItemToObject (repObj, "mndt",
- cJSON_CreateString(deviceInfo.dateOfManufacture));
- }
+ OICFree(savedPlatformInfo.platformVersion);
+ savedPlatformInfo.platformVersion = NULL;
- if (deviceInfo.deviceName)
- {
- cJSON_AddItemToObject (repObj, "dn",
- cJSON_CreateString(deviceInfo.deviceName));
- }
+ OICFree(savedPlatformInfo.operatingSystemVersion);
+ savedPlatformInfo.operatingSystemVersion = NULL;
- if (deviceInfo.deviceUUID)
- {
- cJSON_AddItemToObject (repObj, "di",
- cJSON_CreateString(deviceInfo.deviceUUID));
- }
+ OICFree(savedPlatformInfo.hardwareVersion);
+ savedPlatformInfo.hardwareVersion = NULL;
- if (deviceInfo.firmwareVersion)
- {
- cJSON_AddItemToObject (repObj, "mnfv",
- cJSON_CreateString(deviceInfo.firmwareVersion));
- }
+ OICFree(savedPlatformInfo.firmwareVersion);
+ savedPlatformInfo.firmwareVersion = NULL;
+
+ OICFree(savedPlatformInfo.supportUrl);
+ savedPlatformInfo.supportUrl = NULL;
- if (deviceInfo.hostName)
+ OICFree(savedPlatformInfo.systemTime);
+ savedPlatformInfo.systemTime = NULL;
+}
+
+static OCStackResult DeepCopyPlatFormInfo(OCPlatformInfo info)
+{
+ savedPlatformInfo.platformID = OICStrdup(info.platformID);
+ savedPlatformInfo.manufacturerName = OICStrdup(info.manufacturerName);
+ savedPlatformInfo.manufacturerUrl = OICStrdup(info.manufacturerUrl);
+ savedPlatformInfo.modelNumber = OICStrdup(info.modelNumber);
+ savedPlatformInfo.dateOfManufacture = OICStrdup(info.dateOfManufacture);
+ savedPlatformInfo.platformVersion = OICStrdup(info.platformVersion);
+ savedPlatformInfo.operatingSystemVersion = OICStrdup(info.operatingSystemVersion);
+ savedPlatformInfo.hardwareVersion = OICStrdup(info.hardwareVersion);
+ savedPlatformInfo.firmwareVersion = OICStrdup(info.firmwareVersion);
+ savedPlatformInfo.supportUrl = OICStrdup(info.supportUrl);
+ savedPlatformInfo.systemTime = OICStrdup(info.systemTime);
+
+ if ((!savedPlatformInfo.platformID && info.platformID)||
+ (!savedPlatformInfo.manufacturerName && info.manufacturerName)||
+ (!savedPlatformInfo.manufacturerUrl && info.manufacturerUrl)||
+ (!savedPlatformInfo.modelNumber && info.modelNumber)||
+ (!savedPlatformInfo.dateOfManufacture && info.dateOfManufacture)||
+ (!savedPlatformInfo.platformVersion && info.platformVersion)||
+ (!savedPlatformInfo.operatingSystemVersion && info.operatingSystemVersion)||
+ (!savedPlatformInfo.hardwareVersion && info.hardwareVersion)||
+ (!savedPlatformInfo.firmwareVersion && info.firmwareVersion)||
+ (!savedPlatformInfo.supportUrl && info.supportUrl)||
+ (!savedPlatformInfo.systemTime && info.systemTime))
{
- cJSON_AddItemToObject (repObj, "hn", cJSON_CreateString(deviceInfo.hostName));
+ DeletePlatformInfo();
+ return OC_STACK_INVALID_PARAM;
}
- if (deviceInfo.manufacturerName)
- {
- if(strlen(deviceInfo.manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH)
- {
- DeleteDeviceInfo();
- return OC_STACK_INVALID_PARAM;
- }
+ return OC_STACK_OK;
- cJSON_AddItemToObject (repObj, "mnmn",
- cJSON_CreateString(deviceInfo.manufacturerName));
- }
+}
- if (deviceInfo.manufacturerUrl)
- {
- if(strlen(deviceInfo.manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH)
- {
- DeleteDeviceInfo();
- return OC_STACK_INVALID_PARAM;
- }
+OCStackResult SavePlatformInfo(OCPlatformInfo info)
+{
+ DeletePlatformInfo();
- cJSON_AddItemToObject (repObj, "mnml",
- cJSON_CreateString(deviceInfo.manufacturerUrl));
- }
+ OCStackResult res = DeepCopyPlatFormInfo(info);
- if (deviceInfo.modelNumber)
+ if (res != OC_STACK_OK)
{
- cJSON_AddItemToObject (repObj, "mnmo",
- cJSON_CreateString(deviceInfo.modelNumber));
+ OC_LOG_V(ERROR, TAG, PCF("Failed to save platform info. errno(%d)"), res);
}
-
- if (deviceInfo.platformVersion)
+ else
{
- cJSON_AddItemToObject (repObj, "mnpv",
- cJSON_CreateString(deviceInfo.platformVersion));
+ OC_LOG(ERROR, TAG, PCF("Platform info saved."));
}
- if (deviceInfo.supportUrl)
+ return res;
+}
+
+void DeleteDeviceInfo()
+{
+ OC_LOG(INFO, TAG, PCF("Deleting device info."));
+
+ OICFree(savedDeviceInfo.deviceName);
+ savedDeviceInfo.deviceName = NULL;
+}
+
+static OCStackResult DeepCopyDeviceInfo(OCDeviceInfo info)
+{
+ savedDeviceInfo.deviceName = OICStrdup(info.deviceName);
+
+ if(!savedDeviceInfo.deviceName && info.deviceName)
{
- cJSON_AddItemToObject (repObj, "mnsl",
- cJSON_CreateString(deviceInfo.supportUrl));
+ DeleteDeviceInfo();
+ return OC_STACK_NO_MEMORY;
}
- if (deviceInfo.version)
+ return OC_STACK_OK;
+}
+
+OCStackResult SaveDeviceInfo(OCDeviceInfo info)
+{
+ OCStackResult res = OC_STACK_OK;
+
+ DeleteDeviceInfo();
+
+ res = DeepCopyDeviceInfo(info);
+
+ VERIFY_SUCCESS(res, OC_STACK_OK);
+
+ if(OCGetServerInstanceID() == NULL)
{
- cJSON_AddItemToObject (repObj, "icv",
- cJSON_CreateString(deviceInfo.version));
+ OC_LOG(INFO, TAG, PCF("Device ID generation failed"));
+ res = OC_STACK_ERROR;
+ goto exit;
}
+ OC_LOG(INFO, TAG, PCF("Device initialized successfully."));
return OC_STACK_OK;
-}
+ exit:
+ DeleteDeviceInfo();
+ return res;
+
+}