Merge "Merge branch 'master' into group-manager" into group-manager
[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
23 #include <stdio.h>
24 #include <string.h>
25 #include "oic_malloc.h"
26 #include "oic_string.h"
27 #include "oic_time.h"
28 #include "ocrandom.h"
29 #include "uarraylist.h"
30 #include "ocstackinternal.h"
31 #include "ocpayloadcbor.h"
32 #include "ocpayload.h"
33 #include "ocresourcehandler.h"
34 #include "logger.h"
35
36 /**
37  * Logging tag for module name.
38  */
39 #define TAG "OIC_RI_KEEPALIVE"
40
41 static const uint64_t USECS_PER_SEC = 1000000;
42
43 //-----------------------------------------------------------------------------
44 // Macros
45 //-----------------------------------------------------------------------------
46 #define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
47             {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
48
49 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
50              TAG, #arg " is NULL"); return (retVal); } }
51
52 #define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OIC_LOG((logLevel), \
53              TAG, #arg " is NULL"); return; } }
54
55 #define VERIFY_NON_NULL_V(arg) { if (!arg) {OIC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
56     goto exit;} }
57
58 /**
59  * The KeepAlive table entries are removed
60  * if it can't receive response message within 60 seconds.
61  */
62 #define KEEPALIVE_RESPONSE_TIMEOUT_SEC 60
63
64 /**
65  * The Min time interval value. (2 minutes)
66  * start from 2 minutes and increases in multiples of 2 up to a maximum of 64minutes.
67  */
68 #define KEEPALIVE_MIN_INTERVAL 2
69
70 /**
71  * The Max time interval value. (64 minutes)
72  */
73 #define KEEPALIVE_MAX_INTERVAL 64
74
75 /**
76  * KeepAlive key to parser Payload Table.
77  */
78 static const char INTERVAL[] = "in";
79
80 /**
81  * To check if KeepAlive is initialized.
82  */
83 static bool g_isKeepAliveInitialized = false;
84
85 /**
86  * Pointer to handle of the newly created KeepAlive resource.
87  */
88 static OCResourceHandle g_keepAliveHandle = NULL;
89
90 /**
91  * KeepAlive table which holds connection interval.
92  */
93 static u_arraylist_t *g_keepAliveConnectionTable = NULL;
94
95 /**
96  * KeepAlive table entries.
97  */
98 typedef struct
99 {
100     OCMode mode;                    /**< host Mode of Operation. */
101     CAEndpoint_t remoteAddr;        /**< destination Address. */
102     uint32_t interval;              /**< time interval for KeepAlive. in seconds.*/
103     bool sentPingMsg;               /**< if oic client already sent ping message. */
104     uint64_t timeStamp;             /**< last sent or received ping message. in microseconds. */
105 } KeepAliveEntry_t;
106
107 /**
108  * Send disconnect message to remove connection.
109  */
110 static OCStackResult SendDisconnectMessage(const KeepAliveEntry_t *entry);
111
112 /**
113  * Send ping message to remote endpoint.
114  */
115 static OCStackResult SendPingMessage(KeepAliveEntry_t *entry);
116
117 /**
118  * Ping Message callback registered with RI for KeepAlive Request.
119  */
120 static OCStackApplicationResult PingRequestCallback(void* ctx, OCDoHandle handle,
121                                              OCClientResponse * clientResponse);
122
123 /**
124  * This function creates KeepAlive resource.
125  * @return  ::OC_STACK_OK or Appropriate error code.
126  */
127 static OCStackResult CreateKeepAliveResource();
128
129 /**
130  * This function deletes KeepAlive resource.
131  * @return  ::OC_STACK_OK or Appropriate error code.
132  */
133 static OCStackResult DeleteKeepAliveResource();
134
135 /**
136  * API to handle the GET request received for a KeepAlive resource.
137  * @param[in]   endPoint        RemoteEndpoint which sent the packet.
138  * @param[in]   requestInfo     Received coap packet.
139  * @return  ::OC_STACK_OK or Appropriate error code.
140  */
141 static OCStackResult HandleKeepAliveGETRequest(const CAEndpoint_t* endPoint,
142                                         const CARequestInfo_t* requestInfo);
143
144 /**
145  * API to handle the PUT request received for a KeepAlive resource.
146  * @param[in]   endPoint        RemoteEndpoint which sent the packet.
147  * @param[in]   requestInfo     Received coap packet.
148  * @return  ::OC_STACK_OK or Appropriate error code.
149  */
150 static OCStackResult HandleKeepAlivePUTRequest(const CAEndpoint_t* endPoint,
151                                         const CARequestInfo_t* requestInfo);
152
153 /**
154  * API to handle the Response payload.
155  * @param[in]   endpoint    RemoteEndpoint which sent the packet.
156  * @param[in]   responseCode   Received reseponse code.
157  * @return  ::OC_STACK_OK or Appropriate error code.
158  */
159 static OCStackResult HandleKeepAliveResponse(const CAEndpoint_t *endPoint,
160                                       OCStackResult responseCode);
161
162 /**
163  * Gets keepalive entry.
164  * @param[in]   endpoint    Remote Endpoint information (like ipaddress,
165  *                          port, reference uri and transport type) to
166  *                          which the ping message has to be sent.
167  * @param[out]  index       index of array list.
168  * @return  KeepAlive entry to send ping message.
169  */
170 static KeepAliveEntry_t *GetEntryFromEndpoint(const CAEndpoint_t *endpoint, uint32_t *index);
171
172 /**
173  * Add keepalive entry.
174  * @param[in]   endpoint    Remote Endpoint information (like ipaddress,
175  *                          port, reference uri and transport type).
176  * @param[in]   mode        Whether it is OIC Server or OIC Client.
177  * @return  The KeepAlive entry added in KeepAlive Table.
178  */
179 static KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode);
180
181 /**
182  * Remove keepalive entry.
183  * @param[in]   endpoint    Remote Endpoint information (like ipaddress,
184  *                          port, reference uri and transport type).
185  * @return  The KeepAlive entry removed in KeepAlive Table.
186  */
187 static OCStackResult RemoveKeepAliveEntry(const CAEndpoint_t *endpoint);
188
189 OCStackResult InitializeKeepAlive()
190 {
191     OIC_LOG(DEBUG, TAG, "InitializeKeepAlive IN");
192     if (g_isKeepAliveInitialized)
193     {
194         OIC_LOG(DEBUG, TAG, "KeepAlive already initialized");
195         return OC_STACK_OK;
196     }
197
198     // Create the KeepAlive Resource[/oic/ping].
199     OCStackResult result = CreateKeepAliveResource();
200     if (OC_STACK_OK != result)
201     {
202         OIC_LOG_V(ERROR, TAG, "CreateKeepAliveResource failed[%d]", result);
203         return result;
204     }
205
206     if (!g_keepAliveConnectionTable)
207     {
208         g_keepAliveConnectionTable = u_arraylist_create();
209         if (NULL == g_keepAliveConnectionTable)
210         {
211             OIC_LOG(ERROR, TAG, "Creating KeepAlive Table failed");
212             TerminateKeepAlive();
213             return OC_STACK_ERROR;
214         }
215     }
216
217     g_isKeepAliveInitialized = true;
218
219     OIC_LOG(DEBUG, TAG, "InitializeKeepAlive OUT");
220     return OC_STACK_OK;
221 }
222
223 OCStackResult TerminateKeepAlive()
224 {
225     OIC_LOG(DEBUG, TAG, "TerminateKeepAlive IN");
226     if (!g_isKeepAliveInitialized)
227     {
228         OIC_LOG(ERROR, TAG, "KeepAlive not initialized");
229         return OC_STACK_ERROR;
230     }
231
232     // Delete the KeepAlive Resource[/oic/ping].
233     OCStackResult result = DeleteKeepAliveResource();
234     if (OC_STACK_OK != result)
235     {
236         OIC_LOG_V(ERROR, TAG, "DeleteKeepAliveResource failed[%d]", result);
237         return result;
238     }
239
240     if (NULL != g_keepAliveConnectionTable)
241     {
242         u_arraylist_destroy(g_keepAliveConnectionTable);
243         g_keepAliveConnectionTable = NULL;
244     }
245
246     g_isKeepAliveInitialized = false;
247
248     OIC_LOG(DEBUG, TAG, "TerminateKeepAlive OUT");
249     return OC_STACK_OK;
250 }
251
252 OCStackResult CreateKeepAliveResource()
253 {
254     OIC_LOG(DEBUG, TAG, "InitKeepAliveResource IN");
255
256     // Create a KeepAlive resource
257     OCStackResult result = OCCreateResource(&g_keepAliveHandle,
258                                             KEEPALIVE_RESOURCE_TYPE_NAME,
259                                             KEEPALIVE_RESOURCE_INTF_NAME,
260                                             KEEPALIVE_RESOURCE_URI,
261                                             NULL,
262                                             NULL,
263                                             OC_DISCOVERABLE);
264
265     if (OC_STACK_OK != result)
266     {
267         OIC_LOG_V(ERROR, TAG, "Create resource for KeepAlive failed[%d]", result);
268     }
269
270     OIC_LOG(DEBUG, TAG, "InitKeepAliveResource OUT");
271     return result;
272 }
273
274 OCStackResult DeleteKeepAliveResource()
275 {
276     OIC_LOG(DEBUG, TAG, "DeleteKeepAliveResource IN");
277
278     // Create a KeepAlive resource
279     OCStackResult result = OCDeleteResource(g_keepAliveHandle);
280
281     if (OC_STACK_OK != result)
282     {
283         OIC_LOG_V(ERROR, TAG, "Delete resource for KeepAlive failed[%d]", result);
284     }
285
286     OIC_LOG(DEBUG, TAG, "DeleteKeepAliveResource OUT");
287     return result;
288 }
289
290 OCStackResult HandleKeepAliveRequest(const CAEndpoint_t* endPoint,
291                                      const CARequestInfo_t* requestInfo)
292 {
293     VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
294     VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM);
295
296     OIC_LOG(DEBUG, TAG, "HandleKeepAliveRequest IN");
297
298     OCStackResult result = OC_STACK_OK;
299     if (CA_PUT == requestInfo->method)
300     {
301         result = HandleKeepAlivePUTRequest(endPoint, requestInfo);
302     }
303     else if (CA_GET == requestInfo->method)
304     {
305         result = HandleKeepAliveGETRequest(endPoint, requestInfo);
306     }
307
308     OIC_LOG(DEBUG, TAG, "HandleKeepAliveRequest OUT");
309     return result;
310 }
311
312 OCStackResult HandleKeepAliveGETRequest(const CAEndpoint_t* endPoint,
313                                         const CARequestInfo_t* requestInfo)
314 {
315     VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
316     VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM);
317
318     OIC_LOG_V(DEBUG, TAG, "Find Ping resource [%s]", requestInfo->info.resourceUri);
319
320     CAResponseResult_t result = CA_VALID;
321     OCResource *resourcePtr = FindResourceByUri(requestInfo->info.resourceUri);
322     if (!resourcePtr)
323     {
324         // Resource URL not specified
325         OIC_LOG_V(DEBUG, TAG, "There is no Ping resource [%s]", requestInfo->info.resourceUri);
326         result = CA_NOT_FOUND;
327     }
328
329     SendDirectStackResponse(endPoint, requestInfo->info.messageId, result, requestInfo->info.type,
330                             requestInfo->info.numOptions, requestInfo->info.options,
331                             requestInfo->info.token, requestInfo->info.tokenLength,
332                             requestInfo->info.resourceUri);
333
334     return OC_STACK_OK;
335 }
336
337 OCStackResult HandleKeepAlivePUTRequest(const CAEndpoint_t* endPoint,
338                                         const CARequestInfo_t* requestInfo)
339 {
340     VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
341     VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM);
342
343     // Get entry from KeepAlive table.
344     uint32_t index = 0;
345     KeepAliveEntry_t *entry = GetEntryFromEndpoint(endPoint, &index);
346     if (!entry)
347     {
348         OIC_LOG(ERROR, TAG, "Received the first keepalive message from client");
349         entry = AddKeepAliveEntry(endPoint, OC_SERVER);
350         if (!entry)
351         {
352             OIC_LOG(ERROR, TAG, "Failed to add new keepalive entry");
353             return OC_STACK_ERROR;
354         }
355     }
356
357     OCPayload *ocPayload = NULL;
358     OCParsePayload(&ocPayload, PAYLOAD_TYPE_REPRESENTATION,
359                    requestInfo->info.payload, requestInfo->info.payloadSize);
360     OCRepPayload *repPayload = (OCRepPayload *)ocPayload;
361
362     uint32_t interval = 0;
363     OCRepPayloadGetPropInt(repPayload, INTERVAL, &interval);
364     entry->interval = interval;
365     OIC_LOG_V(DEBUG, TAG, "Received interval is [%d]", entry->interval);
366     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
367
368     // Send response message.
369     SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_VALID, requestInfo->info.type,
370                             requestInfo->info.numOptions, requestInfo->info.options,
371                             requestInfo->info.token, requestInfo->info.tokenLength,
372                             requestInfo->info.resourceUri);
373
374     return OC_STACK_OK;
375 }
376
377 OCStackResult HandleKeepAliveResponse(const CAEndpoint_t *endPoint,
378                                       OCStackResult responseCode)
379 {
380     VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
381
382     OIC_LOG(DEBUG, TAG, "HandleKeepAliveResponse IN");
383
384     // Get entry from KeepAlive table.
385     uint32_t index = 0;
386     KeepAliveEntry_t *entry = GetEntryFromEndpoint(endPoint, &index);
387     if (!entry)
388     {
389         OIC_LOG(ERROR, TAG, "There is no connection info in KeepAlive table");
390
391         if (OC_STACK_NO_RESOURCE == responseCode)
392         {
393             OIC_LOG(ERROR, TAG, "Server doesn't have a ping resource");
394             return OC_STACK_ERROR;
395         }
396         else if (OC_STACK_OK == responseCode)
397         {
398             entry = AddKeepAliveEntry(endPoint, OC_CLIENT);
399             if (!entry)
400             {
401                 OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry");
402                 return OC_STACK_ERROR;
403             }
404
405             // Send first ping message
406             return SendPingMessage(entry);
407         }
408     }
409
410     // Set sentPingMsg values with false.
411     entry->sentPingMsg = false;
412
413     OIC_LOG(DEBUG, TAG, "HandleKeepAliveResponse OUT");
414     return OC_STACK_OK;
415 }
416
417 void ProcessKeepAlive()
418 {
419     if (!g_isKeepAliveInitialized)
420     {
421         OIC_LOG(ERROR, TAG, "KeepAlive not initialized");
422         return;
423     }
424
425     uint32_t len = u_arraylist_length(g_keepAliveConnectionTable);
426
427     for (uint32_t i = 0; i < len; i++)
428     {
429         KeepAliveEntry_t *entry = u_arraylist_get(g_keepAliveConnectionTable, i);
430         if (NULL == entry)
431         {
432             continue;
433         }
434
435         uint64_t currentTime = OICGetCurrentTime(TIME_IN_US);
436         if (OC_CLIENT == entry->mode)
437         {
438             if (entry->sentPingMsg)
439             {
440                 /*
441                  * If an OIC Client does not receive the response within 1 minutes,
442                  * terminate the connection.
443                  * In this case the timeStamp means last time sent ping message.
444                  */
445                 if ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp)
446                 {
447                     OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes.");
448
449                     // Send message to disconnect session.
450                     SendDisconnectMessage(entry);
451                 }
452             }
453             else
454             {
455                 if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC)
456                         <= currentTime - entry->timeStamp)
457                 {
458                     // Increase interval value.
459                     if (KEEPALIVE_MAX_INTERVAL > entry->interval)
460                     {
461                         entry->interval = entry->interval << 1;
462                     }
463
464                     OCStackResult result = SendPingMessage(entry);
465                     if (OC_STACK_OK != result)
466                     {
467                         OIC_LOG(ERROR, TAG, "Failed to send ping request");
468                         continue;
469                     }
470                 }
471             }
472         }
473         else if (OC_SERVER == entry->mode)
474         {
475             /*
476              * If an OIC Server does not receive a PUT request to ping resource
477              * within the specified interval time, terminate the connection.
478              * In this case the timeStamp means last time received ping message.
479              */
480             if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC)
481                     <= currentTime - entry->timeStamp)
482             {
483                 OIC_LOG(DEBUG, TAG, "Server does not receive a PUT request.");
484                 SendDisconnectMessage(entry);
485             }
486         }
487     }
488 }
489
490 OCStackResult SendDisconnectMessage(const KeepAliveEntry_t *entry)
491 {
492     VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM);
493
494     /*
495      * Send empty message to disconnect a connection.
496      * If CA get the empty message from RI, CA will disconnect a connection.
497      */
498     CARequestInfo_t requestInfo = { .method = CA_PUT };
499     return CASendRequest(&entry->remoteAddr, &requestInfo);
500 }
501
502 OCStackResult SendPingMessage(KeepAliveEntry_t *entry)
503 {
504     VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM);
505
506     // Send ping message.
507     OCCallbackData pingData = { .cb = PingRequestCallback };
508     OCDevAddr devAddr = { .adapter = OC_ADAPTER_TCP };
509     CopyEndpointToDevAddr(&(entry->remoteAddr), &devAddr);
510
511     OCRepPayload *payload = OCRepPayloadCreate();
512     if (!payload)
513     {
514         OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
515         return OC_STACK_ERROR;
516     }
517     payload->base.type = PAYLOAD_TYPE_REPRESENTATION;
518     OCRepPayloadSetPropInt(payload, INTERVAL, entry->interval);
519
520     OCDoResource(NULL, OC_REST_PUT, KEEPALIVE_RESOURCE_URI, &devAddr,
521                  (OCPayload *) payload, CT_ADAPTER_TCP, OC_LOW_QOS, &pingData, NULL, 0);
522
523     // Update timeStamp with time sent ping message for next ping message.
524     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
525     entry->sentPingMsg = true;
526
527     OIC_LOG_V(DEBUG, TAG, "Client sent ping message, interval [%d]", entry->interval);
528
529     return OC_STACK_OK;
530 }
531
532 OCStackApplicationResult PingRequestCallback(void* ctx, OCDoHandle handle,
533                                              OCClientResponse *clientResponse)
534 {
535     OIC_LOG(DEBUG, TAG, "PingRequestCallback IN");
536     (void) ctx;
537     (void) handle;
538     if (NULL == clientResponse)
539     {
540         OIC_LOG(ERROR, TAG, "clientResponse is NULL");
541         return OC_STACK_KEEP_TRANSACTION;
542     }
543
544     CAEndpoint_t endpoint = { .adapter = CA_ADAPTER_TCP };
545     CopyDevAddrToEndpoint(&(clientResponse->devAddr), &endpoint);
546
547     HandleKeepAliveResponse(&endpoint, clientResponse->result);
548
549     OIC_LOG(DEBUG, TAG, "PingRequestCallback OUT");
550     return OC_STACK_KEEP_TRANSACTION;
551 }
552
553 KeepAliveEntry_t *GetEntryFromEndpoint(const CAEndpoint_t *endpoint, uint32_t *index)
554 {
555     if (!g_keepAliveConnectionTable)
556     {
557         OIC_LOG(ERROR, TAG, "KeepAlive Table was not Created.");
558         return NULL;
559     }
560
561     uint32_t len = u_arraylist_length(g_keepAliveConnectionTable);
562
563     for (uint32_t i = 0; i < len; i++)
564     {
565         KeepAliveEntry_t *entry = u_arraylist_get(g_keepAliveConnectionTable, i);
566         if (NULL == entry)
567         {
568             continue;
569         }
570
571         if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
572                 && (entry->remoteAddr.port == endpoint->port))
573         {
574             OIC_LOG(DEBUG, TAG, "Connection Info found in KeepAlive table");
575             *index = i;
576             return entry;
577         }
578     }
579
580     return NULL;
581 }
582
583 KeepAliveEntry_t *AddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode)
584 {
585     if (!endpoint)
586     {
587         OIC_LOG(ERROR, TAG, "endpoint is NULL");
588         return NULL;
589     }
590
591     if (!g_keepAliveConnectionTable)
592     {
593         OIC_LOG(ERROR, TAG, "KeepAlive Table was not Created.");
594         return NULL;
595     }
596
597     KeepAliveEntry_t *entry = (KeepAliveEntry_t *) OICCalloc(1, sizeof(KeepAliveEntry_t));
598     if (NULL == entry)
599     {
600         OIC_LOG(ERROR, TAG, "Failed to Calloc KeepAlive Entry");
601         return NULL;
602     }
603
604     entry->mode = mode;
605     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
606     entry->interval = KEEPALIVE_MIN_INTERVAL;
607     entry->remoteAddr.adapter = endpoint->adapter;
608     entry->remoteAddr.flags = endpoint->flags;
609     entry->remoteAddr.interface = endpoint->interface;
610     entry->remoteAddr.port = endpoint->port;
611     strncpy(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr));
612
613     bool result = u_arraylist_add(g_keepAliveConnectionTable, (void *)entry);
614     if (!result)
615     {
616         OIC_LOG(ERROR, TAG, "Adding node to head failed");
617         OICFree(entry);
618         return NULL;
619     }
620
621     return entry;
622 }
623
624 OCStackResult RemoveKeepAliveEntry(const CAEndpoint_t *endpoint)
625 {
626     VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM);
627
628     uint32_t index = 0;
629     KeepAliveEntry_t *entry = GetEntryFromEndpoint(endpoint, &index);
630     if (!entry)
631     {
632         OIC_LOG(ERROR, TAG, "There is no entry in keepalive table.");
633         return OC_STACK_ERROR;
634     }
635
636     KeepAliveEntry_t *removedEntry = u_arraylist_remove(g_keepAliveConnectionTable, index);
637     if (NULL == removedEntry)
638     {
639         OIC_LOG(ERROR, TAG, "Removed Entry is NULL");
640         return OC_STACK_ERROR;
641     }
642
643     OIC_LOG_V(DEBUG, TAG, "Remove Connection Info from KeepAlive table, "
644              "remote addr=%s port:%d", removedEntry->remoteAddr.addr,
645              removedEntry->remoteAddr.port);
646
647     OICFree(removedEntry);
648
649     return OC_STACK_OK;
650 }
651
652 void HandleKeepAliveConnCB(const CAEndpoint_t *endpoint)
653 {
654     VERIFY_NON_NULL_NR(endpoint, FATAL);
655
656     OIC_LOG(DEBUG, TAG, "Received the connected device information from CA");
657
658     // Send discover message to find ping resource
659     OCCallbackData pingData = { .cb = PingRequestCallback };
660     OCDevAddr devAddr = { .adapter = OC_ADAPTER_TCP };
661     CopyEndpointToDevAddr(endpoint, &devAddr);
662     return OCDoResource(NULL, OC_REST_DISCOVER, KEEPALIVE_RESOURCE_URI, &devAddr, NULL,
663                         OC_ADAPTER_TCP, OC_HIGH_QOS, &pingData, NULL, 0);
664 }
665
666 void HandleKeepAliveDisconnCB(const CAEndpoint_t *endpoint)
667 {
668     VERIFY_NON_NULL_NR(endpoint, FATAL);
669
670     OIC_LOG(DEBUG, TAG, "Received the disconnected device information from CA");
671
672     OCStackResult result = RemoveKeepAliveEntry(endpoint);
673     if(result != OC_STACK_OK)
674     {
675         OIC_LOG(ERROR, TAG, "Failed to remove entry");
676         return;
677     }
678 }