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 "ocresourcehandler.h"
26 #include "ocobserve.h"
27 #include "occollection.h"
34 #define TAG PCF("ocresource")
35 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
36 {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
38 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
39 TAG, PCF(#arg " is NULL")); return (retVal); } }
41 extern OCResource *headResource;
43 static const char * VIRTUAL_RSRCS[] = {
52 //-----------------------------------------------------------------------------
53 // Default resource entity handler function
54 //-----------------------------------------------------------------------------
55 OCEntityHandlerResult defaultResourceEHandler(OCEntityHandlerFlag flag,
56 OCEntityHandlerRequest * request) {
57 TODO ("Implement me!!!!");
58 // TODO: remove silence unused param warnings
61 return OC_EH_OK; // Making sure that the Default EH and the Vendor EH have matching signatures
64 static OCStackResult ValidateUrlQuery (unsigned char *url, unsigned char *query,
65 uint8_t *filterOn, char **filterValue)
69 OC_LOG(INFO, TAG, PCF("Entering ValidateUrlQuery"));
71 return OC_STACK_INVALID_URI;
73 if (strcmp ((char *)url, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0) {
74 *filterOn = STACK_RES_DISCOVERY_NOFILTER;
75 if (query && *query) {
76 filterParam = strtok ((char *)query, "=");
77 *filterValue = strtok (NULL, " ");
78 if (!(*filterValue)) {
79 return OC_STACK_INVALID_QUERY;
80 } else if (strcmp (filterParam, OC_RSRVD_INTERFACE) == 0) {
81 // Resource discovery with interface filter
82 *filterOn = STACK_RES_DISCOVERY_IF_FILTER;
83 } else if (strcmp (filterParam, OC_RSRVD_RESOURCE_TYPE) == 0) {
84 // Resource discovery with resource type filter
85 *filterOn = STACK_RES_DISCOVERY_RT_FILTER;
87 // Other filter types not supported
88 return OC_STACK_INVALID_QUERY;
93 else if (strcmp((char *)url, GetVirtualResourceUri(OC_PRESENCE)) == 0) {
94 //Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
95 OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request"));
96 *filterOn = STACK_RES_DISCOVERY_NOFILTER;
100 // Other URIs not yet supported
101 return OC_STACK_INVALID_URI;
103 OC_LOG(INFO, TAG, PCF("Exiting ValidateUrlQuery"));
107 OCStackResult BuildVirtualResourceResponse(OCResource *resourcePtr, uint8_t filterOn,
108 char *filterValue, char * out, uint16_t *remaining)
110 OCResourceType *resourceTypePtr;
111 OCResourceInterface *interfacePtr;
112 cJSON *resObj, *propObj, *rtArray;
114 uint8_t encodeRes = 0;
115 OCStackResult ret = OC_STACK_OK;
118 OC_LOG(INFO, TAG, PCF("Entering BuildVirtualResourceResponse"));
119 resObj = cJSON_CreateObject();
124 if (filterOn == STACK_RES_DISCOVERY_RT_FILTER) {
125 resourceTypePtr = resourcePtr->rsrcType;
126 while (resourceTypePtr) {
127 if (strcmp (resourceTypePtr->resourcetypename, filterValue) == 0) {
131 resourceTypePtr = resourceTypePtr->next;
133 } else if (filterOn == STACK_RES_DISCOVERY_IF_FILTER) {
134 interfacePtr = resourcePtr->rsrcInterface;
135 while (interfacePtr) {
136 if (strcmp (interfacePtr->name, filterValue) == 0) {
140 interfacePtr = interfacePtr->next;
142 } else if (filterOn == STACK_RES_DISCOVERY_NOFILTER) {
145 //TODO: Unsupported query filter
146 return OC_STACK_INVALID_QUERY;
151 cJSON_AddItemToObject (resObj, OC_RSRVD_HREF, cJSON_CreateString(resourcePtr->uri));
153 cJSON_AddItemToObject (resObj, "prop", propObj = cJSON_CreateObject());
154 // Add resource types
155 cJSON_AddItemToObject (propObj, OC_RSRVD_RESOURCE_TYPE, rtArray = cJSON_CreateArray());
156 resourceTypePtr = resourcePtr->rsrcType;
157 while (resourceTypePtr) {
158 cJSON_AddItemToArray (rtArray,
159 cJSON_CreateString(resourceTypePtr->resourcetypename));
160 resourceTypePtr = resourceTypePtr->next;
162 // Add interface types
163 cJSON_AddItemToObject (propObj, OC_RSRVD_INTERFACE, rtArray = cJSON_CreateArray());
164 interfacePtr = resourcePtr->rsrcInterface;
165 while (interfacePtr) {
166 cJSON_AddItemToArray (rtArray, cJSON_CreateString(interfacePtr->name));
167 interfacePtr = interfacePtr->next;
169 // If resource is observable, set observability flag.
170 // Resources that are not observable will not have the flag.
171 if (resourcePtr->resourceProperties & OC_OBSERVABLE) {
172 cJSON_AddItemToObject (propObj, OC_RSRVD_OBSERVABLE,
173 cJSON_CreateNumber(OC_RESOURCE_OBSERVABLE));
175 // Set secure flag for secure resources
176 if (resourcePtr->resourceProperties & OC_SECURE) {
178 cJSON_AddNumberToObject (propObj, OC_RSRVD_SECURE, OC_RESOURCE_SECURE);
179 //Set the IP port also as secure resources are hosted on a different port
180 if (OCGetResourceEndPointInfo (resourcePtr, &port) == OC_STACK_OK) {
181 cJSON_AddNumberToObject (propObj, OC_RSRVD_HOSTING_PORT, port);
187 jsonStr = cJSON_PrintUnformatted (resObj);
189 jsonLen = strlen(jsonStr);
190 if (jsonLen < *remaining)
192 strcpy(out, jsonStr);
193 *remaining = *remaining - jsonLen;
197 ret = OC_STACK_ERROR;
199 cJSON_Delete (resObj);
202 OC_LOG(INFO, TAG, PCF("Exiting BuildVirtualResourceResponse"));
206 TODO ("Does it make sense to make this method as inline")
207 const char * GetVirtualResourceUri( OCVirtualResources resource)
209 if (resource < OC_MAX_VIRTUAL_RESOURCES)
211 return VIRTUAL_RSRCS[resource];
217 uint8_t IsVirtualResource(const char* resourceUri)
219 for (int i = 0; i < OC_MAX_VIRTUAL_RESOURCES; i++)
221 if (strcmp(resourceUri, GetVirtualResourceUri((OCVirtualResources)i)) == 0)
229 uint8_t IsCollectionResource (OCResource *resource)
231 for (int i = 0; i < MAX_CONTAINED_RESOURCES; i++)
233 if (resource->rsrcResources[i])
241 OCResource *FindResourceByUri(const char* resourceUri)
243 OCResource * pointer = headResource;
245 if (strcmp(resourceUri, pointer->uri) == 0) {
248 pointer = pointer->next;
250 OC_LOG(INFO, TAG, PCF("Resource not found"));
255 OCStackResult DetermineResourceHandling (OCServerRequest *request,
256 ResourceHandling *handling,
257 OCResource **resource)
260 OC_LOG(INFO, TAG, PCF("Entering DetermineResourceHandling"));
262 // Check if virtual resource
263 if (IsVirtualResource((const char*)request->resourceUrl))
265 *handling = OC_RESOURCE_VIRTUAL;
266 *resource = headResource;
269 if (NULL == request->resourceUrl || (strlen((const char*)(request->resourceUrl)) == 0))
271 // Resource URL not specified
272 *handling = OC_RESOURCE_NOT_SPECIFIED;
277 OCResource *resourcePtr = NULL;
278 resourcePtr = FindResourceByUri((const char*)request->resourceUrl);
279 *resource = resourcePtr;
282 if(defaultDeviceHandler)
284 *handling = OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER;
288 // Resource does not exist
289 // and default device handler does not exist
290 *handling = OC_RESOURCE_NOT_SPECIFIED;
291 return OC_STACK_NO_RESOURCE;
294 // secure resource will entertain only authorized requests
295 if ((resourcePtr->resourceProperties & OC_SECURE) && (request->secured == 0))
297 OC_LOG(INFO, TAG, PCF("Un-authorized request. Ignore it!"));
298 return OC_STACK_RESOURCE_ERROR;
301 if (IsCollectionResource (resourcePtr))
303 // Collection resource
304 if (resourcePtr->entityHandler != defaultResourceEHandler)
306 *handling = OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER;
309 *handling = OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER;
313 // Resource not a collection
314 if (resourcePtr->entityHandler != defaultResourceEHandler)
316 *handling = OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER;
319 *handling = OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER;
326 OCStackResult EntityHandlerCodeToOCStackCode(OCEntityHandlerResult ehResult)
328 OCStackResult result;
333 result = OC_STACK_OK;
336 result = OC_STACK_SLOW_RESOURCE;
339 result = OC_STACK_ERROR;
341 case OC_EH_FORBIDDEN:
342 result = OC_STACK_RESOURCE_ERROR;
344 case OC_EH_RESOURCE_CREATED:
345 result = OC_STACK_RESOURCE_CREATED;
347 case OC_EH_RESOURCE_DELETED:
348 result = OC_STACK_RESOURCE_DELETED;
351 result = OC_STACK_ERROR;
358 HandleVirtualResource (OCServerRequest *request, OCResource* resource)
360 OCStackResult result = OC_STACK_ERROR;
361 char *filterValue = NULL;
362 uint8_t filterOn = 0;
363 uint16_t remaining = 0;
364 unsigned char * ptr = NULL;
365 uint8_t firstLoopDone = 0;
366 unsigned char discoveryResBuf[MAX_RESPONSE_LENGTH] = {0};
368 OC_LOG(INFO, TAG, PCF("Entering HandleVirtualResource"));
370 result = ValidateUrlQuery (request->resourceUrl,
371 request->query, &filterOn,
374 if (result == OC_STACK_OK)
376 if (strcmp ((char *)request->resourceUrl, GetVirtualResourceUri(OC_WELL_KNOWN_URI)) == 0)
378 ptr = discoveryResBuf;
379 remaining = MAX_RESPONSE_LENGTH;
383 if((resource->resourceProperties & OC_ACTIVE)
384 && (resource->resourceProperties & OC_DISCOVERABLE))
386 // if there is data on the buffer, we have already added a response,
387 // so we need to add a comma before we do anything
389 && remaining >= (sizeof(OC_JSON_SEPARATOR)+1))
391 *ptr = OC_JSON_SEPARATOR;
396 result = BuildVirtualResourceResponse(resource, filterOn, filterValue,
397 (char*)ptr, &remaining);
399 if (result != OC_STACK_OK)
401 // if this failed, we need to remove the comma added above.
410 ptr += strlen((char *)ptr);
413 resource = resource->next;
416 if(strlen((const char *)discoveryResBuf) > 0)
418 OCEntityHandlerResponse response = {0};
420 response.ehResult = OC_EH_OK;
421 response.payload = discoveryResBuf;
422 response.payloadSize = strlen((const char *)discoveryResBuf) + 1;
423 response.persistentBufferFlag = 0;
424 response.requestHandle = (OCRequestHandle) request;
425 response.resourceHandle = (OCResourceHandle) resource;
427 result = OCDoResponse(&response);
433 if(resource->resourceProperties & OC_ACTIVE){
434 SendPresenceNotification(NULL);
439 result = OC_STACK_VIRTUAL_DO_NOT_HANDLE;
444 HandleDefaultDeviceEntityHandler (OCServerRequest *request)
446 OCStackResult result = OC_STACK_OK;
447 OCEntityHandlerResult ehResult = OC_EH_ERROR;
448 OCEntityHandlerRequest ehRequest = {0};
450 OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithDefaultDeviceEntityHandler"));
451 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
452 request->method, (OCResourceHandle) NULL, request->query,
453 request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
454 request->rcvdVendorSpecificHeaderOptions, (OCObserveAction)request->observationOption, (OCObservationId)0);
455 VERIFY_SUCCESS(result, OC_STACK_OK);
457 // At this point we know for sure that defaultDeviceHandler exists
458 ehResult = defaultDeviceHandler(OC_REQUEST_FLAG, &ehRequest,
459 (char*) request->resourceUrl);
460 if(ehResult == OC_EH_SLOW)
462 OC_LOG(INFO, TAG, PCF("This is a slow resource"));
463 request->slowFlag = 1;
465 else if(ehResult == OC_EH_ERROR)
467 FindAndDeleteServerRequest(request);
469 result = EntityHandlerCodeToOCStackCode(ehResult);
475 HandleResourceWithEntityHandler (OCServerRequest *request,
476 OCResource *resource,
477 uint8_t collectionResource)
479 OCStackResult result = OC_STACK_ERROR;
480 OCEntityHandlerResult ehResult = OC_EH_ERROR;
481 OCEntityHandlerFlag ehFlag = OC_REQUEST_FLAG;
482 ResourceObserver *resObs = NULL;
484 OCEntityHandlerRequest ehRequest = {0};
486 OC_LOG(INFO, TAG, PCF("Entering HandleResourceWithEntityHandler"));
487 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
488 request->method, (OCResourceHandle) resource, request->query,
489 request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
490 request->rcvdVendorSpecificHeaderOptions,
491 (OCObserveAction)request->observationOption, 0);
492 VERIFY_SUCCESS(result, OC_STACK_OK);
494 if(ehRequest.obsInfo.action == OC_OBSERVE_NO_OPTION)
496 OC_LOG(INFO, TAG, PCF("No observation requested"));
497 ehFlag = OC_REQUEST_FLAG;
499 else if(ehRequest.obsInfo.action == OC_OBSERVE_REGISTER &&
502 OC_LOG(INFO, TAG, PCF("Registering observation requested"));
503 result = GenerateObserverId(&ehRequest.obsInfo.obsId);
504 VERIFY_SUCCESS(result, OC_STACK_OK);
506 result = AddObserver ((const char*)(request->resourceUrl),
507 (const char *)(request->query),
508 ehRequest.obsInfo.obsId, &request->requestToken,
509 &request->requesterAddr, resource, request->qos);
510 if(result == OC_STACK_OK)
512 OC_LOG(DEBUG, TAG, PCF("Added observer successfully"));
513 request->observeResult = OC_STACK_OK;
514 ehFlag = (OCEntityHandlerFlag)(OC_REQUEST_FLAG | OC_OBSERVE_FLAG);
518 result = OC_STACK_OK;
519 request->observeResult = OC_STACK_ERROR;
520 OC_LOG(DEBUG, TAG, PCF("Observer Addition failed"));
521 ehFlag = OC_REQUEST_FLAG;
525 else if(ehRequest.obsInfo.action == OC_OBSERVE_DEREGISTER &&
528 OC_LOG(INFO, TAG, PCF("Deregistering observation requested"));
529 resObs = GetObserverUsingToken (&request->requestToken);
532 // Stack does not contain this observation request
533 // Either token is incorrect or observation list is corrupted
534 result = OC_STACK_ERROR;
537 ehRequest.obsInfo.obsId = resObs->observeId;
538 ehFlag = (OCEntityHandlerFlag)(ehFlag | OC_OBSERVE_FLAG);
540 result = DeleteObserverUsingToken (&request->requestToken);
541 if(result == OC_STACK_OK)
543 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
544 request->observeResult = OC_STACK_OK;
548 result = OC_STACK_OK;
549 request->observeResult = OC_STACK_ERROR;
550 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
555 result = OC_STACK_ERROR;
559 ehResult = resource->entityHandler(ehFlag, &ehRequest);
560 if(ehResult == OC_EH_SLOW)
562 OC_LOG(INFO, TAG, PCF("This is a slow resource"));
563 request->slowFlag = 1;
565 else if(ehResult == OC_EH_ERROR)
567 FindAndDeleteServerRequest(request);
569 result = EntityHandlerCodeToOCStackCode(ehResult);
575 HandleCollectionResourceDefaultEntityHandler (OCServerRequest *request,
576 OCResource *resource)
578 OCStackResult result = OC_STACK_ERROR;
579 OCEntityHandlerRequest ehRequest = {0};
581 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) request,
582 request->method, (OCResourceHandle) resource, request->query,
583 request->reqJSONPayload, request->numRcvdVendorSpecificHeaderOptions,
584 request->rcvdVendorSpecificHeaderOptions,
585 (OCObserveAction)request->observationOption, (OCObservationId) 0);
586 if(result != OC_STACK_OK)
591 return (DefaultCollectionEntityHandler (OC_REQUEST_FLAG, &ehRequest));
595 ProcessRequest(ResourceHandling resHandling, OCResource *resource, OCServerRequest *request)
597 OCStackResult ret = OC_STACK_OK;
601 case OC_RESOURCE_VIRTUAL:
603 ret = HandleVirtualResource (request, resource);
606 case OC_RESOURCE_DEFAULT_DEVICE_ENTITYHANDLER:
608 ret = HandleDefaultDeviceEntityHandler(request);
611 case OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER:
613 OC_LOG(INFO, TAG, PCF("OC_RESOURCE_NOT_COLLECTION_DEFAULT_ENTITYHANDLER"));
614 return OC_STACK_ERROR;
616 case OC_RESOURCE_NOT_COLLECTION_WITH_ENTITYHANDLER:
618 ret = HandleResourceWithEntityHandler (request, resource, 0);
621 case OC_RESOURCE_COLLECTION_WITH_ENTITYHANDLER:
623 ret = HandleResourceWithEntityHandler (request, resource, 1);
626 case OC_RESOURCE_COLLECTION_DEFAULT_ENTITYHANDLER:
628 ret = HandleCollectionResourceDefaultEntityHandler (request, resource);
631 case OC_RESOURCE_NOT_SPECIFIED:
633 ret = OC_STACK_NO_RESOURCE;
638 OC_LOG(INFO, TAG, PCF("Invalid Resource Determination"));
639 return OC_STACK_ERROR;