replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / csdk / stack / src / oickeepalive.c
1 /* ****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  ******************************************************************/
20
21 #include "oickeepalive.h"
22 #include "oickeepaliveinternal.h"
23
24 #include <stdio.h>
25 #include <string.h>
26 #include "oic_malloc.h"
27 #include "oic_string.h"
28 #include "oic_time.h"
29 #include "ocrandom.h"
30 #include "octhread.h"
31 #include "uarraylist.h"
32 #include "ocstackinternal.h"
33 #include "ocpayloadcbor.h"
34 #include "ocpayload.h"
35 #include "ocresourcehandler.h"
36 #include "logger.h"
37 #include "cautilinterface.h"
38 #include <coap/utlist.h>
39
40 /**
41  * Logging tag for module name.
42  */
43 #define TAG "OIC_RI_KEEPALIVE"
44
45 static const uint64_t USECS_PER_SEC = 1000000;
46
47 //-----------------------------------------------------------------------------
48 // Macros
49 //-----------------------------------------------------------------------------
50 #define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
51             {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
52
53 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
54              TAG, #arg " is NULL"); return (retVal); } }
55
56 #define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OIC_LOG((logLevel), \
57              TAG, #arg " is NULL"); return; } }
58
59 #define VERIFY_NON_NULL_V(arg) { if (!arg) {OIC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
60     goto exit;} }
61
62 /**
63  * The KeepAlive table entries are removed
64  * if it can't receive response message within 60 seconds.
65  */
66 #define KEEPALIVE_RESPONSE_TIMEOUT_SEC 60
67
68 /**
69  * KeepAlive key to parser Payload Table.
70  */
71 static const char INTERVAL[] = "in";
72
73 /**
74  * KeepAlive key to get interval values from Payload Table.
75  */
76 static const char INTERVAL_ARRAY[] = "inarray";
77
78 /**
79  * Pointer to handle of the newly created KeepAlive resource.
80  */
81 static OCResourceHandle g_keepAliveHandle = NULL;
82
83 /**
84  * KeepAlive table which holds connection interval.
85  */
86 static struct KeepAliveEntry_t *g_keepAliveConnectionTable = NULL;
87
88 /**
89  * Mutex to synchronize device object list.
90  */
91 static oc_mutex g_mutexObjectList = NULL;
92
93 /**
94  * KeepAlive table entries.
95  */
96 typedef struct KeepAliveEntry_t
97 {
98     OCMode mode;                    /**< host Mode of Operation. */
99     CAEndpoint_t remoteAddr;        /**< destination Address. */
100     int64_t interval;               /**< time interval for KeepAlive. in seconds.*/
101     int32_t currIndex;              /**< current interval value index. */
102     bool sentPingMsg;               /**< if oic client already sent ping message. */
103     uint64_t timeStamp;             /**< last sent or received ping message. in microseconds. */
104     OCDoHandle handle;              /**< Invocation handle tied to original call to OCDoResource().*/
105     struct KeepAliveEntry_t *next;  /**< Linked list; for multiple keepalive info list.*/
106 } KeepAliveEntry_t;
107
108 /**
109  * Send disconnect message to remove connection.
110  */
111 static OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry);
112
113 /**
114  * This function creates KeepAlive resource.
115  * @return  ::OC_STACK_OK or Appropriate error code.
116  */
117 static OCStackResult OCCreateKeepAliveResource();
118
119 /**
120  * This function deletes KeepAlive resource.
121  * @return  ::OC_STACK_OK or Appropriate error code.
122  */
123 static OCStackResult OCDeleteKeepAliveResource();
124
125 /**
126  * API to handle the GET request received for a KeepAlive resource.
127  * @param[in]   request     Request Received.
128  * @param[in]   resource    Resource handle used for sending the response.
129  * @return  ::OC_STACK_OK or Appropriate error code.
130  */
131 static OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request,
132                                                          const OCResource *resource);
133
134 /**
135  * API to handle the PUT request received for a KeepAlive resource.
136  * @param[in]   request     Request Received.
137  * @param[in]   resource    Resource handle used for sending the response.
138  * @return  ::OC_STACK_OK or Appropriate error code.
139  */
140 static OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request,
141                                                           const OCResource *resource);
142
143 /**
144  * Gets keepalive entry.
145  * @param[in]   endpoint    Remote Endpoint information (like ipaddress,
146  *                          port, reference uri and transport type) to
147  *                          which the ping message has to be sent.
148  * @return  KeepAlive entry to send ping message.
149  */
150 static KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint);
151
152 /**
153  * Add keepalive entry.
154  * @param[in]   endpoint    Remote Endpoint information (like ipaddress,
155  *                          port, reference uri and transport type).
156  * @param[in]   mode        Whether it is OIC Server or OIC Client.
157  * @param[in]   interval    Sent interval value to remote device.
158  * @return  The KeepAlive entry added in KeepAlive Table.
159  */
160 KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode,
161                                       int64_t interval);
162
163 /**
164  * Remove keepalive entry.
165  * @param[in]   endpoint    Remote Endpoint information (like ipaddress,
166  *                          port, reference uri and transport type).
167  * @return  The KeepAlive entry removed in KeepAlive Table.
168  */
169 static OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint);
170
171 /**
172  * Create KeepAlive paylaod to send message.
173  * @param[in]   interval   The interval value to be sent.
174  * @return  Created representation payload.
175  */
176 static OCRepPayload *OCCreateKeepAlivePayload(int64_t interval);
177
178 /**
179  * Send response to remote device.
180  * @param[in]   request     Request Received.
181  * @param[in]   result      Result to be sent.
182  * @return  ::OC_STACK_OK or Appropriate error code.
183  */
184 static OCStackResult OCSendKeepAliveResponse(OCServerRequest *request,
185                                            OCEntityHandlerResult result);
186
187 /**
188  * Add resource type name to payload for GET request.
189  * @param[in]   payload     Pointer to the payload to which byte string needs to be added.
190  * @return  ::OC_STACK_OK or Appropriate error code.
191  */
192 static OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload);
193
194 /**
195  * Add resource interface name to payload for GET request.
196  * @param[in]   payload     Pointer to the payload to which byte string needs to be added.
197  * @return  ::OC_STACK_OK or Appropriate error code.
198  */
199 static OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload);
200
201 OCStackResult OCInitializeKeepAlive(OCMode mode)
202 {
203     OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive IN");
204
205     if (!g_mutexObjectList)
206     {
207         g_mutexObjectList = oc_mutex_new();
208         if (!g_mutexObjectList)
209         {
210             OIC_LOG(ERROR, TAG, "Failed to create mutex!");
211             return OC_STACK_ERROR;
212         }
213     }
214
215     if (OC_CLIENT != mode)
216     {
217         // Create the KeepAlive Resource[/oic/ping].
218         OCStackResult result = OCCreateKeepAliveResource();
219         if (OC_STACK_OK != result)
220         {
221             OIC_LOG_V(ERROR, TAG, "OCCreateKeepAliveResource failed[%d]", result);
222             return result;
223         }
224     }
225
226     OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive OUT");
227     return OC_STACK_OK;
228 }
229
230 OCStackResult OCTerminateKeepAlive(OCMode mode)
231 {
232     OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive IN");
233
234     if (g_mutexObjectList)
235     {
236         oc_mutex_free(g_mutexObjectList);
237         g_mutexObjectList = NULL;
238     }
239
240     if (OC_CLIENT != mode)
241     {
242         // Delete the KeepAlive Resource[/oic/ping].
243         OCStackResult result = OCDeleteKeepAliveResource();
244         if (OC_STACK_OK != result)
245         {
246             OIC_LOG_V(ERROR, TAG, "OCDeleteKeepAliveResource failed[%d]", result);
247             return result;
248         }
249     }
250
251     OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive OUT");
252     return OC_STACK_OK;
253 }
254
255 OCStackResult OCFindKeepAliveResource(OCDoHandle *handle, const char *remoteAddr,
256                                       OCCallbackData *cbData)
257 {
258     // Validate input parameters
259     VERIFY_NON_NULL(remoteAddr, FATAL, OC_STACK_INVALID_CALLBACK);
260     VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
261     VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
262
263     // Send discover message to find ping resource
264     char requestUri[MAX_QUERY_LENGTH] = { 0 };
265     snprintf(requestUri, MAX_QUERY_LENGTH, "%s%s", remoteAddr, KEEPALIVE_RESOURCE_URI);
266     OCStackResult result = OCDoResource(handle, OC_REST_DISCOVER, requestUri,
267                                         NULL, NULL, CT_ADAPTER_TCP, OC_HIGH_QOS,
268                                         cbData, NULL, 0);
269     if (OC_STACK_OK != result)
270     {
271         OIC_LOG(ERROR, TAG, "OCDoResource has failed");
272     }
273     return result;
274 }
275
276 OCStackResult OCSendKeepAliveRequest(OCDoHandle *handle, const char *remoteAddr,
277                                      OCPayload *payload, OCCallbackData *cbData)
278 {
279     VERIFY_NON_NULL(remoteAddr, FATAL, OC_STACK_INVALID_PARAM);
280     VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_PARAM);
281     VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
282     VERIFY_NON_NULL(payload, FATAL, OC_STACK_INVALID_CALLBACK);
283
284     OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest IN");
285
286     // Parse the remote device address to send ping message.
287     OCDevAddr *devAddr = NULL;
288     char requestUri[MAX_QUERY_LENGTH] = { 0 };
289     snprintf(requestUri, MAX_QUERY_LENGTH, "%s%s", remoteAddr, KEEPALIVE_RESOURCE_URI);
290     OCStackResult result = ParseRequestUri(requestUri, OC_DEFAULT_ADAPTER, OC_DEFAULT_FLAGS,
291                                            &devAddr, NULL, NULL);
292     if (result != OC_STACK_OK)
293     {
294         OIC_LOG_V(DEBUG, TAG, "Unable to parse uri: %s", remoteAddr);
295         return OC_STACK_ERROR;
296     }
297
298     VERIFY_NON_NULL(devAddr, FATAL, OC_STACK_INVALID_PARAM);
299
300     if (!(devAddr->adapter & OC_ADAPTER_TCP))
301     {
302         OIC_LOG_V(DEBUG, TAG, "Not supported connectivity type");
303         OICFree(devAddr);
304         return OC_STACK_ERROR;
305     }
306
307     // Get entry from KeepAlive table.
308     CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
309     CopyDevAddrToEndpoint(devAddr, &endpoint);
310
311     oc_mutex_lock(g_mutexObjectList);
312     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
313     if (!entry)
314     {
315         OIC_LOG(DEBUG, TAG, "There is no connection info in KeepAlive table");
316
317         entry = OCAddKeepAliveEntry(&endpoint, OC_CLIENT, 0);
318         if (!entry)
319         {
320             oc_mutex_unlock(g_mutexObjectList);
321             OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry");
322             OICFree(devAddr);
323             return OC_STACK_ERROR;
324         }
325     }
326
327     // Get "in" value from payload.
328     int64_t interval = 0;
329     bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) payload, INTERVAL, &interval);
330     if (findValue && interval)
331     {
332         if (entry->sentPingMsg)
333         {
334             oc_mutex_unlock(g_mutexObjectList);
335             OIC_LOG(ERROR, TAG, "Already sent a ping request to remote device");
336             OICFree(devAddr);
337             return OC_STACK_ERROR;
338         }
339         entry->interval = interval;
340         OIC_LOG_V(DEBUG, TAG, "Send ping message with interval [%" PRId64 "]", entry->interval);
341     }
342
343     // Get "inarray" value from payload.
344     int64_t *inArray = NULL;
345     size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 0 };
346     OCRepPayloadGetIntArray((OCRepPayload *) payload, INTERVAL_ARRAY, &inArray, dimensions);
347     if (inArray)
348     {
349         uint8_t len = 0;
350         char newArray[MAX_URI_LENGTH] = { 0 };
351         size_t inArraySize = calcDimTotal(dimensions);
352         for (size_t i = 0; i < inArraySize; i++)
353         {
354             len += snprintf(newArray + len, MAX_URI_LENGTH, "% " PRId64, inArray[i]);
355         }
356         OICFree(inArray);
357         OIC_LOG_V(DEBUG, TAG, "Send update interval message with inarray [ %s]", newArray);
358     }
359
360     // Send keepalive message.
361     result = OCDoResource(&entry->handle, OC_REST_POST, KEEPALIVE_RESOURCE_URI,
362                           devAddr, (OCPayload *) payload, CT_ADAPTER_TCP,
363                           OC_HIGH_QOS, cbData, NULL, 0);
364     if (OC_STACK_OK != result)
365     {
366         oc_mutex_unlock(g_mutexObjectList);
367         OIC_LOG(ERROR, TAG, "OCDoResource has failed");
368         OICFree(devAddr);
369         return result;
370     }
371
372     // Update timeStamp with time sent ping message for next ping message.
373     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
374     entry->sentPingMsg = true;
375     if (handle)
376     {
377         *handle = entry->handle;
378     }
379
380     oc_mutex_unlock(g_mutexObjectList);
381     OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest OUT");
382     OICFree(devAddr);
383     return result;
384 }
385
386 OCStackResult OCHandleKeepAliveResponse(const CAEndpoint_t *endPoint, const OCPayload *payload)
387 {
388     (void) payload;
389     VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
390
391     // Receive response message about post /oic/ping request.
392     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse IN");
393
394     // Get entry from KeepAlive table.
395     oc_mutex_lock(g_mutexObjectList);
396     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endPoint);
397     if (entry)
398     {
399         OIC_LOG_V(DEBUG, TAG, "Received response about interval [%" PRId64 "]", entry->interval);
400
401         // Set sentPingMsg values with false.
402         entry->sentPingMsg = false;
403         entry->handle = NULL;
404     }
405
406     oc_mutex_unlock(g_mutexObjectList);
407     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse OUT");
408     return OC_STACK_OK;
409 }
410
411 OCStackResult OCCreateKeepAliveResource()
412 {
413     OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource IN");
414
415     // Create a KeepAlive resource
416     OCStackResult result = OCCreateResource(&g_keepAliveHandle,
417                                             KEEPALIVE_RESOURCE_TYPE_NAME,
418                                             OC_RSRVD_INTERFACE_DEFAULT,
419                                             KEEPALIVE_RESOURCE_URI,
420                                             NULL,
421                                             NULL,
422                                             OC_RES_PROP_NONE);
423     if (OC_STACK_OK == result)
424     {
425         result = BindResourceInterfaceToResource((OCResource *) g_keepAliveHandle,
426                                                  KEEPALIVE_RESOURCE_INTF_NAME);
427     }
428
429     if (OC_STACK_OK != result)
430     {
431         OIC_LOG_V(ERROR, TAG, "Create resource for KeepAlive failed[%d]", result);
432     }
433
434     OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource OUT");
435     return result;
436 }
437
438 OCStackResult OCDeleteKeepAliveResource()
439 {
440     OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource IN");
441
442     // Create a KeepAlive resource
443     OCStackResult result = OCDeleteResource(g_keepAliveHandle);
444
445     if (OC_STACK_OK != result)
446     {
447         OIC_LOG_V(ERROR, TAG, "Delete resource for KeepAlive failed[%d]", result);
448     }
449
450     OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource OUT");
451     return result;
452 }
453
454 OCStackResult OCHandleKeepAliveRequest(OCServerRequest *request,
455                                        const OCResource *resource)
456 {
457     VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM);
458     VERIFY_NON_NULL(resource, FATAL, OC_STACK_INVALID_PARAM);
459
460     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest IN");
461
462     OCEntityHandlerResult result = OC_EH_ERROR;
463     if (OC_REST_GET == request->method)
464     {
465         switch ((OCObserveAction)request->observationOption)
466         {
467             case OC_OBSERVE_NO_OPTION:
468             case OC_OBSERVE_REGISTER:
469             case OC_OBSERVE_DEREGISTER:
470                 OIC_LOG(DEBUG, TAG, "Received GET request");
471                 result = OCHandleKeepAliveGETRequest(request, resource);
472                 break;
473             default:
474                 OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive");
475                 result = OC_EH_UNAUTHORIZED_REQ;
476         }
477     }
478     else if (OC_REST_PUT == request->method || OC_REST_POST == request->method)
479     {
480         OIC_LOG(DEBUG, TAG, "Received PUT/POST request");
481         result = OCHandleKeepAlivePOSTRequest(request, resource);
482     }
483     else
484     {
485         OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive");
486         result = OC_EH_UNAUTHORIZED_REQ;
487     }
488
489     OCStackResult ret = OCSendKeepAliveResponse(request, result);
490     if (OC_STACK_OK != ret)
491     {
492         OIC_LOG_V(ERROR, TAG, "SendKeepAliveResponse failed with result %u", ret);
493     }
494
495     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest OUT");
496     return ret;
497 }
498
499 OCStackResult OCSendKeepAliveResponse(OCServerRequest *request,
500                                       OCEntityHandlerResult result)
501 {
502     VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM);
503
504     OIC_LOG_V(DEBUG, TAG, "Send KeepAlive response with entity result[%d]", result);
505
506     // Convert OCDevAddr to CAEndpoint_t.
507     CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER};
508     CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
509
510     oc_mutex_lock(g_mutexObjectList);
511     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
512     int64_t interval = (entry) ? entry->interval : 0;
513     oc_mutex_unlock(g_mutexObjectList);
514
515     // Create KeepAlive payload to send response message.
516     OCRepPayload *payload = OCCreateKeepAlivePayload(interval);
517
518     // Add resource type/interface name to payload for GET request.
519     if (OC_REST_GET == request->method && OC_EH_OK == result)
520     {
521         OCAddResourceTypeNameToPayload(payload);
522         OCAddResourceInterfaceNameToPayload(payload);
523     }
524
525     OCEntityHandlerResponse ehResponse = { .ehResult = result,
526                                            .payload = (OCPayload*) payload,
527                                            .requestHandle = request->requestId,
528                                            .resourceHandle = g_keepAliveHandle };
529     OICStrcpy(ehResponse.resourceUri, sizeof(ehResponse.resourceUri), KEEPALIVE_RESOURCE_URI);
530
531     // Send response message.
532     return OCDoResponse(&ehResponse);
533 }
534
535 OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request,
536                                                   const OCResource *resource)
537 {
538     VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR);
539     VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR);
540
541     OIC_LOG_V(DEBUG, TAG, "Find Ping resource [%s]", request->resourceUrl);
542
543     OCResource *resourcePtr = FindResourceByUri(request->resourceUrl);
544     if (!resourcePtr)
545     {
546         // Resource URL not specified
547         OIC_LOG_V(DEBUG, TAG, "There is no Ping resource [%s]", request->resourceUrl);
548         return OC_EH_RESOURCE_NOT_FOUND;
549     }
550
551     return OC_EH_OK;
552 }
553
554 OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request,
555                                                    const OCResource *resource)
556 {
557     VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR);
558     VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR);
559
560     int64_t interval = 0;
561     OCPayload *ocPayload = NULL;
562     OCStackResult result = OCParsePayload(&ocPayload, PAYLOAD_TYPE_REPRESENTATION,
563                                           request->payload, request->payloadSize);
564     if (OC_STACK_OK != result)
565     {
566         OIC_LOG(ERROR, TAG, "Representation parse failed");
567         return OC_EH_ERROR;
568     }
569     bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) ocPayload, INTERVAL, &interval);
570     if (!findValue)
571     {
572         OIC_LOG(ERROR, TAG, "Can't find the time interval property");
573         OCPayloadDestroy(ocPayload);
574         return OC_EH_BAD_REQ;
575     }
576
577     // Get entry from KeepAlive table.
578     CAEndpoint_t endpoint = { .adapter = OC_ADAPTER_TCP };
579     CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
580
581     oc_mutex_lock(g_mutexObjectList);
582     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
583     if (!entry)
584     {
585         OIC_LOG(ERROR, TAG, "Received the first keepalive message from client");
586         entry = OCAddKeepAliveEntry(&endpoint, OC_SERVER, 0);
587         if (!entry)
588         {
589             oc_mutex_unlock(g_mutexObjectList);
590             OIC_LOG(ERROR, TAG, "Failed to add new keepalive entry");
591             OCPayloadDestroy(ocPayload);
592             return OC_EH_INTERNAL_SERVER_ERROR;
593         }
594     }
595
596     entry->interval = interval;
597     OIC_LOG_V(DEBUG, TAG, "Received interval is [%" PRId64 "]", entry->interval);
598     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
599     oc_mutex_unlock(g_mutexObjectList);
600
601     OCPayloadDestroy(ocPayload);
602     return OC_EH_OK;
603 }
604
605 void OCProcessKeepAlive()
606 {
607     oc_mutex_lock(g_mutexObjectList);
608     KeepAliveEntry_t *entry = NULL;
609     KeepAliveEntry_t *tmp = NULL;
610     LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp)
611     {
612         if (entry)
613         {
614             uint64_t currentTime = OICGetCurrentTime(TIME_IN_US);
615             if (OC_CLIENT == entry->mode)
616             {
617                 if (entry->sentPingMsg)
618                 {
619                     /*
620                      * If an OIC Client does not receive the response within 1 minutes,
621                      * terminate the connection.
622                      * In this case the timeStamp means last time sent ping message.
623                      */
624                     if ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp)
625                     {
626                         OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes.");
627
628                         // Send message to disconnect session.
629                         OCSendDisconnectMessage(entry);
630                     }
631                 }
632             }
633             else if (OC_SERVER == entry->mode)
634             {
635                 /*
636                  * If an OIC Server does not receive a PUT/POST request to ping resource
637                  * within the specified interval time, terminate the connection.
638                  * In this case the timeStamp means last time received ping message.
639                  */
640                 if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC)
641                         <= currentTime - entry->timeStamp)
642                 {
643                     OIC_LOG(DEBUG, TAG, "Server does not receive a PUT/POST request.");
644                     OCSendDisconnectMessage(entry);
645                 }
646             }
647         }
648     }
649     oc_mutex_unlock(g_mutexObjectList);
650 }
651
652 OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry)
653 {
654     VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM);
655
656     // notify application that a client does not receive a response.
657     ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL);
658     if (cbNode)
659     {
660         OCClientResponse response = { .devAddr = { .adapter = OC_DEFAULT_ADAPTER } };
661         CopyEndpointToDevAddr(&entry->remoteAddr, &response.devAddr);
662         FixUpClientResponse(&response);
663         response.resourceUri = cbNode->requestUri;
664         response.result = OC_STACK_TIMEOUT;
665
666         cbNode->callBack(cbNode->context, cbNode->handle, &response);
667         FindAndDeleteClientCB(cbNode);
668     }
669
670     CAEndpoint_t endpoint = entry->remoteAddr;
671     if (OC_STACK_OK != OCRemoveKeepAliveEntry(&endpoint))
672     {
673         OIC_LOG(ERROR, TAG, "OCRemoveKeepAliveEntry is failed");
674         return OC_STACK_ERROR;
675     }
676
677     /*
678      * Send empty message to disconnect a connection.
679      * If CA get the empty message from RI, CA will disconnect a connection.
680      */
681     CAResult_t result = CAUtilTCPDisconnectSession(endpoint.addr, endpoint.port, endpoint.flags);
682     if (OC_STACK_OK != CAResultToOCResult(result))
683     {
684         OIC_LOG(ERROR, TAG, "Failed to disconnect session");
685     }
686
687     return CAResultToOCResult(result);
688 }
689
690 KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint)
691 {
692     KeepAliveEntry_t *entry = NULL;
693     LL_FOREACH(g_keepAliveConnectionTable, entry)
694     {
695         if (entry)
696         {
697             if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
698                     && (entry->remoteAddr.port == endpoint->port))
699             {
700                 OIC_LOG(DEBUG, TAG, "Connection Info found in KeepAlive table");
701                 return entry;
702             }
703         }
704     }
705
706     return NULL;
707 }
708
709 KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode,
710                                       int64_t interval)
711 {
712     if (!endpoint)
713     {
714         OIC_LOG(ERROR, TAG, "endpoint is NULL");
715         return NULL;
716     }
717
718     KeepAliveEntry_t *entry = (KeepAliveEntry_t *) OICCalloc(1, sizeof(KeepAliveEntry_t));
719     if (NULL == entry)
720     {
721         OIC_LOG(ERROR, TAG, "Failed to Calloc KeepAlive Entry");
722         return NULL;
723     }
724
725     entry->mode = mode;
726     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
727     entry->remoteAddr.adapter = endpoint->adapter;
728     entry->remoteAddr.flags = endpoint->flags;
729     entry->remoteAddr.ifindex = endpoint->ifindex;
730     entry->remoteAddr.port = endpoint->port;
731     strncpy(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr));
732     entry->interval = interval;
733
734     LL_APPEND(g_keepAliveConnectionTable, entry);
735     return entry;
736 }
737
738 OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint)
739 {
740     OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry IN");
741
742     VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM);
743
744     KeepAliveEntry_t *entry = NULL;
745     KeepAliveEntry_t *tmp = NULL;
746     LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp)
747     {
748         if (entry)
749         {
750             if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
751                     && (entry->remoteAddr.port == endpoint->port))
752             {
753                 OIC_LOG_V(DEBUG, TAG, "Remove Connection Info from KeepAlive table, "
754                           "remote addr=%s port:%d", entry->remoteAddr.addr,
755                           entry->remoteAddr.port);
756
757                 LL_DELETE(g_keepAliveConnectionTable, entry);
758                 OICFree(entry);
759             }
760         }
761     }
762
763     OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry OUT");
764     return OC_STACK_OK;
765 }
766
767 void OCHandleKeepAliveConnCB(const CAEndpoint_t *endpoint, bool isConnected, bool isClient)
768 {
769     (void) isClient;
770     VERIFY_NON_NULL_NR(endpoint, FATAL);
771
772     if (isConnected)
773     {
774         OIC_LOG(DEBUG, TAG, "Received the connected device information from CA");
775     }
776     else
777     {
778         OIC_LOG(DEBUG, TAG, "Received the disconnected device information from CA");
779
780         // Do nothing because callback will be removed after one min.
781         /*
782         // notify application that the session is disconnected.
783         oc_mutex_lock(g_mutexObjectList);
784         KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endpoint);
785         if (entry)
786         {
787             ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL);
788             if (cbNode)
789             {
790                 OCClientResponse response = { .devAddr = { .adapter = OC_ADAPTER_TCP } };
791                 CopyEndpointToDevAddr(&entry->remoteAddr, &response.devAddr);
792                 FixUpClientResponse(&response);
793                 response.resourceUri = cbNode->requestUri;
794                 response.result = OC_STACK_COMM_ERROR;
795
796                 cbNode->callBack(cbNode->context, cbNode->handle, &response);
797                 FindAndDeleteClientCB(cbNode);
798             }
799             OCRemoveKeepAliveEntry(endpoint);
800         }
801         oc_mutex_unlock(g_mutexObjectList);
802         */
803     }
804 }
805
806 OCRepPayload *OCCreateKeepAlivePayload(int64_t interval)
807 {
808     OIC_LOG_V(DEBUG, TAG, "Create KeepAlive Payload, interval is [%" PRId64 "]", interval);
809
810     OCRepPayload *payload = OCRepPayloadCreate();
811     if (!payload)
812     {
813         OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
814         return NULL;
815     }
816     payload->base.type = PAYLOAD_TYPE_REPRESENTATION;
817     OCRepPayloadSetPropInt(payload, INTERVAL, interval);
818
819     return payload;
820 }
821
822 OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload)
823 {
824     uint8_t numElement = 0;
825     OCStackResult res = OCGetNumberOfResourceTypes(g_keepAliveHandle, &numElement);
826     if (OC_STACK_OK == res)
827     {
828         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
829         char **rt = (char **)OICMalloc(sizeof(char *) * numElement);
830         if (!rt)
831         {
832             OIC_LOG(ERROR, TAG, "Could not allocate memory for rf");
833             return OC_STACK_NO_MEMORY;
834         }
835         for (uint8_t i = 0; i < numElement; ++i)
836         {
837             const char *value = OCGetResourceTypeName(g_keepAliveHandle, i);
838             OIC_LOG_V(DEBUG, TAG, "value: %s", value);
839             rt[i] = OICStrdup(value);
840             if (NULL == rt[i])
841             {
842                 OIC_LOG_V(ERROR, TAG, "Creating duplicate string for rt failed!");
843                 for (uint8_t j = 0; j < i; ++j)
844                 {
845                     OICFree(rt[j]);
846                 }
847                 OICFree(rt);
848                 return OC_STACK_NO_MEMORY;
849             }
850         }
851         OCRepPayloadSetStringArray(payload, OC_RSRVD_RESOURCE_TYPE, (const char **) rt, rtDim);
852         for (uint8_t i = 0; i < numElement; ++i)
853         {
854             OICFree(rt[i]);
855         }
856         OICFree(rt);
857     }
858
859     return res;
860 }
861
862 OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload)
863 {
864     uint8_t numElement = 0;
865     OCStackResult res = OCGetNumberOfResourceInterfaces(g_keepAliveHandle, &numElement);
866     if (OC_STACK_OK == res)
867     {
868         size_t ifDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
869         char **itf = (char **)OICMalloc(sizeof(char *) * numElement);
870         if (!itf)
871         {
872             OIC_LOG(ERROR, TAG, "Could not allocate memory for itf");
873             return OC_STACK_NO_MEMORY;
874         }
875
876         for (uint8_t i = 0; i < numElement; ++i)
877         {
878             const char *value = OCGetResourceInterfaceName(g_keepAliveHandle, i);
879             OIC_LOG_V(DEBUG, TAG, "value: %s", value);
880             itf[i] = OICStrdup(value);
881             if (NULL == itf[i])
882             {
883                 OIC_LOG_V(ERROR, TAG, "Creating duplicate string for itf failed!");
884                 for (uint8_t j = 0; j < i; ++j)
885                 {
886                     OICFree(itf[j]);
887                 }
888                 OICFree(itf);
889                 return OC_STACK_NO_MEMORY;
890             }
891         }
892         OCRepPayloadSetStringArray(payload, OC_RSRVD_INTERFACE, (const char **) itf, ifDim);
893         for (uint8_t i = 0; i < numElement; ++i)
894         {
895             OICFree(itf[i]);
896         }
897         OICFree(itf);
898     }
899
900     return res;
901 }