X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fstack%2Fsrc%2Foickeepalive.c;h=1340b705d9ba43967fbfdb6dd2b4a25866c36a50;hb=7f00f942c39b7bc27c7eeecf213a239c3fe4173c;hp=52dae8907823d123c6f15d941afa42e8d6d4e988;hpb=edcfc3d2329da7b914771c0dcff5f42c9b74fd93;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/stack/src/oickeepalive.c b/resource/csdk/stack/src/oickeepalive.c index 52dae89..1340b70 100644 --- 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. @@ -62,22 +66,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 +76,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,55 +83,44 @@ 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. */ - int64_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. @@ -156,8 +128,8 @@ static OCStackResult DeleteKeepAliveResource(); * @param[in] resource Resource handle used for sending the response. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCEntityHandlerResult HandleKeepAliveGETRequest(OCServerRequest *request, - const OCResource *resource); +static OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request, + const OCResource *resource); /** * API to handle the PUT request received for a KeepAlive resource. @@ -165,39 +137,28 @@ static OCEntityHandlerResult HandleKeepAliveGETRequest(OCServerRequest *request, * @param[in] resource Resource handle used for sending the response. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCEntityHandlerResult HandleKeepAlivePOSTRequest(OCServerRequest *request, - const OCResource *resource); +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,14 +166,14 @@ 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 *CreateKeepAlivePayload(int64_t interval); +static OCRepPayload *OCCreateKeepAlivePayload(int64_t interval); /** * Send response to remote device. @@ -220,7 +181,7 @@ static OCRepPayload *CreateKeepAlivePayload(int64_t interval); * @param[in] result Result to be sent. * @return ::OC_STACK_OK or Appropriate error code. */ -static OCStackResult SendKeepAliveResponse(OCServerRequest *request, +static OCStackResult OCSendKeepAliveResponse(OCServerRequest *request, OCEntityHandlerResult result); /** @@ -228,87 +189,228 @@ static OCStackResult SendKeepAliveResponse(OCServerRequest *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 AddResourceTypeNameToPayload(OCRepPayload *payload); +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 AddResourceInterfaceNameToPayload(OCRepPayload *payload); +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) + { + oc_mutex_free(g_mutexObjectList); + g_mutexObjectList = NULL; + } + + if (OC_CLIENT != mode) { - g_keepAliveConnectionTable = u_arraylist_create(); - if (NULL == g_keepAliveConnectionTable) + // 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) + VERIFY_NON_NULL(remoteAddr, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK); + VERIFY_NON_NULL(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); return OC_STACK_ERROR; } - if (OC_CLIENT != mode) + VERIFY_NON_NULL(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); + 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); + 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); + 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; +} + +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"); - OIC_LOG(DEBUG, TAG, "TerminateKeepAlive OUT"); + // 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, @@ -329,13 +431,13 @@ OCStackResult CreateKeepAliveResource() 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); @@ -345,17 +447,17 @@ 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(OCServerRequest *request, - const OCResource *resource) +OCStackResult OCHandleKeepAliveRequest(OCServerRequest *request, + const OCResource *resource) { 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"); OCEntityHandlerResult result = OC_EH_ERROR; if (OC_REST_GET == request->method) @@ -366,7 +468,7 @@ OCStackResult HandleKeepAliveRequest(OCServerRequest *request, case OC_OBSERVE_REGISTER: case OC_OBSERVE_DEREGISTER: OIC_LOG(DEBUG, TAG, "Received GET request"); - result = HandleKeepAliveGETRequest(request, resource); + result = OCHandleKeepAliveGETRequest(request, resource); break; default: OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive"); @@ -376,7 +478,7 @@ OCStackResult HandleKeepAliveRequest(OCServerRequest *request, else if (OC_REST_PUT == request->method || OC_REST_POST == request->method) { OIC_LOG(DEBUG, TAG, "Received PUT/POST request"); - result = HandleKeepAlivePOSTRequest(request, resource); + result = OCHandleKeepAlivePOSTRequest(request, resource); } else { @@ -384,18 +486,18 @@ OCStackResult HandleKeepAliveRequest(OCServerRequest *request, result = OC_EH_UNAUTHORIZED_REQ; } - OCStackResult ret = SendKeepAliveResponse(request, 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, "HandleKeepAliveRequest OUT"); + OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest OUT"); return ret; } -OCStackResult SendKeepAliveResponse(OCServerRequest *request, - OCEntityHandlerResult result) +OCStackResult OCSendKeepAliveResponse(OCServerRequest *request, + OCEntityHandlerResult result) { VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM); @@ -405,18 +507,19 @@ OCStackResult SendKeepAliveResponse(OCServerRequest *request, CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER}; CopyDevAddrToEndpoint(&request->devAddr, &endpoint); - uint32_t index = 0; - KeepAliveEntry_t *entry = GetEntryFromEndpoint(&endpoint, &index); + 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 = CreateKeepAlivePayload(interval); + OCRepPayload *payload = OCCreateKeepAlivePayload(interval); // Add resource type/interface name to payload for GET request. if (OC_REST_GET == request->method && OC_EH_OK == result) { - AddResourceTypeNameToPayload(payload); - AddResourceInterfaceNameToPayload(payload); + OCAddResourceTypeNameToPayload(payload); + OCAddResourceInterfaceNameToPayload(payload); } OCEntityHandlerResponse ehResponse = { .ehResult = result, @@ -429,11 +532,11 @@ OCStackResult SendKeepAliveResponse(OCServerRequest *request, return OCDoResponse(&ehResponse); } -OCEntityHandlerResult HandleKeepAliveGETRequest(OCServerRequest *request, - const OCResource *resource) +OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request, + const OCResource *resource) { - VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(resource, FATAL, OC_STACK_INVALID_PARAM); + 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); @@ -448,290 +551,163 @@ OCEntityHandlerResult HandleKeepAliveGETRequest(OCServerRequest *request, return OC_EH_OK; } -OCEntityHandlerResult HandleKeepAlivePOSTRequest(OCServerRequest *request, - const OCResource *resource) +OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request, + const OCResource *resource) { - VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(resource, 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. - CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER }; + CAEndpoint_t endpoint = { .adapter = OC_ADAPTER_TCP }; CopyDevAddrToEndpoint(&request->devAddr, &endpoint); - uint32_t index = 0; - KeepAliveEntry_t *entry = GetEntryFromEndpoint(&endpoint, &index); + 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"); + OCPayloadDestroy(ocPayload); return OC_EH_INTERNAL_SERVER_ERROR; } } - OCPayload *ocPayload = NULL; - OCParsePayload(&ocPayload, PAYLOAD_TYPE_REPRESENTATION, - request->payload, request->payloadSize); - OCRepPayload *repPayload = (OCRepPayload *)ocPayload; - - int64_t interval = 0; - OCRepPayloadGetPropInt(repPayload, INTERVAL, &interval); entry->interval = 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); - return OC_EH_OK; } -OCStackResult HandleKeepAliveResponse(const CAEndpoint_t *endPoint, - OCStackResult responseCode, - const OCRepPayload *respPayload) +void OCProcessKeepAlive() { - 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) + 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) - { - OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry"); - return OC_STACK_ERROR; - } - - 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; - - // Check the received interval value. - int64_t interval = 0; - OCRepPayloadGetPropInt(respPayload, INTERVAL, &interval); - OIC_LOG_V(DEBUG, TAG, "Received interval is [%" PRId64 "]", entry->interval); - } - - 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) + uint64_t currentTime = OICGetCurrentTime(TIME_IN_US); + if (OC_CLIENT == 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 ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp) + if (entry->sentPingMsg) { - OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes."); + /* + * 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."); - // Send message to disconnect session. - SendDisconnectMessage(entry); + // Send message to disconnect session. + OCSendDisconnectMessage(entry); + } } } - else + else if (OC_SERVER == entry->mode) { + /* + * 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 ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp) { - // Increase interval value. - IncreaseInterval(entry); - - OCStackResult result = SendPingMessage(entry); - if (OC_STACK_OK != result) - { - OIC_LOG(ERROR, TAG, "Failed to send ping request"); - continue; - } + OIC_LOG(DEBUG, TAG, "Server does not receive a PUT/POST request."); + OCSendDisconnectMessage(entry); } } } - 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); - } - } } + 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: %zu", entry->intervalSize); - if (entry->intervalSize > (size_t)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 [%" PRId64 "]", 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; + + cbNode->callBack(cbNode->context, cbNode->handle, &response); + 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. */ - - OCStackResult result = RemoveKeepAliveEntry(&entry->remoteAddr); - if (result != OC_STACK_OK) + CAResult_t result = CAUtilTCPDisconnectSession(endpoint.addr, endpoint.port, endpoint.flags); + if (OC_STACK_OK != CAResultToOCResult(result)) { - return result; + OIC_LOG(ERROR, TAG, "Failed to disconnect session"); } - CARequestInfo_t requestInfo = { .method = CA_POST }; - 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 = CreateKeepAlivePayload(entry->interval); - OCStackResult result = OCDoResource(NULL, OC_REST_POST, KEEPALIVE_RESOURCE_URI, &devAddr, - (OCPayload *) payload, CT_ADAPTER_TCP, OC_LOW_QOS, - &pingData, NULL, 0); - if (OC_STACK_OK != result) - { - OIC_LOG(ERROR, TAG, "OCDoResource has failed"); - return result; - } - - // 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 [%" PRId64 "]", entry->interval); - - return OC_STACK_OK; -} - -OCStackApplicationResult PingRequestCallback(void* ctx, OCDoHandle handle, - OCClientResponse *clientResponse) -{ - (void) ctx; - (void) handle; - if (NULL == clientResponse) - { - OIC_LOG(ERROR, TAG, "clientResponse is NULL"); - return OC_STACK_DELETE_TRANSACTION; - } - - CAEndpoint_t endpoint = { .adapter = CA_ADAPTER_TCP }; - CopyDevAddrToEndpoint(&(clientResponse->devAddr), &endpoint); - - HandleKeepAliveResponse(&endpoint, clientResponse->result, - (OCRepPayload *)clientResponse->payload); - - return OC_STACK_DELETE_TRANSACTION; -} - -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) - { - continue; - } - - if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr)) - && (entry->remoteAddr.port == endpoint->port)) + if (entry) { - 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) { @@ -739,12 +715,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) { @@ -759,96 +729,81 @@ 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); 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); - - OCStackResult result = OCDoResource(NULL, OC_REST_DISCOVER, KEEPALIVE_RESOURCE_URI, - &devAddr, NULL, CT_ADAPTER_TCP, OC_HIGH_QOS, - &pingData, NULL, 0); - if (OC_STACK_OK != result) - { - OIC_LOG(ERROR, TAG, "OCDoResource has failed"); - return; - } } 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) { - 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 *CreateKeepAlivePayload(int64_t interval) +OCRepPayload *OCCreateKeepAlivePayload(int64_t interval) { OIC_LOG_V(DEBUG, TAG, "Create KeepAlive Payload, interval is [%" PRId64 "]", interval); @@ -864,7 +819,7 @@ OCRepPayload *CreateKeepAlivePayload(int64_t interval) return payload; } -OCStackResult AddResourceTypeNameToPayload(OCRepPayload *payload) +OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload) { uint8_t numElement = 0; OCStackResult res = OCGetNumberOfResourceTypes(g_keepAliveHandle, &numElement); @@ -872,6 +827,11 @@ OCStackResult AddResourceTypeNameToPayload(OCRepPayload *payload) { 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); @@ -899,7 +859,7 @@ OCStackResult AddResourceTypeNameToPayload(OCRepPayload *payload) return res; } -OCStackResult AddResourceInterfaceNameToPayload(OCRepPayload *payload) +OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload) { uint8_t numElement = 0; OCStackResult res = OCGetNumberOfResourceInterfaces(g_keepAliveHandle, &numElement); @@ -907,6 +867,12 @@ OCStackResult AddResourceInterfaceNameToPayload(OCRepPayload *payload) { 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);