1 /* ****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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 ******************************************************************/
21 #include "oickeepalive.h"
22 #include "oickeepaliveinternal.h"
26 #include "oic_malloc.h"
27 #include "oic_string.h"
31 #include "uarraylist.h"
32 #include "ocstackinternal.h"
33 #include "ocpayloadcbor.h"
34 #include "ocpayload.h"
35 #include "ocresourcehandler.h"
37 #include "cautilinterface.h"
38 #include <coap/utlist.h>
41 * Logging tag for module name.
43 #define TAG "OIC_RI_KEEPALIVE"
45 static const uint64_t USECS_PER_SEC = 1000000;
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
50 #define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
51 {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
53 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
54 TAG, #arg " is NULL"); return (retVal); } }
56 #define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OIC_LOG((logLevel), \
57 TAG, #arg " is NULL"); return; } }
59 #define VERIFY_NON_NULL_V(arg) { if (!arg) {OIC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
62 #define VERIFY_NON_NULL_EXIT(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
63 TAG, #arg " is NULL"); ret = retVal; goto exit; } }
66 * The KeepAlive table entries are removed
67 * if it can't receive response message within 60 seconds.
69 #define KEEPALIVE_RESPONSE_TIMEOUT_SEC 60
72 * KeepAlive key to parser Payload Table.
74 static const char INTERVAL[] = "in";
77 * KeepAlive key to get interval values from Payload Table.
79 static const char INTERVAL_ARRAY[] = "inarray";
82 * Pointer to handle of the newly created KeepAlive resource.
84 static OCResourceHandle g_keepAliveHandle = NULL;
87 * KeepAlive table which holds connection interval.
89 static struct KeepAliveEntry_t *g_keepAliveConnectionTable = NULL;
92 * Mutex to synchronize device object list.
94 static oc_mutex g_mutexObjectList = NULL;
97 * KeepAlive table entries.
99 typedef struct KeepAliveEntry_t
101 OCMode mode; /**< host Mode of Operation. */
102 CAEndpoint_t remoteAddr; /**< destination Address. */
103 int64_t interval; /**< time interval for KeepAlive. in seconds.*/
104 int32_t currIndex; /**< current interval value index. */
105 bool sentPingMsg; /**< if oic client already sent ping message. */
106 uint64_t timeStamp; /**< last sent or received ping message. in microseconds. */
107 OCDoHandle handle; /**< Invocation handle tied to original call to OCDoResource().*/
108 struct KeepAliveEntry_t *next; /**< Linked list; for multiple keepalive info list.*/
112 * Send disconnect message to remove connection.
114 static OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry);
117 * This function creates KeepAlive resource.
118 * @return ::OC_STACK_OK or Appropriate error code.
120 static OCStackResult OCCreateKeepAliveResource();
123 * This function deletes KeepAlive resource.
124 * @return ::OC_STACK_OK or Appropriate error code.
126 static OCStackResult OCDeleteKeepAliveResource();
129 * API to handle the GET request received for a KeepAlive resource.
130 * @param[in] request Request Received.
131 * @param[in] resource Resource handle used for sending the response.
132 * @return ::OC_STACK_OK or Appropriate error code.
134 static OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request,
135 const OCResource *resource);
138 * API to handle the PUT request received for a KeepAlive resource.
139 * @param[in] request Request Received.
140 * @param[in] resource Resource handle used for sending the response.
141 * @return ::OC_STACK_OK or Appropriate error code.
143 static OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request,
144 const OCResource *resource);
147 * Gets keepalive entry.
148 * @param[in] endpoint Remote Endpoint information (like ipaddress,
149 * port, reference uri and transport type) to
150 * which the ping message has to be sent.
151 * @return KeepAlive entry to send ping message.
153 static KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint);
156 * Add keepalive entry.
157 * @param[in] endpoint Remote Endpoint information (like ipaddress,
158 * port, reference uri and transport type).
159 * @param[in] mode Whether it is OIC Server or OIC Client.
160 * @param[in] interval Sent interval value to remote device.
161 * @return The KeepAlive entry added in KeepAlive Table.
163 KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode,
167 * Remove keepalive entry.
168 * @param[in] endpoint Remote Endpoint information (like ipaddress,
169 * port, reference uri and transport type).
170 * @return The KeepAlive entry removed in KeepAlive Table.
172 static OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint);
175 * Create KeepAlive paylaod to send message.
176 * @param[in] interval The interval value to be sent.
177 * @return Created representation payload.
179 static OCRepPayload *OCCreateKeepAlivePayload(int64_t interval);
182 * Send response to remote device.
183 * @param[in] request Request Received.
184 * @param[in] result Result to be sent.
185 * @return ::OC_STACK_OK or Appropriate error code.
187 static OCStackResult OCSendKeepAliveResponse(OCServerRequest *request,
188 OCEntityHandlerResult result);
191 * Add resource type name to payload for GET request.
192 * @param[in] payload Pointer to the payload to which byte string needs to be added.
193 * @return ::OC_STACK_OK or Appropriate error code.
195 static OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload);
198 * Add resource interface name to payload for GET request.
199 * @param[in] payload Pointer to the payload to which byte string needs to be added.
200 * @return ::OC_STACK_OK or Appropriate error code.
202 static OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload);
204 OCStackResult OCInitializeKeepAlive(OCMode mode)
206 OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive IN");
208 if (!g_mutexObjectList)
210 g_mutexObjectList = oc_mutex_new();
211 if (!g_mutexObjectList)
213 OIC_LOG(ERROR, TAG, "Failed to create mutex!");
214 return OC_STACK_ERROR;
218 if (OC_CLIENT != mode)
220 // Create the KeepAlive Resource[/oic/ping].
221 OCStackResult result = OCCreateKeepAliveResource();
222 if (OC_STACK_OK != result)
224 OIC_LOG_V(ERROR, TAG, "OCCreateKeepAliveResource failed[%d]", result);
229 OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive OUT");
233 OCStackResult OCTerminateKeepAlive(OCMode mode)
235 OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive IN");
237 if (g_mutexObjectList)
239 oc_mutex_free(g_mutexObjectList);
240 g_mutexObjectList = NULL;
243 if (OC_CLIENT != mode)
245 // Delete the KeepAlive Resource[/oic/ping].
246 OCStackResult result = OCDeleteKeepAliveResource();
247 if (OC_STACK_OK != result)
249 OIC_LOG_V(ERROR, TAG, "OCDeleteKeepAliveResource failed[%d]", result);
254 OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive OUT");
258 OCStackResult OCFindKeepAliveResource(OCDoHandle *handle, const char *remoteAddr,
259 OCCallbackData *cbData)
261 // Validate input parameters
262 VERIFY_NON_NULL(remoteAddr, FATAL, OC_STACK_INVALID_CALLBACK);
263 VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
264 VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
266 // Send discover message to find ping resource
267 char requestUri[MAX_QUERY_LENGTH] = { 0 };
268 snprintf(requestUri, MAX_QUERY_LENGTH, "%s%s", remoteAddr, KEEPALIVE_RESOURCE_URI);
269 OCStackResult result = OCDoResource(handle, OC_REST_DISCOVER, requestUri,
270 NULL, NULL, CT_ADAPTER_TCP, OC_HIGH_QOS,
272 if (OC_STACK_OK != result)
274 OIC_LOG(ERROR, TAG, "OCDoResource has failed");
279 OCStackResult OCSendKeepAliveRequest(OCDoHandle *handle, const char *remoteAddr,
280 OCPayload *payload, OCCallbackData *cbData)
283 VERIFY_NON_NULL_EXIT(remoteAddr, FATAL, OC_STACK_INVALID_PARAM);
284 VERIFY_NON_NULL_EXIT(cbData, FATAL, OC_STACK_INVALID_PARAM);
285 VERIFY_NON_NULL_EXIT(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
286 VERIFY_NON_NULL_EXIT(payload, FATAL, OC_STACK_INVALID_CALLBACK);
288 OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest IN");
290 // Parse the remote device address to send ping message.
291 OCDevAddr *devAddr = NULL;
292 char requestUri[MAX_QUERY_LENGTH] = { 0 };
293 snprintf(requestUri, MAX_QUERY_LENGTH, "%s%s", remoteAddr, KEEPALIVE_RESOURCE_URI);
294 OCStackResult result = ParseRequestUri(requestUri, OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS,
295 &devAddr, NULL, NULL);
296 if (result != OC_STACK_OK)
298 OIC_LOG_V(DEBUG, TAG, "Unable to parse uri: %s", remoteAddr);
299 OCPayloadDestroy(payload);
300 return OC_STACK_ERROR;
303 VERIFY_NON_NULL_EXIT(devAddr, FATAL, OC_STACK_INVALID_PARAM);
305 if (!(devAddr->adapter & OC_ADAPTER_TCP))
307 OIC_LOG_V(DEBUG, TAG, "Not supported connectivity type");
309 OCPayloadDestroy(payload);
310 return OC_STACK_ERROR;
313 // Get entry from KeepAlive table.
314 CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
315 CopyDevAddrToEndpoint(devAddr, &endpoint);
317 oc_mutex_lock(g_mutexObjectList);
318 KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
321 OIC_LOG(DEBUG, TAG, "There is no connection info in KeepAlive table");
323 entry = OCAddKeepAliveEntry(&endpoint, OC_CLIENT, 0);
326 oc_mutex_unlock(g_mutexObjectList);
327 OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry");
329 OCPayloadDestroy(payload);
330 return OC_STACK_ERROR;
334 // Get "in" value from payload.
335 int64_t interval = 0;
336 bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) payload, INTERVAL, &interval);
337 if (findValue && interval)
339 if (entry->sentPingMsg)
341 oc_mutex_unlock(g_mutexObjectList);
342 OIC_LOG(ERROR, TAG, "Already sent a ping request to remote device");
344 OCPayloadDestroy(payload);
345 return OC_STACK_ERROR;
347 entry->interval = interval;
348 OIC_LOG_V(DEBUG, TAG, "Send ping message with interval [%" PRId64 "]", entry->interval);
351 // Get "inarray" value from payload.
352 int64_t *inArray = NULL;
353 size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 0 };
354 OCRepPayloadGetIntArray((OCRepPayload *) payload, INTERVAL_ARRAY, &inArray, dimensions);
358 char newArray[MAX_URI_LENGTH] = { 0 };
359 size_t inArraySize = calcDimTotal(dimensions);
360 for (size_t i = 0; i < inArraySize; i++)
362 len += snprintf(newArray + len, MAX_URI_LENGTH, "% " PRId64, inArray[i]);
365 OIC_LOG_V(DEBUG, TAG, "Send update interval message with inarray [ %s]", newArray);
368 // Send keepalive message.
369 result = OCDoResource(&entry->handle, OC_REST_POST, KEEPALIVE_RESOURCE_URI,
370 devAddr, (OCPayload *) payload, CT_ADAPTER_TCP,
371 OC_HIGH_QOS, cbData, NULL, 0);
372 if (OC_STACK_OK != result)
374 oc_mutex_unlock(g_mutexObjectList);
375 OIC_LOG(ERROR, TAG, "OCDoResource has failed");
380 // Update timeStamp with time sent ping message for next ping message.
381 entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
382 entry->sentPingMsg = true;
385 *handle = entry->handle;
388 oc_mutex_unlock(g_mutexObjectList);
389 OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest OUT");
394 OCPayloadDestroy(payload);
398 OCStackResult OCHandleKeepAliveResponse(const CAEndpoint_t *endPoint, const OCPayload *payload)
401 VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
403 // Receive response message about post /oic/ping request.
404 OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse IN");
406 // Get entry from KeepAlive table.
407 oc_mutex_lock(g_mutexObjectList);
408 KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endPoint);
411 OIC_LOG_V(DEBUG, TAG, "Received response about interval [%" PRId64 "]", entry->interval);
413 // Set sentPingMsg values with false.
414 entry->sentPingMsg = false;
415 entry->handle = NULL;
418 oc_mutex_unlock(g_mutexObjectList);
419 OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse OUT");
423 OCStackResult OCCreateKeepAliveResource()
425 OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource IN");
427 // Create a KeepAlive resource
428 OCStackResult result = OCCreateResource(&g_keepAliveHandle,
429 KEEPALIVE_RESOURCE_TYPE_NAME,
430 OC_RSRVD_INTERFACE_DEFAULT,
431 KEEPALIVE_RESOURCE_URI,
435 if (OC_STACK_OK == result)
437 result = BindResourceInterfaceToResource((OCResource *) g_keepAliveHandle,
438 KEEPALIVE_RESOURCE_INTF_NAME);
441 if (OC_STACK_OK != result)
443 OIC_LOG_V(ERROR, TAG, "Create resource for KeepAlive failed[%d]", result);
446 OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource OUT");
450 OCStackResult OCDeleteKeepAliveResource()
452 OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource IN");
454 // Create a KeepAlive resource
455 OCStackResult result = OCDeleteResource(g_keepAliveHandle);
457 if (OC_STACK_OK != result)
459 OIC_LOG_V(ERROR, TAG, "Delete resource for KeepAlive failed[%d]", result);
462 OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource OUT");
466 OCStackResult OCHandleKeepAliveRequest(OCServerRequest *request,
467 const OCResource *resource)
469 VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM);
470 VERIFY_NON_NULL(resource, FATAL, OC_STACK_INVALID_PARAM);
472 OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest IN");
474 OCEntityHandlerResult result = OC_EH_ERROR;
475 if (OC_REST_GET == request->method)
477 switch ((OCObserveAction)request->observationOption)
479 case OC_OBSERVE_NO_OPTION:
480 case OC_OBSERVE_REGISTER:
481 case OC_OBSERVE_DEREGISTER:
482 OIC_LOG(DEBUG, TAG, "Received GET request");
483 result = OCHandleKeepAliveGETRequest(request, resource);
486 OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive");
487 result = OC_EH_UNAUTHORIZED_REQ;
490 else if (OC_REST_PUT == request->method || OC_REST_POST == request->method)
492 OIC_LOG(DEBUG, TAG, "Received PUT/POST request");
493 result = OCHandleKeepAlivePOSTRequest(request, resource);
497 OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive");
498 result = OC_EH_UNAUTHORIZED_REQ;
501 OCStackResult ret = OCSendKeepAliveResponse(request, result);
502 if (OC_STACK_OK != ret)
504 OIC_LOG_V(ERROR, TAG, "SendKeepAliveResponse failed with result %u", ret);
507 OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest OUT");
511 OCStackResult OCSendKeepAliveResponse(OCServerRequest *request,
512 OCEntityHandlerResult result)
514 VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM);
516 OIC_LOG_V(DEBUG, TAG, "Send KeepAlive response with entity result[%d]", result);
518 // Convert OCDevAddr to CAEndpoint_t.
519 CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER};
520 CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
522 oc_mutex_lock(g_mutexObjectList);
523 KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
524 int64_t interval = (entry) ? entry->interval : 0;
525 oc_mutex_unlock(g_mutexObjectList);
527 // Create KeepAlive payload to send response message.
528 OCRepPayload *payload = OCCreateKeepAlivePayload(interval);
530 // Add resource type/interface name to payload for GET request.
531 if (OC_REST_GET == request->method && OC_EH_OK == result)
533 OCAddResourceTypeNameToPayload(payload);
534 OCAddResourceInterfaceNameToPayload(payload);
537 OCEntityHandlerResponse ehResponse = { .ehResult = result,
538 .payload = (OCPayload*) payload,
539 .requestHandle = request->requestId,
540 .resourceHandle = g_keepAliveHandle };
541 OICStrcpy(ehResponse.resourceUri, sizeof(ehResponse.resourceUri), KEEPALIVE_RESOURCE_URI);
543 // Send response message.
544 return OCDoResponse(&ehResponse);
547 OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request,
548 const OCResource *resource)
550 VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR);
551 VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR);
553 OIC_LOG_V(DEBUG, TAG, "Find Ping resource [%s]", request->resourceUrl);
555 OCResource *resourcePtr = FindResourceByUri(request->resourceUrl);
558 // Resource URL not specified
559 OIC_LOG_V(DEBUG, TAG, "There is no Ping resource [%s]", request->resourceUrl);
560 return OC_EH_RESOURCE_NOT_FOUND;
566 OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request,
567 const OCResource *resource)
569 VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR);
570 VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR);
572 int64_t interval = 0;
573 OCPayload *ocPayload = NULL;
574 OCStackResult result = OCParsePayload(&ocPayload, PAYLOAD_TYPE_REPRESENTATION,
575 request->payload, request->payloadSize);
576 if (OC_STACK_OK != result)
578 OIC_LOG(ERROR, TAG, "Representation parse failed");
581 bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) ocPayload, INTERVAL, &interval);
584 OIC_LOG(ERROR, TAG, "Can't find the time interval property");
585 OCPayloadDestroy(ocPayload);
586 return OC_EH_BAD_REQ;
589 // Get entry from KeepAlive table.
590 CAEndpoint_t endpoint = { .adapter = OC_ADAPTER_TCP };
591 CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
593 oc_mutex_lock(g_mutexObjectList);
594 KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
597 OIC_LOG(ERROR, TAG, "Received the first keepalive message from client");
598 entry = OCAddKeepAliveEntry(&endpoint, OC_SERVER, 0);
601 oc_mutex_unlock(g_mutexObjectList);
602 OIC_LOG(ERROR, TAG, "Failed to add new keepalive entry");
603 OCPayloadDestroy(ocPayload);
604 return OC_EH_INTERNAL_SERVER_ERROR;
608 entry->interval = interval;
609 OIC_LOG_V(DEBUG, TAG, "Received interval is [%" PRId64 "]", entry->interval);
610 entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
611 oc_mutex_unlock(g_mutexObjectList);
613 OCPayloadDestroy(ocPayload);
617 #ifdef WITH_PROCESS_EVENT
618 void OCProcessKeepAlive(uint32_t *nextEventTime)
619 #else // WITH_PROCESS_EVENT
620 void OCProcessKeepAlive()
621 #endif // !WITH_PROCESS_EVENT
623 oc_mutex_lock(g_mutexObjectList);
624 KeepAliveEntry_t *entry = NULL;
625 KeepAliveEntry_t *tmp = NULL;
626 LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp)
628 #ifdef WITH_PROCESS_EVENT
629 uint64_t nextPingMicroSeconds = UINT64_MAX;
630 #endif // WITH_PROCESS_EVENT
633 uint64_t currentTime = OICGetCurrentTime(TIME_IN_US);
634 if (OC_CLIENT == entry->mode)
636 if (entry->sentPingMsg)
639 * If an OIC Client does not receive the response within 1 minutes,
640 * terminate the connection.
641 * In this case the timeStamp means last time sent ping message.
643 if ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp)
645 OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes.");
647 /* TCPDisconnectSession should be invoked depending on the result from client callback */
648 if (OCSendDisconnectMessage(entry) == OC_STACK_CONTINUE)
650 // Set sentPingMsg values with false.
651 entry->sentPingMsg = false;
652 entry->handle = NULL;
655 #ifdef WITH_PROCESS_EVENT
658 nextPingMicroSeconds = (KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) -
659 (currentTime - entry->timeStamp);
661 #endif // WITH_PROCESS_EVENT
664 else if (OC_SERVER == entry->mode)
667 * If an OIC Server does not receive a PUT/POST request to ping resource
668 * within the specified interval time, terminate the connection.
669 * In this case the timeStamp means last time received ping message.
671 if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC)
672 <= currentTime - entry->timeStamp)
674 OIC_LOG(DEBUG, TAG, "Server does not receive a PUT/POST request.");
675 OCSendDisconnectMessage(entry);
677 #ifdef WITH_PROCESS_EVENT
680 nextPingMicroSeconds =
681 (entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) -
682 (currentTime - entry->timeStamp);
684 #endif // WITH_PROCESS_EVENT
687 #ifdef WITH_PROCESS_EVENT
688 if (nextEventTime && (nextPingMicroSeconds < UINT64_MAX))
690 uint32_t nextPingMiliSeconds = (uint32_t)(nextPingMicroSeconds / US_PER_MS);
691 uint32_t nextPingMicroRemain = (uint32_t)(nextPingMicroSeconds % US_PER_MS);
692 if (nextPingMicroRemain > 0)
694 nextPingMiliSeconds += 1; // To round up the remaining microsecond.
697 if (nextPingMiliSeconds < *nextEventTime)
699 *nextEventTime = nextPingMiliSeconds;
702 #endif // WITH_PROCESS_EVENT
705 oc_mutex_unlock(g_mutexObjectList);
708 OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry)
710 VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM);
712 // notify application that a client does not receive a response.
713 ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL);
716 OCClientResponse response = { .devAddr = { .adapter = OC_DEFAULT_ADAPTER } };
717 CopyEndpointToDevAddr(&entry->remoteAddr, &response.devAddr);
718 FixUpClientResponse(&response);
719 response.resourceUri = cbNode->requestUri;
720 response.result = OC_STACK_TIMEOUT;
722 /* TCPDisconnectSession should be invoked depending on the result from client callback */
723 if (cbNode->callBack(cbNode->context, cbNode->handle, &response) == OC_STACK_KEEP_TRANSACTION)
725 return OC_STACK_CONTINUE;
728 FindAndDeleteClientCB(cbNode);
731 CAEndpoint_t endpoint = entry->remoteAddr;
732 if (OC_STACK_OK != OCRemoveKeepAliveEntry(&endpoint))
734 OIC_LOG(ERROR, TAG, "OCRemoveKeepAliveEntry is failed");
735 return OC_STACK_ERROR;
739 * Send empty message to disconnect a connection.
740 * If CA get the empty message from RI, CA will disconnect a connection.
742 CAResult_t result = CAUtilTCPDisconnectSession(endpoint.addr, endpoint.port, endpoint.flags);
743 if (OC_STACK_OK != CAResultToOCResult(result))
745 OIC_LOG(ERROR, TAG, "Failed to disconnect session");
748 return CAResultToOCResult(result);
751 KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint)
753 KeepAliveEntry_t *entry = NULL;
754 LL_FOREACH(g_keepAliveConnectionTable, entry)
758 if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
759 && (entry->remoteAddr.port == endpoint->port))
761 OIC_LOG(DEBUG, TAG, "Connection Info found in KeepAlive table");
770 KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode,
775 OIC_LOG(ERROR, TAG, "endpoint is NULL");
779 KeepAliveEntry_t *entry = (KeepAliveEntry_t *) OICCalloc(1, sizeof(KeepAliveEntry_t));
782 OIC_LOG(ERROR, TAG, "Failed to Calloc KeepAlive Entry");
787 entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
788 entry->remoteAddr.adapter = endpoint->adapter;
789 entry->remoteAddr.flags = endpoint->flags;
790 entry->remoteAddr.ifindex = endpoint->ifindex;
791 entry->remoteAddr.port = endpoint->port;
792 strncpy(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr));
793 entry->interval = interval;
795 LL_APPEND(g_keepAliveConnectionTable, entry);
796 #ifdef WITH_PROCESS_EVENT
797 OCSendProcessEventSignal();
798 #endif // WITH_PROCESS_EVENT
802 OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint)
804 OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry IN");
806 VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM);
808 KeepAliveEntry_t *entry = NULL;
809 KeepAliveEntry_t *tmp = NULL;
810 LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp)
814 if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
815 && (entry->remoteAddr.port == endpoint->port))
817 OIC_LOG_V(DEBUG, TAG, "Remove Connection Info from KeepAlive table, "
818 "remote addr=%s port:%d", entry->remoteAddr.addr,
819 entry->remoteAddr.port);
821 LL_DELETE(g_keepAliveConnectionTable, entry);
827 OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry OUT");
831 void OCHandleKeepAliveConnCB(const CAEndpoint_t *endpoint, bool isConnected, bool isClient)
834 VERIFY_NON_NULL_NR(endpoint, FATAL);
838 OIC_LOG(DEBUG, TAG, "Received the connected device information from CA");
842 OIC_LOG(DEBUG, TAG, "Received the disconnected device information from CA");
844 // Do nothing because callback will be removed after one min.
846 // notify application that the session is disconnected.
847 oc_mutex_lock(g_mutexObjectList);
848 KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endpoint);
851 ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL);
854 OCClientResponse response = { .devAddr = { .adapter = OC_ADAPTER_TCP } };
855 CopyEndpointToDevAddr(&entry->remoteAddr, &response.devAddr);
856 FixUpClientResponse(&response);
857 response.resourceUri = cbNode->requestUri;
858 response.result = OC_STACK_COMM_ERROR;
860 cbNode->callBack(cbNode->context, cbNode->handle, &response);
861 FindAndDeleteClientCB(cbNode);
863 OCRemoveKeepAliveEntry(endpoint);
865 oc_mutex_unlock(g_mutexObjectList);
870 OCRepPayload *OCCreateKeepAlivePayload(int64_t interval)
872 OIC_LOG_V(DEBUG, TAG, "Create KeepAlive Payload, interval is [%" PRId64 "]", interval);
874 OCRepPayload *payload = OCRepPayloadCreate();
877 OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
880 payload->base.type = PAYLOAD_TYPE_REPRESENTATION;
881 OCRepPayloadSetPropInt(payload, INTERVAL, interval);
886 OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload)
888 uint8_t numElement = 0;
889 OCStackResult res = OCGetNumberOfResourceTypes(g_keepAliveHandle, &numElement);
890 if (OC_STACK_OK == res)
892 size_t rtDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
893 char **rt = (char **)OICMalloc(sizeof(char *) * numElement);
896 OIC_LOG(ERROR, TAG, "Could not allocate memory for rf");
897 return OC_STACK_NO_MEMORY;
899 for (uint8_t i = 0; i < numElement; ++i)
901 const char *value = OCGetResourceTypeName(g_keepAliveHandle, i);
902 OIC_LOG_V(DEBUG, TAG, "value: %s", value);
903 rt[i] = OICStrdup(value);
906 OIC_LOG_V(ERROR, TAG, "Creating duplicate string for rt failed!");
907 for (uint8_t j = 0; j < i; ++j)
912 return OC_STACK_NO_MEMORY;
915 OCRepPayloadSetStringArray(payload, OC_RSRVD_RESOURCE_TYPE, (const char **) rt, rtDim);
916 for (uint8_t i = 0; i < numElement; ++i)
926 OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload)
928 uint8_t numElement = 0;
929 OCStackResult res = OCGetNumberOfResourceInterfaces(g_keepAliveHandle, &numElement);
930 if (OC_STACK_OK == res)
932 size_t ifDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
933 char **itf = (char **)OICMalloc(sizeof(char *) * numElement);
936 OIC_LOG(ERROR, TAG, "Could not allocate memory for itf");
937 return OC_STACK_NO_MEMORY;
940 for (uint8_t i = 0; i < numElement; ++i)
942 const char *value = OCGetResourceInterfaceName(g_keepAliveHandle, i);
943 OIC_LOG_V(DEBUG, TAG, "value: %s", value);
944 itf[i] = OICStrdup(value);
947 OIC_LOG_V(ERROR, TAG, "Creating duplicate string for itf failed!");
948 for (uint8_t j = 0; j < i; ++j)
953 return OC_STACK_NO_MEMORY;
956 OCRepPayloadSetStringArray(payload, OC_RSRVD_INTERFACE, (const char **) itf, ifDim);
957 for (uint8_t i = 0; i < numElement; ++i)