1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
23 #include "ocstackconfig.h"
24 #include "ocstackinternal.h"
25 #include "ocresource.h"
26 #include "ocobserve.h"
27 #include "occollection.h"
33 #define TAG PCF("ocresource")
34 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
35 TAG, PCF(#arg " is NULL")); return (retVal); } }
37 extern OCResource *headResource;
39 static const char * VIRTUAL_RSRCS[] = {
48 //-----------------------------------------------------------------------------
49 // Default resource entity handler function
50 //-----------------------------------------------------------------------------
51 OCEntityHandlerResult defaultResourceEHandler(OCEntityHandlerFlag flag,
52 OCEntityHandlerRequest * request) {
53 TODO ("Implement me!!!!");
54 // TODO: remove silence unused param warnings
57 return OC_EH_OK; // Making sure that the Default EH and the Vendor EH have matching signatures
60 static OCStackResult ValidateUrlQuery (unsigned char *url, unsigned char *query,
61 uint8_t *filterOn, char **filterValue)
65 OC_LOG(INFO, TAG, PCF("Entering ValidateUrlQuery"));
67 return OC_STACK_INVALID_URI;
69 if (strcmp ((char *)url, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0) {
70 *filterOn = STACK_RES_DISCOVERY_NOFILTER;
71 if (query && *query) {
72 filterParam = strtok ((char *)query, "=");
73 *filterValue = strtok (NULL, " ");
74 if (!(*filterValue)) {
75 return OC_STACK_INVALID_QUERY;
76 } else if (strcmp (filterParam, OC_RSRVD_INTERFACE) == 0) {
77 // Resource discovery with interface filter
78 *filterOn = STACK_RES_DISCOVERY_IF_FILTER;
79 } else if (strcmp (filterParam, OC_RSRVD_RESOURCE_TYPE) == 0) {
80 // Resource discovery with resource type filter
81 *filterOn = STACK_RES_DISCOVERY_RT_FILTER;
83 // Other filter types not supported
84 return OC_STACK_INVALID_QUERY;
89 else if (strcmp((char *)url, GetVirtualResourceUri(OC_PRESENCE)) == 0) {
90 //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
91 OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request"));
92 *filterOn = STACK_RES_DISCOVERY_NOFILTER;
96 // Other URIs not yet supported
97 return OC_STACK_INVALID_URI;
99 OC_LOG(INFO, TAG, PCF("Exiting ValidateUrlQuery"));
103 OCStackResult BuildVirtualResourceResponse(OCResource *resourcePtr, uint8_t filterOn,
104 char *filterValue, char * out, uint16_t *remaining)
106 OCResourceType *resourceTypePtr;
107 OCResourceInterface *interfacePtr;
108 cJSON *resObj, *propObj, *rtArray;
110 uint8_t encodeRes = 0;
111 OCStackResult ret = OC_STACK_OK;
114 OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponse"));
115 resObj = cJSON_CreateObject();
120 if (filterOn == STACK_RES_DISCOVERY_RT_FILTER) {
121 resourceTypePtr = resourcePtr->rsrcType;
122 while (resourceTypePtr) {
123 if (strcmp (resourceTypePtr->resourcetypename, filterValue) == 0) {
127 resourceTypePtr = resourceTypePtr->next;
129 } else if (filterOn == STACK_RES_DISCOVERY_IF_FILTER) {
130 interfacePtr = resourcePtr->rsrcInterface;
131 while (interfacePtr) {
132 if (strcmp (interfacePtr->name, filterValue) == 0) {
136 interfacePtr = interfacePtr->next;
138 } else if (filterOn == STACK_RES_DISCOVERY_NOFILTER) {
141 //TODO: Unsupported query filter
142 return OC_STACK_INVALID_QUERY;
147 cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resourcePtr->uri));
149 cJSON_AddItemToObject (resObj, "prop", propObj = cJSON_CreateObject());
150 // Add resource types
151 cJSON_AddItemToObject (propObj, OC_RSRVD_RESOURCE_TYPE, rtArray = cJSON_CreateArray());
152 resourceTypePtr = resourcePtr->rsrcType;
153 while (resourceTypePtr) {
154 cJSON_AddItemToArray (rtArray,
155 cJSON_CreateString(resourceTypePtr->resourcetypename));
156 resourceTypePtr = resourceTypePtr->next;
158 // Add interface types
159 cJSON_AddItemToObject (propObj, OC_RSRVD_INTERFACE, rtArray = cJSON_CreateArray());
160 interfacePtr = resourcePtr->rsrcInterface;
161 while (interfacePtr) {
162 cJSON_AddItemToArray (rtArray, cJSON_CreateString(interfacePtr->name));
163 interfacePtr = interfacePtr->next;
165 // If resource is observable, set observability flag.
166 // Resources that are not observable will not have the flag.
167 if (resourcePtr->resourceProperties & OC_OBSERVABLE) {
168 cJSON_AddItemToObject (propObj, OC_RSRVD_OBSERVABLE,
169 cJSON_CreateNumber(OC_RESOURCE_OBSERVABLE));
173 jsonStr = cJSON_PrintUnformatted (resObj);
174 jsonLen = strlen(jsonStr);
175 if (jsonLen < *remaining)
177 strcpy(out, jsonStr);
178 *remaining = *remaining - jsonLen;
182 ret = OC_STACK_ERROR;
184 cJSON_Delete (resObj);
188 OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponse"));
192 OCEntityHandlerResult
193 BuildObsJSONResponse(OCResource *resource, OCEntityHandlerRequest *ehRequest)
195 OCEntityHandlerResult ret = OC_EH_ERROR;
196 unsigned char* saveJSONPayLoadPtr = ehRequest->resJSONPayload;
198 if (ehRequest->resJSONPayloadLen > OC_JSON_PREFIX_LEN)
200 strcpy((char*)ehRequest->resJSONPayload, OC_JSON_PREFIX);
201 ehRequest->resJSONPayloadLen -= OC_JSON_PREFIX_LEN;
202 ehRequest->resJSONPayload += OC_JSON_PREFIX_LEN;
205 ret = resource->entityHandler(OC_REQUEST_FLAG, ehRequest);
207 ehRequest->resJSONPayloadLen = ehRequest->resJSONPayloadLen -
208 strlen((char*)ehRequest->resJSONPayload);
209 ehRequest->resJSONPayload += strlen((char*)ehRequest->resJSONPayload);
211 if (ehRequest->resJSONPayloadLen > OC_JSON_SUFFIX_LEN)
213 strcpy((char*)ehRequest->resJSONPayload, OC_JSON_SUFFIX);
215 ehRequest->resJSONPayload = saveJSONPayLoadPtr;
220 TODO ("Does it make sense to make this method as inline")
221 const char * GetVirtualResourceUri( OCVirtualResources resource)
223 if (resource < OC_MAX_VIRTUAL_RESOURCES)
225 return VIRTUAL_RSRCS[resource];
231 uint8_t IsVirtualResource(const char* resourceUri)
233 for (int i = 0; i < OC_MAX_VIRTUAL_RESOURCES; i++)
235 if (strcmp(resourceUri, GetVirtualResourceUri((OCVirtualResources)i)) == 0)
243 uint8_t IsCollectionResource (OCResource *resource)
245 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
247 if (resource->rsrcResources[i])
255 OCResource *FindResourceByUri(const char* resourceUri)
257 OCResource * pointer = headResource;
259 if (strcmp(resourceUri, pointer->uri) == 0) {
262 pointer = pointer->next;
264 OC_LOG(INFO, TAG, PCF("Resource not found"));
269 OCStackResult DetermineResourceHandling (OCRequest *request,
270 ResourceHandling *handling,
271 OCResource **resource)
274 OC_LOG(INFO, TAG, PCF("Entering DetermineResourceHandling"));
276 // Check if virtual resource
277 if (IsVirtualResource((const char*)request->resourceUrl))
279 *handling = OC_RESOURCE_VIRTUAL;
280 *resource = headResource;
283 if (NULL == request->resourceUrl || (strlen((const char*)(request->resourceUrl)) == 0))
285 // Resource URL not specified
286 *handling = OC_RESOURCE_NOT_SPECIFIED;
291 OCResource *resourcePtr = NULL;
292 resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
293 *resource = resourcePtr;
296 if(defaultDeviceHandler)
298 *handling = OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER;
302 // Resource does not exist
303 // and default device handler does not exist
304 return OC_STACK_NO_RESOURCE;
307 // secure resource will entertain only authorized requests
308 if ((resourcePtr->resourceProperties & OC_SECURE) && (request->secure == 0))
310 OC_LOG(INFO, TAG, PCF("Un-authorized request. Ignore it!"));
311 return OC_STACK_RESOURCE_ERROR;
314 if (IsCollectionResource (resourcePtr))
316 // Collection resource
317 if (resourcePtr->entityHandler != defaultResourceEHandler)
319 *handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
322 *handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
326 // Resource not a collection
327 if (resourcePtr->entityHandler != defaultResourceEHandler)
329 *handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
332 *handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
339 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
341 OCStackResult result;
346 result = OC_STACK_OK;
349 result = OC_STACK_ERROR;
351 case OC_EH_FORBIDDEN:
352 result = OC_STACK_RESOURCE_ERROR;
354 case OC_EH_RESOURCE_CREATED:
355 result = OC_STACK_RESOURCE_CREATED;
357 case OC_EH_RESOURCE_DELETED:
358 result = OC_STACK_NO_RESOURCE;
361 result = OC_STACK_ERROR;
368 HandleVirtualResource (OCRequest *request, OCResource* resource)
370 OCStackResult result = OC_STACK_ERROR;
371 char *filterValue = NULL;
372 uint8_t filterOn = 0;
373 uint16_t remaining = 0;
374 unsigned char *buffer = NULL;
376 OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
378 result = ValidateUrlQuery (request->resourceUrl,
379 request->entityHandlerRequest->query, &filterOn,
382 if (result == OC_STACK_OK)
384 if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0)
386 remaining = request->entityHandlerRequest->resJSONPayloadLen;
387 buffer = request->entityHandlerRequest->resJSONPayload;
390 if((resource->resourceProperties & OC_ACTIVE)
391 && (resource->resourceProperties & OC_DISCOVERABLE))
393 // if there is data on the buffer, we have already added a response,
394 // so we need to add a comma before we do anything
395 if(buffer != request->entityHandlerRequest->resJSONPayload
396 && remaining >= (sizeof(OC_JSON_SEPARATOR)+1))
398 *buffer = OC_JSON_SEPARATOR;
403 result = BuildVirtualResourceResponse(resource, filterOn, filterValue,
404 (char*)buffer, &remaining);
405 if (result != OC_STACK_OK)
407 // if this failed, we need to remove the comma added above.
408 if(buffer != request->entityHandlerRequest->resJSONPayload)
417 buffer += strlen((char*)buffer);
419 resource = resource->next;
425 if(resource->resourceProperties & OC_ACTIVE){
426 OCNotifyAllObservers((OCResourceHandle) resource, OC_LOW_QOS);
428 result = OC_STACK_PRESENCE_DO_NOT_HANDLE;
433 if (result == OC_STACK_OK)
435 request->entityHandlerRequest->resJSONPayloadLen = remaining;
436 request->entityHandlerRequest->resJSONPayload = buffer;
443 HandleDefaultDeviceEntityHandler (OCRequest *request)
445 OCStackResult result = OC_STACK_OK;
446 OCEntityHandlerResult ehResult;
447 OCEntityHandlerRequest *ehRequest = request->entityHandlerRequest;
449 // At this point we know for sure that defaultDeviceHandler exists
450 ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, ehRequest,
451 (char*) request->resourceUrl);
453 result = EntityHandlerCodeToOCStackCode(ehResult);
455 ehRequest->resJSONPayloadLen = ehRequest->resJSONPayloadLen -
456 strlen((char*)ehRequest->resJSONPayload);
457 ehRequest->resJSONPayload += strlen((char*)ehRequest->resJSONPayload);
463 HandleResourceWithEntityHandler (OCRequest *request,
464 OCResource *resource,
465 uint8_t collectionResource)
467 OCStackResult result = OC_STACK_OK;
468 OCEntityHandlerResult ehResult = OC_EH_OK;
470 OCEntityHandlerRequest *ehRequest = request->entityHandlerRequest;
472 OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithEntityHandler"));
474 ehRequest->resource = (OCResourceHandle)resource;
476 // status code from entity handler is ignored unless observe call
477 if (request->observe == NULL)
479 ehResult = resource->entityHandler(OC_REQUEST_FLAG, ehRequest);
480 result = EntityHandlerCodeToOCStackCode(ehResult);
484 // If an observation register/deregister is included handle separately
485 if (!collectionResource)
487 result = ProcessObserveRequest (resource, request);
491 // Observation on collection resources not currently supported
492 result = OC_STACK_ERROR;
496 if (result == OC_STACK_OK || OC_STACK_RESOURCE_CREATED)
498 ehRequest->resJSONPayloadLen = ehRequest->resJSONPayloadLen -
499 strlen((char*)ehRequest->resJSONPayload);
500 ehRequest->resJSONPayload += strlen((char*)ehRequest->resJSONPayload);
508 HandleCollectionResourceDefaultEntityHandler (OCRequest *request,
509 OCResource *resource)
511 request->entityHandlerRequest->resource = (OCResourceHandle)resource;
512 return (DefaultCollectionEntityHandler (OC_REQUEST_FLAG, request->entityHandlerRequest));
517 BuildJSONResponse(ResourceHandling resHandling, OCResource *resource, OCRequest *request)
519 OCStackResult ret = OC_STACK_OK;
521 // save the response payload pointer, this pointer will be moved as
522 // different entity handlers will be called
523 unsigned char* saveJSONPayLoadPtr = request->entityHandlerRequest->resJSONPayload;
524 unsigned char* buffer = saveJSONPayLoadPtr;
525 uint16_t remaining = request->entityHandlerRequest->resJSONPayloadLen;
527 // add suffix in payload
528 if (remaining > OC_JSON_PREFIX_LEN)
530 strcpy((char*)buffer, OC_JSON_PREFIX);
531 remaining -= OC_JSON_PREFIX_LEN;
532 buffer += OC_JSON_PREFIX_LEN;
535 // move the entity handler payload pointer and update
536 // remaining valid bytes to fill data
537 request->entityHandlerRequest->resJSONPayload = buffer;
538 request->entityHandlerRequest->resJSONPayloadLen = remaining;
542 case OC_RESOURCE_VIRTUAL:
544 ret = HandleVirtualResource (request, resource);
548 case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
550 ret = HandleDefaultDeviceEntityHandler(request);
553 case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
555 OC_LOG(INFO, TAG, PCF("OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER"));
556 return OC_STACK_ERROR;
559 case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
561 ret = HandleResourceWithEntityHandler (request, resource, 0);
564 case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
566 ret = HandleResourceWithEntityHandler (request, resource, 1);
570 case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
572 ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
578 OC_LOG(INFO, TAG, PCF("Invalid Resource Determination"));
579 return OC_STACK_ERROR;
583 remaining = request->entityHandlerRequest->resJSONPayloadLen;
585 if (remaining > OC_JSON_SUFFIX_LEN)
587 strcpy((char*)request->entityHandlerRequest->resJSONPayload, OC_JSON_SUFFIX);
590 // update payload pointer with it's original location and original length
591 request->entityHandlerRequest->resJSONPayload = saveJSONPayLoadPtr;
592 request->entityHandlerRequest->resJSONPayloadLen = MAX_RESPONSE_LENGTH;