X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fstack%2Fsrc%2Foickeepalive.c;h=bd01d08311a79a0848b424d54243a7e944be3b81;hb=refs%2Fchanges%2F37%2F208337%2F1;hp=09fc6a708e308019f052104f10442a2a01d1154d;hpb=6ac4daf1c0a01ee54845041025cb7ec845d2502b;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/stack/src/oickeepalive.c b/resource/csdk/stack/src/oickeepalive.c old mode 100644 new mode 100755 index 09fc6a7..bd01d08 --- a/resource/csdk/stack/src/oickeepalive.c +++ b/resource/csdk/stack/src/oickeepalive.c @@ -19,6 +19,7 @@ ******************************************************************/ #include "oickeepalive.h" +#include "oickeepaliveinternal.h" #include #include @@ -26,12 +27,15 @@ #include "oic_string.h" #include "oic_time.h" #include "ocrandom.h" +#include "octhread.h" #include "uarraylist.h" #include "ocstackinternal.h" #include "ocpayloadcbor.h" #include "ocpayload.h" #include "ocresourcehandler.h" #include "logger.h" +#include "cautilinterface.h" +#include /** * Logging tag for module name. @@ -55,6 +59,9 @@ static const uint64_t USECS_PER_SEC = 1000000; #define VERIFY_NON_NULL_V(arg) { if (!arg) {OIC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\ goto exit;} } +#define VERIFY_NON_NULL_EXIT(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \ + TAG, #arg " is NULL"); ret = retVal; goto exit; } } + /** * The KeepAlive table entries are removed * if it can't receive response message within 60 seconds. @@ -62,22 +69,6 @@ static const uint64_t USECS_PER_SEC = 1000000; #define KEEPALIVE_RESPONSE_TIMEOUT_SEC 60 /** - * The Min time interval value. (2 minutes) - * start from 2 minutes and increases in multiples of 2 up to a maximum of 64minutes. - */ -#define KEEPALIVE_MIN_INTERVAL 2 - -/** - * The Max time interval value. (64 minutes) - */ -#define KEEPALIVE_MAX_INTERVAL 64 - -/** - * Default counts of interval value. - */ -#define DEFAULT_INTERVAL_COUNT 6 - -/** * KeepAlive key to parser Payload Table. */ static const char INTERVAL[] = "in"; @@ -88,11 +79,6 @@ static const char INTERVAL[] = "in"; static const char INTERVAL_ARRAY[] = "inarray"; /** - * To check if KeepAlive is initialized. - */ -static bool g_isKeepAliveInitialized = false; - -/** * Pointer to handle of the newly created KeepAlive resource. */ static OCResourceHandle g_keepAliveHandle = NULL; @@ -100,104 +86,82 @@ static OCResourceHandle g_keepAliveHandle = NULL; /** * KeepAlive table which holds connection interval. */ -static u_arraylist_t *g_keepAliveConnectionTable = NULL; +static struct KeepAliveEntry_t *g_keepAliveConnectionTable = NULL; + +/** + * Mutex to synchronize device object list. + */ +static oc_mutex g_mutexObjectList = NULL; /** * KeepAlive table entries. */ -typedef struct +typedef struct KeepAliveEntry_t { OCMode mode; /**< host Mode of Operation. */ CAEndpoint_t remoteAddr; /**< destination Address. */ - uint32_t interval; /**< time interval for KeepAlive. in seconds.*/ + int64_t interval; /**< time interval for KeepAlive. in seconds.*/ int32_t currIndex; /**< current interval value index. */ - size_t intervalSize; /**< total interval counts. */ - int64_t *intervalInfo; /**< interval values for KeepAlive. */ bool sentPingMsg; /**< if oic client already sent ping message. */ uint64_t timeStamp; /**< last sent or received ping message. in microseconds. */ + OCDoHandle handle; /**< Invocation handle tied to original call to OCDoResource().*/ + struct KeepAliveEntry_t *next; /**< Linked list; for multiple keepalive info list.*/ } KeepAliveEntry_t; /** * Send disconnect message to remove connection. */ -static OCStackResult SendDisconnectMessage(const KeepAliveEntry_t *entry); - -/** - * Send ping message to remote endpoint. - */ -static OCStackResult SendPingMessage(KeepAliveEntry_t *entry); - -/** - * Increase interval value to send next ping message. - */ -static void IncreaseInterval(KeepAliveEntry_t *entry); - -/** - * Ping Message callback registered with RI for KeepAlive Request. - */ -static OCStackApplicationResult PingRequestCallback(void* ctx, OCDoHandle handle, - OCClientResponse * clientResponse); +static OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry); /** * This function creates KeepAlive resource. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCStackResult CreateKeepAliveResource(); +static OCStackResult OCCreateKeepAliveResource(); /** * This function deletes KeepAlive resource. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCStackResult DeleteKeepAliveResource(); +static OCStackResult OCDeleteKeepAliveResource(); /** * API to handle the GET request received for a KeepAlive resource. - * @param[in] endPoint RemoteEndpoint which sent the packet. - * @param[in] requestInfo Received coap packet. + * @param[in] request Request Received. + * @param[in] resource Resource handle used for sending the response. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCStackResult HandleKeepAliveGETRequest(const CAEndpoint_t* endPoint, - const CARequestInfo_t* requestInfo); +static OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request, + const OCResource *resource); /** * API to handle the PUT request received for a KeepAlive resource. - * @param[in] endPoint RemoteEndpoint which sent the packet. - * @param[in] requestInfo Received coap packet. + * @param[in] request Request Received. + * @param[in] resource Resource handle used for sending the response. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCStackResult HandleKeepAlivePUTRequest(const CAEndpoint_t* endPoint, - const CARequestInfo_t* requestInfo); +static OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request, + const OCResource *resource); /** - * API to handle the Response payload. - * @param[in] endpoint RemoteEndpoint which sent the packet. - * @param[in] responseCode Received reseponse code. - * @param[in] respPayload Response payload. - * @return ::OC_STACK_OK or Appropriate error code. - */ -OCStackResult HandleKeepAliveResponse(const CAEndpoint_t *endPoint, - OCStackResult responseCode, - const OCRepPayload *respPayload); -/** * Gets keepalive entry. * @param[in] endpoint Remote Endpoint information (like ipaddress, * port, reference uri and transport type) to * which the ping message has to be sent. - * @param[out] index index of array list. * @return KeepAlive entry to send ping message. */ -static KeepAliveEntry_t *GetEntryFromEndpoint(const CAEndpoint_t *endpoint, uint32_t *index); +static KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint); /** * Add keepalive entry. * @param[in] endpoint Remote Endpoint information (like ipaddress, * port, reference uri and transport type). * @param[in] mode Whether it is OIC Server or OIC Client. - * @param[in] intervalArray Received interval values from cloud server. + * @param[in] interval Sent interval value to remote device. * @return The KeepAlive entry added in KeepAlive Table. */ -KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, - int64_t *intervalArray); +KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, + int64_t interval); /** * Remove keepalive entry. @@ -205,102 +169,287 @@ KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, * port, reference uri and transport type). * @return The KeepAlive entry removed in KeepAlive Table. */ -static OCStackResult RemoveKeepAliveEntry(const CAEndpoint_t *endpoint); +static OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint); + +/** + * Create KeepAlive paylaod to send message. + * @param[in] interval The interval value to be sent. + * @return Created representation payload. + */ +static OCRepPayload *OCCreateKeepAlivePayload(int64_t interval); + +/** + * Send response to remote device. + * @param[in] request Request Received. + * @param[in] result Result to be sent. + * @return ::OC_STACK_OK or Appropriate error code. + */ +static OCStackResult OCSendKeepAliveResponse(OCServerRequest *request, + OCEntityHandlerResult result); + +/** + * Add resource type name to payload for GET request. + * @param[in] payload Pointer to the payload to which byte string needs to be added. + * @return ::OC_STACK_OK or Appropriate error code. + */ +static OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload); + +/** + * Add resource interface name to payload for GET request. + * @param[in] payload Pointer to the payload to which byte string needs to be added. + * @return ::OC_STACK_OK or Appropriate error code. + */ +static OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload); -OCStackResult InitializeKeepAlive(OCMode mode) +OCStackResult OCInitializeKeepAlive(OCMode mode) { - OIC_LOG(DEBUG, TAG, "InitializeKeepAlive IN"); - if (g_isKeepAliveInitialized) + OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive IN"); + + if (!g_mutexObjectList) { - OIC_LOG(DEBUG, TAG, "KeepAlive already initialized"); - return OC_STACK_OK; + g_mutexObjectList = oc_mutex_new(); + if (!g_mutexObjectList) + { + OIC_LOG(ERROR, TAG, "Failed to create mutex!"); + return OC_STACK_ERROR; + } } if (OC_CLIENT != mode) { // Create the KeepAlive Resource[/oic/ping]. - OCStackResult result = CreateKeepAliveResource(); + OCStackResult result = OCCreateKeepAliveResource(); if (OC_STACK_OK != result) { - OIC_LOG_V(ERROR, TAG, "CreateKeepAliveResource failed[%d]", result); + OIC_LOG_V(ERROR, TAG, "OCCreateKeepAliveResource failed[%d]", result); return result; } } - if (!g_keepAliveConnectionTable) + OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive OUT"); + return OC_STACK_OK; +} + +OCStackResult OCTerminateKeepAlive(OCMode mode) +{ + OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive IN"); + + if (g_mutexObjectList) { - g_keepAliveConnectionTable = u_arraylist_create(); - if (NULL == g_keepAliveConnectionTable) + oc_mutex_free(g_mutexObjectList); + g_mutexObjectList = NULL; + } + + if (OC_CLIENT != mode) + { + // Delete the KeepAlive Resource[/oic/ping]. + OCStackResult result = OCDeleteKeepAliveResource(); + if (OC_STACK_OK != result) { - OIC_LOG(ERROR, TAG, "Creating KeepAlive Table failed"); - TerminateKeepAlive(mode); - return OC_STACK_ERROR; + OIC_LOG_V(ERROR, TAG, "OCDeleteKeepAliveResource failed[%d]", result); + return result; } } - g_isKeepAliveInitialized = true; - - OIC_LOG(DEBUG, TAG, "InitializeKeepAlive OUT"); + OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive OUT"); return OC_STACK_OK; } -OCStackResult TerminateKeepAlive(OCMode mode) +OCStackResult OCFindKeepAliveResource(OCDoHandle *handle, const char *remoteAddr, + OCCallbackData *cbData) +{ + // Validate input parameters + VERIFY_NON_NULL(remoteAddr, FATAL, OC_STACK_INVALID_CALLBACK); + VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK); + VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK); + + // Send discover message to find ping resource + char requestUri[MAX_QUERY_LENGTH] = { 0 }; + snprintf(requestUri, MAX_QUERY_LENGTH, "%s%s", remoteAddr, KEEPALIVE_RESOURCE_URI); + OCStackResult result = OCDoResource(handle, OC_REST_DISCOVER, requestUri, + NULL, NULL, CT_ADAPTER_TCP, OC_HIGH_QOS, + cbData, NULL, 0); + if (OC_STACK_OK != result) + { + OIC_LOG(ERROR, TAG, "OCDoResource has failed"); + } + return result; +} + +OCStackResult OCSendKeepAliveRequest(OCDoHandle *handle, const char *remoteAddr, + OCPayload *payload, OCCallbackData *cbData) { - OIC_LOG(DEBUG, TAG, "TerminateKeepAlive IN"); - if (!g_isKeepAliveInitialized) + OCStackResult ret; + VERIFY_NON_NULL_EXIT(remoteAddr, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL_EXIT(cbData, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL_EXIT(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK); + VERIFY_NON_NULL_EXIT(payload, FATAL, OC_STACK_INVALID_CALLBACK); + + OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest IN"); + + // Parse the remote device address to send ping message. + OCDevAddr *devAddr = NULL; + char requestUri[MAX_QUERY_LENGTH] = { 0 }; + snprintf(requestUri, MAX_QUERY_LENGTH, "%s%s", remoteAddr, KEEPALIVE_RESOURCE_URI); + OCStackResult result = ParseRequestUri(requestUri, OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS, + &devAddr, NULL, NULL); + if (result != OC_STACK_OK) { - OIC_LOG(ERROR, TAG, "KeepAlive not initialized"); + OIC_LOG_V(DEBUG, TAG, "Unable to parse uri: %s", remoteAddr); + OCPayloadDestroy(payload); return OC_STACK_ERROR; } - if (OC_CLIENT != mode) + VERIFY_NON_NULL_EXIT(devAddr, FATAL, OC_STACK_INVALID_PARAM); + + if (!(devAddr->adapter & OC_ADAPTER_TCP)) { - // Delete the KeepAlive Resource[/oic/ping]. - OCStackResult result = DeleteKeepAliveResource(); - if (OC_STACK_OK != result) + OIC_LOG_V(DEBUG, TAG, "Not supported connectivity type"); + OICFree(devAddr); + OCPayloadDestroy(payload); + return OC_STACK_ERROR; + } + + // Get entry from KeepAlive table. + CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER }; + CopyDevAddrToEndpoint(devAddr, &endpoint); + + oc_mutex_lock(g_mutexObjectList); + KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint); + if (!entry) + { + OIC_LOG(DEBUG, TAG, "There is no connection info in KeepAlive table"); + + entry = OCAddKeepAliveEntry(&endpoint, OC_CLIENT, 0); + if (!entry) { - OIC_LOG_V(ERROR, TAG, "DeleteKeepAliveResource failed[%d]", result); - return result; + oc_mutex_unlock(g_mutexObjectList); + OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry"); + OICFree(devAddr); + OCPayloadDestroy(payload); + return OC_STACK_ERROR; + } + } + + // Get "in" value from payload. + int64_t interval = 0; + bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) payload, INTERVAL, &interval); + if (findValue && interval) + { + if (entry->sentPingMsg) + { + oc_mutex_unlock(g_mutexObjectList); + OIC_LOG(ERROR, TAG, "Already sent a ping request to remote device"); + OICFree(devAddr); + OCPayloadDestroy(payload); + return OC_STACK_ERROR; } + entry->interval = interval; + OIC_LOG_V(DEBUG, TAG, "Send ping message with interval [%" PRId64 "]", entry->interval); + } + + // Get "inarray" value from payload. + int64_t *inArray = NULL; + size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 0 }; + OCRepPayloadGetIntArray((OCRepPayload *) payload, INTERVAL_ARRAY, &inArray, dimensions); + if (inArray) + { + uint8_t len = 0; + char newArray[MAX_URI_LENGTH] = { 0 }; + size_t inArraySize = calcDimTotal(dimensions); + for (size_t i = 0; i < inArraySize; i++) + { + len += snprintf(newArray + len, MAX_URI_LENGTH, "% " PRId64, inArray[i]); + } + OICFree(inArray); + OIC_LOG_V(DEBUG, TAG, "Send update interval message with inarray [ %s]", newArray); + } + + // Send keepalive message. + result = OCDoResource(&entry->handle, OC_REST_POST, KEEPALIVE_RESOURCE_URI, + devAddr, (OCPayload *) payload, CT_ADAPTER_TCP, + OC_HIGH_QOS, cbData, NULL, 0); + if (OC_STACK_OK != result) + { + oc_mutex_unlock(g_mutexObjectList); + OIC_LOG(ERROR, TAG, "OCDoResource has failed"); + OICFree(devAddr); + return result; } - if (NULL != g_keepAliveConnectionTable) + // Update timeStamp with time sent ping message for next ping message. + entry->timeStamp = OICGetCurrentTime(TIME_IN_US); + entry->sentPingMsg = true; + if (handle) { - u_arraylist_destroy(g_keepAliveConnectionTable); - g_keepAliveConnectionTable = NULL; + *handle = entry->handle; } - g_isKeepAliveInitialized = false; + oc_mutex_unlock(g_mutexObjectList); + OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest OUT"); + OICFree(devAddr); + return result; + +exit: + OCPayloadDestroy(payload); + return (ret); +} - OIC_LOG(DEBUG, TAG, "TerminateKeepAlive OUT"); +OCStackResult OCHandleKeepAliveResponse(const CAEndpoint_t *endPoint, const OCPayload *payload) +{ + (void) payload; + VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM); + + // Receive response message about post /oic/ping request. + OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse IN"); + + // Get entry from KeepAlive table. + oc_mutex_lock(g_mutexObjectList); + KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endPoint); + if (entry) + { + OIC_LOG_V(DEBUG, TAG, "Received response about interval [%" PRId64 "]", entry->interval); + + // Set sentPingMsg values with false. + entry->sentPingMsg = false; + entry->handle = NULL; + } + + oc_mutex_unlock(g_mutexObjectList); + OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse OUT"); return OC_STACK_OK; } -OCStackResult CreateKeepAliveResource() +OCStackResult OCCreateKeepAliveResource() { - OIC_LOG(DEBUG, TAG, "InitKeepAliveResource IN"); + OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource IN"); // Create a KeepAlive resource OCStackResult result = OCCreateResource(&g_keepAliveHandle, KEEPALIVE_RESOURCE_TYPE_NAME, - KEEPALIVE_RESOURCE_INTF_NAME, + OC_RSRVD_INTERFACE_DEFAULT, KEEPALIVE_RESOURCE_URI, NULL, NULL, - OC_DISCOVERABLE); + OC_RES_PROP_NONE); + if (OC_STACK_OK == result) + { + result = BindResourceInterfaceToResource((OCResource *) g_keepAliveHandle, + KEEPALIVE_RESOURCE_INTF_NAME); + } if (OC_STACK_OK != result) { OIC_LOG_V(ERROR, TAG, "Create resource for KeepAlive failed[%d]", result); } - OIC_LOG(DEBUG, TAG, "InitKeepAliveResource OUT"); + OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource OUT"); return result; } -OCStackResult DeleteKeepAliveResource() +OCStackResult OCDeleteKeepAliveResource() { - OIC_LOG(DEBUG, TAG, "DeleteKeepAliveResource IN"); + OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource IN"); // Create a KeepAlive resource OCStackResult result = OCDeleteResource(g_keepAliveHandle); @@ -310,335 +459,316 @@ OCStackResult DeleteKeepAliveResource() OIC_LOG_V(ERROR, TAG, "Delete resource for KeepAlive failed[%d]", result); } - OIC_LOG(DEBUG, TAG, "DeleteKeepAliveResource OUT"); + OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource OUT"); return result; } -OCStackResult HandleKeepAliveRequest(const CAEndpoint_t* endPoint, - const CARequestInfo_t* requestInfo) +OCStackResult OCHandleKeepAliveRequest(OCServerRequest *request, + const OCResource *resource) { - VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(resource, FATAL, OC_STACK_INVALID_PARAM); - OIC_LOG(DEBUG, TAG, "HandleKeepAliveRequest IN"); + OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest IN"); - OCStackResult result = OC_STACK_OK; - if (CA_PUT == requestInfo->method) + OCEntityHandlerResult result = OC_EH_ERROR; + if (OC_REST_GET == request->method) + { + switch ((OCObserveAction)request->observationOption) + { + case OC_OBSERVE_NO_OPTION: + case OC_OBSERVE_REGISTER: + case OC_OBSERVE_DEREGISTER: + OIC_LOG(DEBUG, TAG, "Received GET request"); + result = OCHandleKeepAliveGETRequest(request, resource); + break; + default: + OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive"); + result = OC_EH_UNAUTHORIZED_REQ; + } + } + else if (OC_REST_PUT == request->method || OC_REST_POST == request->method) { - result = HandleKeepAlivePUTRequest(endPoint, requestInfo); + OIC_LOG(DEBUG, TAG, "Received PUT/POST request"); + result = OCHandleKeepAlivePOSTRequest(request, resource); } - else if (CA_GET == requestInfo->method) + else { - result = HandleKeepAliveGETRequest(endPoint, requestInfo); + OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive"); + result = OC_EH_UNAUTHORIZED_REQ; } - OIC_LOG(DEBUG, TAG, "HandleKeepAliveRequest OUT"); - return result; + OCStackResult ret = OCSendKeepAliveResponse(request, result); + if (OC_STACK_OK != ret) + { + OIC_LOG_V(ERROR, TAG, "SendKeepAliveResponse failed with result %u", ret); + } + + OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest OUT"); + return ret; } -OCStackResult HandleKeepAliveGETRequest(const CAEndpoint_t* endPoint, - const CARequestInfo_t* requestInfo) +OCStackResult OCSendKeepAliveResponse(OCServerRequest *request, + OCEntityHandlerResult result) { - VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM); + + OIC_LOG_V(DEBUG, TAG, "Send KeepAlive response with entity result[%d]", result); + + // Convert OCDevAddr to CAEndpoint_t. + CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER}; + CopyDevAddrToEndpoint(&request->devAddr, &endpoint); - OIC_LOG_V(DEBUG, TAG, "Find Ping resource [%s]", requestInfo->info.resourceUri); + oc_mutex_lock(g_mutexObjectList); + KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint); + int64_t interval = (entry) ? entry->interval : 0; + oc_mutex_unlock(g_mutexObjectList); + + // Create KeepAlive payload to send response message. + OCRepPayload *payload = OCCreateKeepAlivePayload(interval); + + // Add resource type/interface name to payload for GET request. + if (OC_REST_GET == request->method && OC_EH_OK == result) + { + OCAddResourceTypeNameToPayload(payload); + OCAddResourceInterfaceNameToPayload(payload); + } + + OCEntityHandlerResponse ehResponse = { .ehResult = result, + .payload = (OCPayload*) payload, + .requestHandle = request->requestId, + .resourceHandle = g_keepAliveHandle }; + OICStrcpy(ehResponse.resourceUri, sizeof(ehResponse.resourceUri), KEEPALIVE_RESOURCE_URI); + + // Send response message. + return OCDoResponse(&ehResponse); +} - CAResponseResult_t result = CA_CONTENT; - OCResource *resourcePtr = FindResourceByUri(requestInfo->info.resourceUri); +OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request, + const OCResource *resource) +{ + VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR); + VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR); + + OIC_LOG_V(DEBUG, TAG, "Find Ping resource [%s]", request->resourceUrl); + + OCResource *resourcePtr = FindResourceByUri(request->resourceUrl); if (!resourcePtr) { // Resource URL not specified - OIC_LOG_V(DEBUG, TAG, "There is no Ping resource [%s]", requestInfo->info.resourceUri); - result = CA_NOT_FOUND; + OIC_LOG_V(DEBUG, TAG, "There is no Ping resource [%s]", request->resourceUrl); + return OC_EH_RESOURCE_NOT_FOUND; } - SendDirectStackResponse(endPoint, requestInfo->info.messageId, result, requestInfo->info.type, - requestInfo->info.numOptions, requestInfo->info.options, - requestInfo->info.token, requestInfo->info.tokenLength, - requestInfo->info.resourceUri, CA_RESPONSE_DATA); - - return OC_STACK_OK; + return OC_EH_OK; } -OCStackResult HandleKeepAlivePUTRequest(const CAEndpoint_t* endPoint, - const CARequestInfo_t* requestInfo) +OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request, + const OCResource *resource) { - VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR); + VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR); + + int64_t interval = 0; + OCPayload *ocPayload = NULL; + OCStackResult result = OCParsePayload(&ocPayload, PAYLOAD_TYPE_REPRESENTATION, + request->payload, request->payloadSize); + if (OC_STACK_OK != result) + { + OIC_LOG(ERROR, TAG, "Representation parse failed"); + return OC_EH_ERROR; + } + bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) ocPayload, INTERVAL, &interval); + if (!findValue) + { + OIC_LOG(ERROR, TAG, "Can't find the time interval property"); + OCPayloadDestroy(ocPayload); + return OC_EH_BAD_REQ; + } // Get entry from KeepAlive table. - uint32_t index = 0; - KeepAliveEntry_t *entry = GetEntryFromEndpoint(endPoint, &index); + CAEndpoint_t endpoint = { .adapter = OC_ADAPTER_TCP }; + CopyDevAddrToEndpoint(&request->devAddr, &endpoint); + + oc_mutex_lock(g_mutexObjectList); + KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint); if (!entry) { OIC_LOG(ERROR, TAG, "Received the first keepalive message from client"); - entry = AddKeepAliveEntry(endPoint, OC_SERVER, NULL); + entry = OCAddKeepAliveEntry(&endpoint, OC_SERVER, 0); if (!entry) { + oc_mutex_unlock(g_mutexObjectList); OIC_LOG(ERROR, TAG, "Failed to add new keepalive entry"); - return OC_STACK_ERROR; + OCPayloadDestroy(ocPayload); + return OC_EH_INTERNAL_SERVER_ERROR; } } - OCPayload *ocPayload = NULL; - OCParsePayload(&ocPayload, PAYLOAD_TYPE_REPRESENTATION, - requestInfo->info.payload, requestInfo->info.payloadSize); - OCRepPayload *repPayload = (OCRepPayload *)ocPayload; - - int64_t interval = 0; - OCRepPayloadGetPropInt(repPayload, INTERVAL, &interval); entry->interval = interval; - OIC_LOG_V(DEBUG, TAG, "Received interval is [%d]", entry->interval); + OIC_LOG_V(DEBUG, TAG, "Received interval is [%" PRId64 "]", entry->interval); entry->timeStamp = OICGetCurrentTime(TIME_IN_US); + oc_mutex_unlock(g_mutexObjectList); OCPayloadDestroy(ocPayload); - - // Send response message. - return SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_CHANGED, - requestInfo->info.type, requestInfo->info.numOptions, - requestInfo->info.options, requestInfo->info.token, - requestInfo->info.tokenLength, requestInfo->info.resourceUri, - CA_RESPONSE_DATA); + return OC_EH_OK; } -OCStackResult HandleKeepAliveResponse(const CAEndpoint_t *endPoint, - OCStackResult responseCode, - const OCRepPayload *respPayload) +#ifdef WITH_PROCESS_EVENT +void OCProcessKeepAlive(uint32_t *nextEventTime) +#else // WITH_PROCESS_EVENT +void OCProcessKeepAlive() +#endif // !WITH_PROCESS_EVENT { - VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM); - - OIC_LOG(DEBUG, TAG, "HandleKeepAliveResponse IN"); - - // Get entry from KeepAlive table. - uint32_t index = 0; - KeepAliveEntry_t *entry = GetEntryFromEndpoint(endPoint, &index); - if (!entry) + oc_mutex_lock(g_mutexObjectList); + KeepAliveEntry_t *entry = NULL; + KeepAliveEntry_t *tmp = NULL; + LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp) { - // Receive response message about find /oic/ping request. - OIC_LOG(ERROR, TAG, "There is no connection info in KeepAlive table"); - - if (OC_STACK_NO_RESOURCE == responseCode) +#ifdef WITH_PROCESS_EVENT + uint64_t nextPingMicroSeconds = UINT64_MAX; +#endif // WITH_PROCESS_EVENT + if (entry) { - OIC_LOG(ERROR, TAG, "Server doesn't have a ping resource"); - return OC_STACK_ERROR; - } - else if (OC_STACK_OK == responseCode) - { - int64_t *recvInterval = NULL; - size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 0 }; - OCRepPayloadGetIntArray(respPayload, INTERVAL_ARRAY, &recvInterval, dimensions); - size_t serverIntervalSize = calcDimTotal(dimensions); - - entry = AddKeepAliveEntry(endPoint, OC_CLIENT, recvInterval); - if (!entry) + uint64_t currentTime = OICGetCurrentTime(TIME_IN_US); + if (OC_CLIENT == entry->mode) { - OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry"); - return OC_STACK_ERROR; + if (entry->sentPingMsg) + { + /* + * If an OIC Client does not receive the response within 1 minutes, + * terminate the connection. + * In this case the timeStamp means last time sent ping message. + */ + if ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp) + { + OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes."); + + /* TCPDisconnectSession should be invoked depending on the result from client callback */ + if (OCSendDisconnectMessage(entry) == OC_STACK_CONTINUE) + { + // Set sentPingMsg values with false. + entry->sentPingMsg = false; + entry->handle = NULL; + } + } +#ifdef WITH_PROCESS_EVENT + else + { + nextPingMicroSeconds = (KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) - + (currentTime - entry->timeStamp); + } +#endif // WITH_PROCESS_EVENT + } } - - if (serverIntervalSize) - { - // update interval size with received size of server. - entry->intervalSize = serverIntervalSize; - } - - // Send first ping message - return SendPingMessage(entry); - } - } - else - { - // Set sentPingMsg values with false. - entry->sentPingMsg = false; - } - - OIC_LOG(DEBUG, TAG, "HandleKeepAliveResponse OUT"); - return OC_STACK_OK; -} - -void ProcessKeepAlive() -{ - if (!g_isKeepAliveInitialized) - { - OIC_LOG(ERROR, TAG, "KeepAlive not initialized"); - return; - } - - uint32_t len = u_arraylist_length(g_keepAliveConnectionTable); - - for (uint32_t i = 0; i < len; i++) - { - KeepAliveEntry_t *entry = (KeepAliveEntry_t *)u_arraylist_get(g_keepAliveConnectionTable, - i); - if (NULL == entry) - { - continue; - } - - uint64_t currentTime = OICGetCurrentTime(TIME_IN_US); - if (OC_CLIENT == entry->mode) - { - if (entry->sentPingMsg) + else if (OC_SERVER == entry->mode) { /* - * If an OIC Client does not receive the response within 1 minutes, - * terminate the connection. - * In this case the timeStamp means last time sent ping message. + * If an OIC Server does not receive a PUT/POST request to ping resource + * within the specified interval time, terminate the connection. + * In this case the timeStamp means last time received ping message. */ - if ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp) + if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) + <= currentTime - entry->timeStamp) { - OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes."); - - // Send message to disconnect session. - SendDisconnectMessage(entry); + OIC_LOG(DEBUG, TAG, "Server does not receive a PUT/POST request."); + OCSendDisconnectMessage(entry); + } +#ifdef WITH_PROCESS_EVENT + else + { + nextPingMicroSeconds = + (entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) - + (currentTime - entry->timeStamp); } +#endif // WITH_PROCESS_EVENT } - else + +#ifdef WITH_PROCESS_EVENT + if (nextEventTime && (nextPingMicroSeconds < UINT64_MAX)) { - if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) - <= currentTime - entry->timeStamp) + uint32_t nextPingMiliSeconds = (uint32_t)(nextPingMicroSeconds / US_PER_MS); + uint32_t nextPingMicroRemain = (uint32_t)(nextPingMicroSeconds % US_PER_MS); + if (nextPingMicroRemain > 0) { - // Increase interval value. - IncreaseInterval(entry); + nextPingMiliSeconds += 1; // To round up the remaining microsecond. + } - OCStackResult result = SendPingMessage(entry); - if (OC_STACK_OK != result) - { - OIC_LOG(ERROR, TAG, "Failed to send ping request"); - continue; - } + if (nextPingMiliSeconds < *nextEventTime) + { + *nextEventTime = nextPingMiliSeconds; } } - } - else if (OC_SERVER == entry->mode) - { - /* - * If an OIC Server does not receive a PUT request to ping resource - * within the specified interval time, terminate the connection. - * In this case the timeStamp means last time received ping message. - */ - if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) - <= currentTime - entry->timeStamp) - { - OIC_LOG(DEBUG, TAG, "Server does not receive a PUT request."); - SendDisconnectMessage(entry); +#endif // WITH_PROCESS_EVENT } - } } + oc_mutex_unlock(g_mutexObjectList); } -void IncreaseInterval(KeepAliveEntry_t *entry) +OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry) { - VERIFY_NON_NULL_NR(entry, FATAL); + VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM); - OIC_LOG_V(DEBUG, TAG, "Total interval counts: %d", entry->intervalSize); - if (entry->intervalSize > entry->currIndex + 1) + // notify application that a client does not receive a response. + ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL); + if (cbNode) { - entry->currIndex++; - entry->interval = entry->intervalInfo[entry->currIndex]; - OIC_LOG_V(DEBUG, TAG, "increase interval value [%d]", entry->interval); + OCClientResponse response = { .devAddr = { .adapter = OC_DEFAULT_ADAPTER } }; + CopyEndpointToDevAddr(&entry->remoteAddr, &response.devAddr); + FixUpClientResponse(&response); + response.resourceUri = cbNode->requestUri; + response.result = OC_STACK_TIMEOUT; + + /* TCPDisconnectSession should be invoked depending on the result from client callback */ + if (cbNode->callBack(cbNode->context, cbNode->handle, &response) == OC_STACK_KEEP_TRANSACTION) + { + return OC_STACK_CONTINUE; + } + + FindAndDeleteClientCB(cbNode); } -} -OCStackResult SendDisconnectMessage(const KeepAliveEntry_t *entry) -{ - VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM); + CAEndpoint_t endpoint = entry->remoteAddr; + if (OC_STACK_OK != OCRemoveKeepAliveEntry(&endpoint)) + { + OIC_LOG(ERROR, TAG, "OCRemoveKeepAliveEntry is failed"); + return OC_STACK_ERROR; + } /* * Send empty message to disconnect a connection. * If CA get the empty message from RI, CA will disconnect a connection. */ - CARequestInfo_t requestInfo = { .method = CA_PUT }; - CAResult_t result = CASendRequest(&entry->remoteAddr, &requestInfo); - return CAResultToOCResult(result); -} - -OCStackResult SendPingMessage(KeepAliveEntry_t *entry) -{ - VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM); - - // Send ping message. - OCCallbackData pingData = { .context = NULL, .cb = PingRequestCallback }; - OCDevAddr devAddr = { .adapter = OC_ADAPTER_TCP }; - CopyEndpointToDevAddr(&(entry->remoteAddr), &devAddr); - - OCRepPayload *payload = OCRepPayloadCreate(); - if (!payload) + CAResult_t result = CAUtilTCPDisconnectSession(endpoint.addr, endpoint.port, endpoint.flags); + if (OC_STACK_OK != CAResultToOCResult(result)) { - OIC_LOG(ERROR, TAG, "Failed to allocate Payload"); - return OC_STACK_ERROR; + OIC_LOG(ERROR, TAG, "Failed to disconnect session"); } - payload->base.type = PAYLOAD_TYPE_REPRESENTATION; - OCRepPayloadSetPropInt(payload, INTERVAL, entry->interval); - - OCDoResource(NULL, OC_REST_PUT, KEEPALIVE_RESOURCE_URI, &devAddr, - (OCPayload *) payload, CT_ADAPTER_TCP, OC_LOW_QOS, &pingData, NULL, 0); - - // Update timeStamp with time sent ping message for next ping message. - entry->timeStamp = OICGetCurrentTime(TIME_IN_US); - entry->sentPingMsg = true; - - OIC_LOG_V(DEBUG, TAG, "Client sent ping message, interval [%d]", entry->interval); - return OC_STACK_OK; -} - -OCStackApplicationResult PingRequestCallback(void* ctx, OCDoHandle handle, - OCClientResponse *clientResponse) -{ - OIC_LOG(DEBUG, TAG, "PingRequestCallback IN"); - (void) ctx; - (void) handle; - if (NULL == clientResponse) - { - OIC_LOG(ERROR, TAG, "clientResponse is NULL"); - return OC_STACK_KEEP_TRANSACTION; - } - - CAEndpoint_t endpoint = { .adapter = CA_ADAPTER_TCP }; - CopyDevAddrToEndpoint(&(clientResponse->devAddr), &endpoint); - - HandleKeepAliveResponse(&endpoint, clientResponse->result, - (OCRepPayload *)clientResponse->payload); - - OIC_LOG(DEBUG, TAG, "PingRequestCallback OUT"); - return OC_STACK_KEEP_TRANSACTION; + return CAResultToOCResult(result); } -KeepAliveEntry_t *GetEntryFromEndpoint(const CAEndpoint_t *endpoint, uint32_t *index) +KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint) { - if (!g_keepAliveConnectionTable) + KeepAliveEntry_t *entry = NULL; + LL_FOREACH(g_keepAliveConnectionTable, entry) { - OIC_LOG(ERROR, TAG, "KeepAlive Table was not Created."); - return NULL; - } - - uint32_t len = u_arraylist_length(g_keepAliveConnectionTable); - - for (uint32_t i = 0; i < len; i++) - { - KeepAliveEntry_t *entry = (KeepAliveEntry_t *)u_arraylist_get(g_keepAliveConnectionTable, - i); - if (NULL == entry) + if (entry) { - continue; - } - - if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr)) - && (entry->remoteAddr.port == endpoint->port)) - { - OIC_LOG(DEBUG, TAG, "Connection Info found in KeepAlive table"); - *index = i; - return entry; + if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr)) + && (entry->remoteAddr.port == endpoint->port)) + { + OIC_LOG(DEBUG, TAG, "Connection Info found in KeepAlive table"); + return entry; + } } } return NULL; } -KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, - int64_t *intervalInfo) +KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, + int64_t interval) { if (!endpoint) { @@ -646,12 +776,6 @@ KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, return NULL; } - if (!g_keepAliveConnectionTable) - { - OIC_LOG(ERROR, TAG, "KeepAlive Table was not Created."); - return NULL; - } - KeepAliveEntry_t *entry = (KeepAliveEntry_t *) OICCalloc(1, sizeof(KeepAliveEntry_t)); if (NULL == entry) { @@ -666,86 +790,176 @@ KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode, entry->remoteAddr.ifindex = endpoint->ifindex; entry->remoteAddr.port = endpoint->port; strncpy(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr)); + entry->interval = interval; - entry->intervalSize = DEFAULT_INTERVAL_COUNT; - entry->intervalInfo = intervalInfo; - if (!entry->intervalInfo) - { - entry->intervalInfo = (int64_t*) OICMalloc(entry->intervalSize * sizeof(int64_t)); - for (size_t i = 0; i < entry->intervalSize; i++) - { - entry->intervalInfo[i] = KEEPALIVE_MIN_INTERVAL << i; - } - } - entry->interval = entry->intervalInfo[0]; - - bool result = u_arraylist_add(g_keepAliveConnectionTable, (void *)entry); - if (!result) - { - OIC_LOG(ERROR, TAG, "Adding node to head failed"); - OICFree(entry->intervalInfo); - OICFree(entry); - return NULL; - } - + LL_APPEND(g_keepAliveConnectionTable, entry); +#ifdef WITH_PROCESS_EVENT + OCSendProcessEventSignal(); +#endif // WITH_PROCESS_EVENT return entry; } -OCStackResult RemoveKeepAliveEntry(const CAEndpoint_t *endpoint) +OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint) { + OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry IN"); + VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM); - uint32_t index = 0; - KeepAliveEntry_t *entry = GetEntryFromEndpoint(endpoint, &index); - if (!entry) + KeepAliveEntry_t *entry = NULL; + KeepAliveEntry_t *tmp = NULL; + LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp) { - OIC_LOG(ERROR, TAG, "There is no entry in keepalive table."); - return OC_STACK_ERROR; - } + if (entry) + { + if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr)) + && (entry->remoteAddr.port == endpoint->port)) + { + OIC_LOG_V(DEBUG, TAG, "Remove Connection Info from KeepAlive table, " + "remote addr=%s port:%d", entry->remoteAddr.addr, + entry->remoteAddr.port); - KeepAliveEntry_t *removedEntry = (KeepAliveEntry_t *) - u_arraylist_remove(g_keepAliveConnectionTable, index); - if (NULL == removedEntry) - { - OIC_LOG(ERROR, TAG, "Removed Entry is NULL"); - return OC_STACK_ERROR; + LL_DELETE(g_keepAliveConnectionTable, entry); + OICFree(entry); + } + } } - OIC_LOG_V(DEBUG, TAG, "Remove Connection Info from KeepAlive table, " - "remote addr=%s port:%d", removedEntry->remoteAddr.addr, - removedEntry->remoteAddr.port); - - OICFree(entry->intervalInfo); - OICFree(removedEntry); - + OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry OUT"); return OC_STACK_OK; } -void HandleKeepAliveConnCB(const CAEndpoint_t *endpoint, bool isConnected) +void OCHandleKeepAliveConnCB(const CAEndpoint_t *endpoint, bool isConnected, bool isClient) { + (void) isClient; VERIFY_NON_NULL_NR(endpoint, FATAL); if (isConnected) { OIC_LOG(DEBUG, TAG, "Received the connected device information from CA"); - - // Send discover message to find ping resource - OCCallbackData pingData = {.context = NULL, .cb = PingRequestCallback }; - OCDevAddr devAddr = { .adapter = OC_ADAPTER_TCP }; - CopyEndpointToDevAddr(endpoint, &devAddr); - - OCDoResource(NULL, OC_REST_DISCOVER, KEEPALIVE_RESOURCE_URI, &devAddr, NULL, - CT_ADAPTER_TCP, OC_HIGH_QOS, &pingData, NULL, 0); } else { OIC_LOG(DEBUG, TAG, "Received the disconnected device information from CA"); - OCStackResult result = RemoveKeepAliveEntry(endpoint); - if(result != OC_STACK_OK) + // Do nothing because callback will be removed after one min. + /* + // notify application that the session is disconnected. + oc_mutex_lock(g_mutexObjectList); + KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endpoint); + if (entry) { - OIC_LOG(ERROR, TAG, "Failed to remove entry"); - return; + ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL); + if (cbNode) + { + OCClientResponse response = { .devAddr = { .adapter = OC_ADAPTER_TCP } }; + CopyEndpointToDevAddr(&entry->remoteAddr, &response.devAddr); + FixUpClientResponse(&response); + response.resourceUri = cbNode->requestUri; + response.result = OC_STACK_COMM_ERROR; + + cbNode->callBack(cbNode->context, cbNode->handle, &response); + FindAndDeleteClientCB(cbNode); + } + OCRemoveKeepAliveEntry(endpoint); } + oc_mutex_unlock(g_mutexObjectList); + */ } } + +OCRepPayload *OCCreateKeepAlivePayload(int64_t interval) +{ + OIC_LOG_V(DEBUG, TAG, "Create KeepAlive Payload, interval is [%" PRId64 "]", interval); + + OCRepPayload *payload = OCRepPayloadCreate(); + if (!payload) + { + OIC_LOG(ERROR, TAG, "Failed to allocate Payload"); + return NULL; + } + payload->base.type = PAYLOAD_TYPE_REPRESENTATION; + OCRepPayloadSetPropInt(payload, INTERVAL, interval); + + return payload; +} + +OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload) +{ + uint8_t numElement = 0; + OCStackResult res = OCGetNumberOfResourceTypes(g_keepAliveHandle, &numElement); + if (OC_STACK_OK == res) + { + size_t rtDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0}; + char **rt = (char **)OICMalloc(sizeof(char *) * numElement); + if (!rt) + { + OIC_LOG(ERROR, TAG, "Could not allocate memory for rf"); + return OC_STACK_NO_MEMORY; + } + for (uint8_t i = 0; i < numElement; ++i) + { + const char *value = OCGetResourceTypeName(g_keepAliveHandle, i); + OIC_LOG_V(DEBUG, TAG, "value: %s", value); + rt[i] = OICStrdup(value); + if (NULL == rt[i]) + { + OIC_LOG_V(ERROR, TAG, "Creating duplicate string for rt failed!"); + for (uint8_t j = 0; j < i; ++j) + { + OICFree(rt[j]); + } + OICFree(rt); + return OC_STACK_NO_MEMORY; + } + } + OCRepPayloadSetStringArray(payload, OC_RSRVD_RESOURCE_TYPE, (const char **) rt, rtDim); + for (uint8_t i = 0; i < numElement; ++i) + { + OICFree(rt[i]); + } + OICFree(rt); + } + + return res; +} + +OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload) +{ + uint8_t numElement = 0; + OCStackResult res = OCGetNumberOfResourceInterfaces(g_keepAliveHandle, &numElement); + if (OC_STACK_OK == res) + { + size_t ifDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0}; + char **itf = (char **)OICMalloc(sizeof(char *) * numElement); + if (!itf) + { + OIC_LOG(ERROR, TAG, "Could not allocate memory for itf"); + return OC_STACK_NO_MEMORY; + } + + for (uint8_t i = 0; i < numElement; ++i) + { + const char *value = OCGetResourceInterfaceName(g_keepAliveHandle, i); + OIC_LOG_V(DEBUG, TAG, "value: %s", value); + itf[i] = OICStrdup(value); + if (NULL == itf[i]) + { + OIC_LOG_V(ERROR, TAG, "Creating duplicate string for itf failed!"); + for (uint8_t j = 0; j < i; ++j) + { + OICFree(itf[j]); + } + OICFree(itf); + return OC_STACK_NO_MEMORY; + } + } + OCRepPayloadSetStringArray(payload, OC_RSRVD_INTERFACE, (const char **) itf, ifDim); + for (uint8_t i = 0; i < numElement; ++i) + { + OICFree(itf[i]); + } + OICFree(itf); + } + + return res; +}