#include <coap/utlist.h>
#include <coap/pdu.h>
-
+#include <coap/coap.h>
// Module Name
#define MOD_NAME "ocobserve"
return decidedQoS;
}
+/**
+ * Create a get request and pass to entityhandler to notify specific observer.
+ *
+ * @param observer Observer that need to be notified.
+ * @param qos Quality of service of resource.
+ *
+ * @return ::OC_STACK_OK on success, some other value upon failure.
+ */
+static OCStackResult SendObserveNotification(ResourceObserver *observer,
+ OCQualityOfService qos)
+{
+ 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,
+ observer->query, NULL, NULL,
+ observer->token, observer->tokenLength,
+ observer->resUri, 0, observer->acceptFormat,
+ &observer->devAddr);
+
+ if (request)
+ {
+ 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);
+ if (result == OC_STACK_OK)
+ {
+ ehResult = observer->resource->entityHandler(OC_REQUEST_FLAG, &ehRequest,
+ observer->resource->entityHandlerCallbackParam);
+ if (ehResult == OC_EH_ERROR)
+ {
+ FindAndDeleteServerRequest(request);
+ }
+ // Reset Observer TTL.
+ observer->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
+ }
+ OCPayloadDestroy(ehRequest.payload);
+ }
+ }
+
+ return result;
+}
+
#ifdef WITH_PRESENCE
OCStackResult SendAllObserverNotification (OCMethod method, OCResource *resPtr, uint32_t maxAge,
OCPresenceTrigger trigger, OCResourceType *resourceType, OCQualityOfService qos)
{
#endif
qos = DetermineObserverQoS(method, resourceObserver, qos);
-
- result = AddServerRequest(&request, 0, 0, 1, OC_REST_GET,
- 0, resPtr->sequenceNum, qos, resourceObserver->query,
- NULL, NULL,
- resourceObserver->token, resourceObserver->tokenLength,
- resourceObserver->resUri, 0, resourceObserver->acceptFormat,
- &resourceObserver->devAddr);
-
- if (request)
- {
- request->observeResult = OC_STACK_OK;
- if (result == OC_STACK_OK)
- {
- result = FormOCEntityHandlerRequest(
- &ehRequest,
- (OCRequestHandle) request,
- request->method,
- &request->devAddr,
- (OCResourceHandle) resPtr,
- request->query,
- PAYLOAD_TYPE_REPRESENTATION,
- request->payload,
- request->payloadSize,
- request->numRcvdVendorSpecificHeaderOptions,
- request->rcvdVendorSpecificHeaderOptions,
- OC_OBSERVE_NO_OPTION,
- 0,
- request->coapID);
- if (result == OC_STACK_OK)
- {
- ehResult = resPtr->entityHandler(OC_REQUEST_FLAG, &ehRequest,
- resPtr->entityHandlerCallbackParam);
- if (ehResult == OC_EH_ERROR)
- {
- FindAndDeleteServerRequest(request);
- }
- }
- OCPayloadDestroy(ehRequest.payload);
- }
- }
+ result = SendObserveNotification(resourceObserver, qos);
#ifdef WITH_PRESENCE
}
else
{
OIC_LOG_V(INFO, TAG, "Error notifying observer id %d.", *obsIdList);
}
+ // Reset Observer TTL.
+ observer->TTL =
+ GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
}
else
{
obsNode->devAddr = *devAddr;
obsNode->resource = resHandle;
+ if ((strcmp(resUri, OC_RSRVD_PRESENCE_URI) == 0))
+ {
+ obsNode->TTL = 0;
+ }
+ else
+ {
+ obsNode->TTL = GetTicks(MAX_OBSERVER_TTL_SECONDS * MILLISECONDS_PER_SECOND);
+ }
+
LL_APPEND (g_serverObsList, obsNode);
return OC_STACK_OK;
return OC_STACK_NO_MEMORY;
}
+/*
+ * This function checks if the node is past its time to live and
+ * deletes it if timed-out. Calling this function with a presence callback
+ * with ttl set to 0 will not delete anything as presence nodes have
+ * their own mechanisms for timeouts. A null argument will cause the function to
+ * silently return.
+ */
+static void CheckTimedOutObserver(ResourceObserver* observer)
+{
+ if (!observer || observer->TTL == 0)
+ {
+ return;
+ }
+
+ coap_tick_t now;
+ coap_ticks(&now);
+
+ if (observer->TTL < now)
+ {
+ // Send confirmable notification message to observer.
+ OIC_LOG(INFO, TAG, "Sending High-QoS notification to observer");
+ SendObserveNotification(observer, OC_HIGH_QOS);
+ }
+}
+
ResourceObserver* GetObserverUsingId (const OCObservationId observeId)
{
ResourceObserver *out = NULL;
{
return out;
}
+ CheckTimedOutObserver(out);
}
}
OIC_LOG(INFO, TAG, "Observer node not found!!");
OIC_LOG(INFO, TAG, "Found in observer list");
return out;
}
+ CheckTimedOutObserver(out);
}
}
else
static CAResult_t OCSelectNetwork();
/**
- * Get the CoAP ticks after the specified number of milli-seconds.
- *
- * @param afterMilliSeconds Milli-seconds.
- * @return
- * CoAP ticks
- */
-static uint32_t GetTicks(uint32_t afterMilliSeconds);
-
-/**
- * Convert CAResult_t to OCStackResult.
- *
- * @param caResult CAResult_t code.
- * @return ::OC_STACK_OK on success, some other value upon failure.
- */
-static OCStackResult CAResultToOCStackResult(CAResult_t caResult);
-
-/**
* Convert CAResponseResult_t to OCStackResult.
*
* @param caCode CAResponseResult_t code.
return false;
}
-uint32_t GetTicks(uint32_t afterMilliSeconds)
+uint32_t GetTicks(uint32_t milliSeconds)
{
coap_tick_t now;
coap_ticks(&now);
// Guard against overflow of uint32_t
- if (afterMilliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) /
+ if (milliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) /
COAP_TICKS_PER_SECOND)
{
- return now + (afterMilliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND;
+ return now + (milliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND;
}
else
{
else
{
observer->failedCommCount++;
+ observer->forceHighQos = 1;
+ OIC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",
+ observer->failedCommCount);
result = OC_STACK_CONTINUE;
}
- observer->forceHighQos = 1;
- OIC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
}
break;
default:
return result;
}
-static OCStackResult CAResultToOCStackResult(CAResult_t caResult)
-{
- OCStackResult ret = OC_STACK_ERROR;
-
- switch(caResult)
- {
- case CA_ADAPTER_NOT_ENABLED:
- case CA_SERVER_NOT_STARTED:
- ret = OC_STACK_ADAPTER_NOT_ENABLED;
- break;
- case CA_MEMORY_ALLOC_FAILED:
- ret = OC_STACK_NO_MEMORY;
- break;
- case CA_STATUS_INVALID_PARAM:
- ret = OC_STACK_INVALID_PARAM;
- break;
- default:
- break;
- }
- return ret;
-}
-
OCStackResult CAResponseToOCStackResult(CAResponseResult_t caCode)
{
OCStackResult ret = OC_STACK_ERROR;
*/
void HandleCAErrorResponse(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo)
{
- OIC_LOG(INFO, TAG, "Enter HandleCAErrorResponse");
-
- if (NULL == endPoint)
- {
- OIC_LOG(ERROR, TAG, "endPoint is NULL");
- return;
- }
+ VERIFY_NON_NULL_NR(endPoint, FATAL);
+ VERIFY_NON_NULL_NR(errorInfo, FATAL);
- if (NULL == errorInfo)
- {
- OIC_LOG(ERROR, TAG, "errorInfo is NULL");
- return;
- }
+ OIC_LOG(INFO, TAG, "Enter HandleCAErrorResponse");
ClientCB *cbNode = GetClientCB(errorInfo->info.token,
errorInfo->info.tokenLength, NULL, NULL);
memcpy(response.identity.id, errorInfo->info.identity.id,
sizeof (response.identity.id));
response.identity.id_length = errorInfo->info.identity.id_length;
- response.result = CAResultToOCStackResult(errorInfo->result);
+ response.result = CAResultToOCResult(errorInfo->result);
cbNode->callBack(cbNode->context, cbNode->handle, &response);
}
+ ResourceObserver *observer = GetObserverUsingToken(errorInfo->info.token,
+ errorInfo->info.tokenLength);
+ if (observer)
+ {
+ OIC_LOG(INFO, TAG, "Receiving communication error for an observer");
+ OCStackResult result = CAResultToOCResult(errorInfo->result);
+ if (OC_STACK_COMM_ERROR == result)
+ {
+ OCStackFeedBack(errorInfo->info.token, errorInfo->info.tokenLength,
+ OC_OBSERVER_FAILED_COMM);
+ }
+ }
+
OIC_LOG(INFO, TAG, "Exit HandleCAErrorResponse");
}