[CONPRO-1398] Adjust server request handling
[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 #define VERIFY_NON_NULL_EXIT(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \
63              TAG, #arg " is NULL"); ret = retVal; goto exit; } }
64
65 /**
66  * The KeepAlive table entries are removed
67  * if it can't receive response message within 60 seconds.
68  */
69 #define KEEPALIVE_RESPONSE_TIMEOUT_SEC 60
70
71 /**
72  * KeepAlive key to parser Payload Table.
73  */
74 static const char INTERVAL[] = "in";
75
76 /**
77  * KeepAlive key to get interval values from Payload Table.
78  */
79 static const char INTERVAL_ARRAY[] = "inarray";
80
81 /**
82  * Pointer to handle of the newly created KeepAlive resource.
83  */
84 static OCResourceHandle g_keepAliveHandle = NULL;
85
86 /**
87  * KeepAlive table which holds connection interval.
88  */
89 static struct KeepAliveEntry_t *g_keepAliveConnectionTable = NULL;
90
91 /**
92  * Mutex to synchronize device object list.
93  */
94 static oc_mutex g_mutexObjectList = NULL;
95
96 /**
97  * KeepAlive table entries.
98  */
99 typedef struct KeepAliveEntry_t
100 {
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.*/
109 } KeepAliveEntry_t;
110
111 /**
112  * Send disconnect message to remove connection.
113  */
114 static OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry);
115
116 /**
117  * This function creates KeepAlive resource.
118  * @return  ::OC_STACK_OK or Appropriate error code.
119  */
120 static OCStackResult OCCreateKeepAliveResource();
121
122 /**
123  * This function deletes KeepAlive resource.
124  * @return  ::OC_STACK_OK or Appropriate error code.
125  */
126 static OCStackResult OCDeleteKeepAliveResource();
127
128 /**
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.
133  */
134 static OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request,
135                                                          const OCResource *resource);
136
137 /**
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.
142  */
143 static OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request,
144                                                           const OCResource *resource);
145
146 /**
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.
152  */
153 static KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint);
154
155 /**
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.
162  */
163 KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode,
164                                       int64_t interval);
165
166 /**
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.
171  */
172 static OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint);
173
174 /**
175  * Create KeepAlive paylaod to send message.
176  * @param[in]   interval   The interval value to be sent.
177  * @return  Created representation payload.
178  */
179 static OCRepPayload *OCCreateKeepAlivePayload(int64_t interval);
180
181 /**
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.
186  */
187 static OCStackResult OCSendKeepAliveResponse(OCServerRequest *request,
188                                            OCEntityHandlerResult result);
189
190 /**
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.
194  */
195 static OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload);
196
197 /**
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.
201  */
202 static OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload);
203
204 OCStackResult OCInitializeKeepAlive(OCMode mode)
205 {
206     OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive IN");
207
208     if (!g_mutexObjectList)
209     {
210         g_mutexObjectList = oc_mutex_new();
211         if (!g_mutexObjectList)
212         {
213             OIC_LOG(ERROR, TAG, "Failed to create mutex!");
214             return OC_STACK_ERROR;
215         }
216     }
217
218     if (OC_CLIENT != mode)
219     {
220         // Create the KeepAlive Resource[/oic/ping].
221         OCStackResult result = OCCreateKeepAliveResource();
222         if (OC_STACK_OK != result)
223         {
224             OIC_LOG_V(ERROR, TAG, "OCCreateKeepAliveResource failed[%d]", result);
225             return result;
226         }
227     }
228
229     OIC_LOG(DEBUG, TAG, "OCInitializeKeepAlive OUT");
230     return OC_STACK_OK;
231 }
232
233 OCStackResult OCTerminateKeepAlive(OCMode mode)
234 {
235     OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive IN");
236
237     if (g_mutexObjectList)
238     {
239         oc_mutex_free(g_mutexObjectList);
240         g_mutexObjectList = NULL;
241     }
242
243     if (OC_CLIENT != mode)
244     {
245         // Delete the KeepAlive Resource[/oic/ping].
246         OCStackResult result = OCDeleteKeepAliveResource();
247         if (OC_STACK_OK != result)
248         {
249             OIC_LOG_V(ERROR, TAG, "OCDeleteKeepAliveResource failed[%d]", result);
250             return result;
251         }
252     }
253
254     OIC_LOG(DEBUG, TAG, "OCTerminateKeepAlive OUT");
255     return OC_STACK_OK;
256 }
257
258 OCStackResult OCFindKeepAliveResource(OCDoHandle *handle, const char *remoteAddr,
259                                       OCCallbackData *cbData)
260 {
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);
265
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,
271                                         cbData, NULL, 0);
272     if (OC_STACK_OK != result)
273     {
274         OIC_LOG(ERROR, TAG, "OCDoResource has failed");
275     }
276     return result;
277 }
278
279 OCStackResult OCSendKeepAliveRequest(OCDoHandle *handle, const char *remoteAddr,
280                                      OCPayload *payload, OCCallbackData *cbData)
281 {
282     OCStackResult ret;
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);
287
288     OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest IN");
289
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)
297     {
298         OIC_LOG_V(DEBUG, TAG, "Unable to parse uri: %s", remoteAddr);
299         OCPayloadDestroy(payload);
300         return OC_STACK_ERROR;
301     }
302
303     VERIFY_NON_NULL_EXIT(devAddr, FATAL, OC_STACK_INVALID_PARAM);
304
305     if (!(devAddr->adapter & OC_ADAPTER_TCP))
306     {
307         OIC_LOG_V(DEBUG, TAG, "Not supported connectivity type");
308         OICFree(devAddr);
309         OCPayloadDestroy(payload);
310         return OC_STACK_ERROR;
311     }
312
313     // Get entry from KeepAlive table.
314     CAEndpoint_t endpoint = { .adapter = CA_DEFAULT_ADAPTER };
315     CopyDevAddrToEndpoint(devAddr, &endpoint);
316
317     oc_mutex_lock(g_mutexObjectList);
318     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
319     if (!entry)
320     {
321         OIC_LOG(DEBUG, TAG, "There is no connection info in KeepAlive table");
322
323         entry = OCAddKeepAliveEntry(&endpoint, OC_CLIENT, 0);
324         if (!entry)
325         {
326             oc_mutex_unlock(g_mutexObjectList);
327             OIC_LOG(ERROR, TAG, "Failed to add new KeepAlive entry");
328             OICFree(devAddr);
329             OCPayloadDestroy(payload);
330             return OC_STACK_ERROR;
331         }
332     }
333
334     // Get "in" value from payload.
335     int64_t interval = 0;
336     bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) payload, INTERVAL, &interval);
337     if (findValue && interval)
338     {
339         if (entry->sentPingMsg)
340         {
341             oc_mutex_unlock(g_mutexObjectList);
342             OIC_LOG(ERROR, TAG, "Already sent a ping request to remote device");
343             OICFree(devAddr);
344             OCPayloadDestroy(payload);
345             return OC_STACK_ERROR;
346         }
347         entry->interval = interval;
348         OIC_LOG_V(DEBUG, TAG, "Send ping message with interval [%" PRId64 "]", entry->interval);
349     }
350
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);
355     if (inArray)
356     {
357         uint8_t len = 0;
358         char newArray[MAX_URI_LENGTH] = { 0 };
359         size_t inArraySize = calcDimTotal(dimensions);
360         for (size_t i = 0; i < inArraySize; i++)
361         {
362             len += snprintf(newArray + len, MAX_URI_LENGTH, "% " PRId64, inArray[i]);
363         }
364         OICFree(inArray);
365         OIC_LOG_V(DEBUG, TAG, "Send update interval message with inarray [ %s]", newArray);
366     }
367
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)
373     {
374         oc_mutex_unlock(g_mutexObjectList);
375         OIC_LOG(ERROR, TAG, "OCDoResource has failed");
376         OICFree(devAddr);
377         return result;
378     }
379
380     // Update timeStamp with time sent ping message for next ping message.
381     entry->timeStamp = OICGetCurrentTime(TIME_IN_US);
382     entry->sentPingMsg = true;
383     if (handle)
384     {
385         *handle = entry->handle;
386     }
387
388     oc_mutex_unlock(g_mutexObjectList);
389     OIC_LOG(DEBUG, TAG, "SendKeepAliveRequest OUT");
390     OICFree(devAddr);
391     return result;
392
393 exit:
394     OCPayloadDestroy(payload);
395     return (ret);
396 }
397
398 OCStackResult OCHandleKeepAliveResponse(const CAEndpoint_t *endPoint, const OCPayload *payload)
399 {
400     (void) payload;
401     VERIFY_NON_NULL(endPoint, FATAL, OC_STACK_INVALID_PARAM);
402
403     // Receive response message about post /oic/ping request.
404     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse IN");
405
406     // Get entry from KeepAlive table.
407     oc_mutex_lock(g_mutexObjectList);
408     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endPoint);
409     if (entry)
410     {
411         OIC_LOG_V(DEBUG, TAG, "Received response about interval [%" PRId64 "]", entry->interval);
412
413         // Set sentPingMsg values with false.
414         entry->sentPingMsg = false;
415         entry->handle = NULL;
416     }
417
418     oc_mutex_unlock(g_mutexObjectList);
419     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveResponse OUT");
420     return OC_STACK_OK;
421 }
422
423 OCStackResult OCCreateKeepAliveResource()
424 {
425     OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource IN");
426
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,
432                                             NULL,
433                                             NULL,
434                                             OC_RES_PROP_NONE);
435     if (OC_STACK_OK == result)
436     {
437         result = BindResourceInterfaceToResource((OCResource *) g_keepAliveHandle,
438                                                  KEEPALIVE_RESOURCE_INTF_NAME);
439     }
440
441     if (OC_STACK_OK != result)
442     {
443         OIC_LOG_V(ERROR, TAG, "Create resource for KeepAlive failed[%d]", result);
444     }
445
446     OIC_LOG(DEBUG, TAG, "OCCreateKeepAliveResource OUT");
447     return result;
448 }
449
450 OCStackResult OCDeleteKeepAliveResource()
451 {
452     OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource IN");
453
454     // Create a KeepAlive resource
455     OCStackResult result = OCDeleteResource(g_keepAliveHandle);
456
457     if (OC_STACK_OK != result)
458     {
459         OIC_LOG_V(ERROR, TAG, "Delete resource for KeepAlive failed[%d]", result);
460     }
461
462     OIC_LOG(DEBUG, TAG, "OCDeleteKeepAliveResource OUT");
463     return result;
464 }
465
466 OCStackResult OCHandleKeepAliveRequest(OCServerRequest *request,
467                                        const OCResource *resource)
468 {
469     VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM);
470     VERIFY_NON_NULL(resource, FATAL, OC_STACK_INVALID_PARAM);
471
472     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest IN");
473
474     OCEntityHandlerResult result = OC_EH_ERROR;
475     if (OC_REST_GET == request->method)
476     {
477         switch ((OCObserveAction)request->observationOption)
478         {
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);
484                 break;
485             default:
486                 OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive");
487                 result = OC_EH_UNAUTHORIZED_REQ;
488         }
489     }
490     else if (OC_REST_PUT == request->method || OC_REST_POST == request->method)
491     {
492         OIC_LOG(DEBUG, TAG, "Received PUT/POST request");
493         result = OCHandleKeepAlivePOSTRequest(request, resource);
494     }
495     else
496     {
497         OIC_LOG(DEBUG, TAG, "Not Supported by KeepAlive");
498         result = OC_EH_UNAUTHORIZED_REQ;
499     }
500
501     OCStackResult ret = OCSendKeepAliveResponse(request, result);
502     if (OC_STACK_OK != ret)
503     {
504         OIC_LOG_V(ERROR, TAG, "SendKeepAliveResponse failed with result %u", ret);
505     }
506
507     OIC_LOG(DEBUG, TAG, "OCHandleKeepAliveRequest OUT");
508     return ret;
509 }
510
511 OCStackResult OCSendKeepAliveResponse(OCServerRequest *request,
512                                       OCEntityHandlerResult result)
513 {
514     VERIFY_NON_NULL(request, FATAL, OC_STACK_INVALID_PARAM);
515
516     OIC_LOG_V(DEBUG, TAG, "Send KeepAlive response with entity result[%d]", result);
517
518     // Convert OCDevAddr to CAEndpoint_t.
519     CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER};
520     CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
521
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);
526
527     // Create KeepAlive payload to send response message.
528     OCRepPayload *payload = OCCreateKeepAlivePayload(interval);
529
530     // Add resource type/interface name to payload for GET request.
531     if (OC_REST_GET == request->method && OC_EH_OK == result)
532     {
533         OCAddResourceTypeNameToPayload(payload);
534         OCAddResourceInterfaceNameToPayload(payload);
535     }
536
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);
542
543     // Send response message.
544     return OCDoResponse(&ehResponse);
545 }
546
547 OCEntityHandlerResult OCHandleKeepAliveGETRequest(OCServerRequest *request,
548                                                   const OCResource *resource)
549 {
550     VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR);
551     VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR);
552
553     OIC_LOG_V(DEBUG, TAG, "Find Ping resource [%s]", request->resourceUrl);
554
555     OCResource *resourcePtr = FindResourceByUri(request->resourceUrl);
556     if (!resourcePtr)
557     {
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;
561     }
562
563     return OC_EH_OK;
564 }
565
566 OCEntityHandlerResult OCHandleKeepAlivePOSTRequest(OCServerRequest *request,
567                                                    const OCResource *resource)
568 {
569     VERIFY_NON_NULL(request, FATAL, OC_EH_ERROR);
570     VERIFY_NON_NULL(resource, FATAL, OC_EH_ERROR);
571
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)
577     {
578         OIC_LOG(ERROR, TAG, "Representation parse failed");
579         return OC_EH_ERROR;
580     }
581     bool findValue = OCRepPayloadGetPropInt((OCRepPayload *) ocPayload, INTERVAL, &interval);
582     if (!findValue)
583     {
584         OIC_LOG(ERROR, TAG, "Can't find the time interval property");
585         OCPayloadDestroy(ocPayload);
586         return OC_EH_BAD_REQ;
587     }
588
589     // Get entry from KeepAlive table.
590     CAEndpoint_t endpoint = { .adapter = OC_ADAPTER_TCP };
591     CopyDevAddrToEndpoint(&request->devAddr, &endpoint);
592
593     oc_mutex_lock(g_mutexObjectList);
594     KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(&endpoint);
595     if (!entry)
596     {
597         OIC_LOG(ERROR, TAG, "Received the first keepalive message from client");
598         entry = OCAddKeepAliveEntry(&endpoint, OC_SERVER, 0);
599         if (!entry)
600         {
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;
605         }
606     }
607
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);
612
613     OCPayloadDestroy(ocPayload);
614     return OC_EH_OK;
615 }
616
617 #ifdef WITH_PROCESS_EVENT
618 void OCProcessKeepAlive(uint32_t *nextEventTime)
619 #else // WITH_PROCESS_EVENT
620 void OCProcessKeepAlive()
621 #endif // !WITH_PROCESS_EVENT
622 {
623     oc_mutex_lock(g_mutexObjectList);
624     KeepAliveEntry_t *entry = NULL;
625     KeepAliveEntry_t *tmp = NULL;
626     LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp)
627     {
628 #ifdef WITH_PROCESS_EVENT
629         uint64_t nextPingMicroSeconds = UINT64_MAX;
630 #endif // WITH_PROCESS_EVENT
631         if (entry)
632         {
633             uint64_t currentTime = OICGetCurrentTime(TIME_IN_US);
634             if (OC_CLIENT == entry->mode)
635             {
636                 if (entry->sentPingMsg)
637                 {
638                     /*
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.
642                      */
643                     if ((KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) <= currentTime - entry->timeStamp)
644                     {
645                         OIC_LOG(DEBUG, TAG, "Client does not receive the response within 1 minutes.");
646
647                         /* TCPDisconnectSession should be invoked depending on the result from client callback */
648                         if (OCSendDisconnectMessage(entry) == OC_STACK_CONTINUE)
649                         {
650                             // Set sentPingMsg values with false.
651                             entry->sentPingMsg = false;
652                             entry->handle = NULL;
653                         }
654                     }
655 #ifdef WITH_PROCESS_EVENT
656                     else
657                     {
658                         nextPingMicroSeconds = (KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) -
659                                                (currentTime - entry->timeStamp);
660                     }
661 #endif // WITH_PROCESS_EVENT
662                 }
663             }
664             else if (OC_SERVER == entry->mode)
665             {
666                 /*
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.
670                  */
671                 if ((entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC)
672                         <= currentTime - entry->timeStamp)
673                 {
674                     OIC_LOG(DEBUG, TAG, "Server does not receive a PUT/POST request.");
675                     OCSendDisconnectMessage(entry);
676                 }
677 #ifdef WITH_PROCESS_EVENT
678                 else
679                 {
680                     nextPingMicroSeconds =
681                         (entry->interval * KEEPALIVE_RESPONSE_TIMEOUT_SEC * USECS_PER_SEC) -
682                         (currentTime - entry->timeStamp);
683                 }
684 #endif // WITH_PROCESS_EVENT
685             }
686
687 #ifdef WITH_PROCESS_EVENT
688             if (nextEventTime && (nextPingMicroSeconds < UINT64_MAX))
689             {
690                 uint32_t nextPingMiliSeconds = (uint32_t)(nextPingMicroSeconds / US_PER_MS);
691                 uint32_t nextPingMicroRemain = (uint32_t)(nextPingMicroSeconds % US_PER_MS);
692                 if (nextPingMicroRemain > 0)
693                 {
694                     nextPingMiliSeconds += 1;   // To round up the remaining microsecond.
695                 }
696
697                 if (nextPingMiliSeconds < *nextEventTime)
698                 {
699                     *nextEventTime = nextPingMiliSeconds;
700                 }
701             }
702 #endif // WITH_PROCESS_EVENT
703             }
704     }
705     oc_mutex_unlock(g_mutexObjectList);
706 }
707
708 OCStackResult OCSendDisconnectMessage(const KeepAliveEntry_t *entry)
709 {
710     VERIFY_NON_NULL(entry, FATAL, OC_STACK_INVALID_PARAM);
711
712     // notify application that a client does not receive a response.
713     ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL);
714     if (cbNode)
715     {
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;
721
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)
724         {
725             return OC_STACK_CONTINUE;
726         }
727
728         FindAndDeleteClientCB(cbNode);
729     }
730
731     CAEndpoint_t endpoint = entry->remoteAddr;
732     if (OC_STACK_OK != OCRemoveKeepAliveEntry(&endpoint))
733     {
734         OIC_LOG(ERROR, TAG, "OCRemoveKeepAliveEntry is failed");
735         return OC_STACK_ERROR;
736     }
737
738     /*
739      * Send empty message to disconnect a connection.
740      * If CA get the empty message from RI, CA will disconnect a connection.
741      */
742     CAResult_t result = CAUtilTCPDisconnectSession(endpoint.addr, endpoint.port, endpoint.flags);
743     if (OC_STACK_OK != CAResultToOCResult(result))
744     {
745         OIC_LOG(ERROR, TAG, "Failed to disconnect session");
746     }
747
748     return CAResultToOCResult(result);
749 }
750
751 KeepAliveEntry_t *OCGetEntryFromEndpoint(const CAEndpoint_t *endpoint)
752 {
753     KeepAliveEntry_t *entry = NULL;
754     LL_FOREACH(g_keepAliveConnectionTable, entry)
755     {
756         if (entry)
757         {
758             if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
759                     && (entry->remoteAddr.port == endpoint->port))
760             {
761                 OIC_LOG(DEBUG, TAG, "Connection Info found in KeepAlive table");
762                 return entry;
763             }
764         }
765     }
766
767     return NULL;
768 }
769
770 KeepAliveEntry_t *OCAddKeepAliveEntry(const CAEndpoint_t *endpoint, OCMode mode,
771                                       int64_t interval)
772 {
773     if (!endpoint)
774     {
775         OIC_LOG(ERROR, TAG, "endpoint is NULL");
776         return NULL;
777     }
778
779     KeepAliveEntry_t *entry = (KeepAliveEntry_t *) OICCalloc(1, sizeof(KeepAliveEntry_t));
780     if (NULL == entry)
781     {
782         OIC_LOG(ERROR, TAG, "Failed to Calloc KeepAlive Entry");
783         return NULL;
784     }
785
786     entry->mode = mode;
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;
794
795     LL_APPEND(g_keepAliveConnectionTable, entry);
796 #ifdef WITH_PROCESS_EVENT
797     OCSendProcessEventSignal();
798 #endif // WITH_PROCESS_EVENT
799     return entry;
800 }
801
802 OCStackResult OCRemoveKeepAliveEntry(const CAEndpoint_t *endpoint)
803 {
804     OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry IN");
805
806     VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM);
807
808     KeepAliveEntry_t *entry = NULL;
809     KeepAliveEntry_t *tmp = NULL;
810     LL_FOREACH_SAFE(g_keepAliveConnectionTable, entry, tmp)
811     {
812         if (entry)
813         {
814             if (!strncmp(entry->remoteAddr.addr, endpoint->addr, sizeof(entry->remoteAddr.addr))
815                     && (entry->remoteAddr.port == endpoint->port))
816             {
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);
820
821                 LL_DELETE(g_keepAliveConnectionTable, entry);
822                 OICFree(entry);
823             }
824         }
825     }
826
827     OIC_LOG(DEBUG, TAG, "OCRemoveKeepAliveEntry OUT");
828     return OC_STACK_OK;
829 }
830
831 void OCHandleKeepAliveConnCB(const CAEndpoint_t *endpoint, bool isConnected, bool isClient)
832 {
833     (void) isClient;
834     VERIFY_NON_NULL_NR(endpoint, FATAL);
835
836     if (isConnected)
837     {
838         OIC_LOG(DEBUG, TAG, "Received the connected device information from CA");
839     }
840     else
841     {
842         OIC_LOG(DEBUG, TAG, "Received the disconnected device information from CA");
843
844         // Do nothing because callback will be removed after one min.
845         /*
846         // notify application that the session is disconnected.
847         oc_mutex_lock(g_mutexObjectList);
848         KeepAliveEntry_t *entry = OCGetEntryFromEndpoint(endpoint);
849         if (entry)
850         {
851             ClientCB *cbNode = GetClientCB(NULL, 0, entry->handle, NULL);
852             if (cbNode)
853             {
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;
859
860                 cbNode->callBack(cbNode->context, cbNode->handle, &response);
861                 FindAndDeleteClientCB(cbNode);
862             }
863             OCRemoveKeepAliveEntry(endpoint);
864         }
865         oc_mutex_unlock(g_mutexObjectList);
866         */
867     }
868 }
869
870 OCRepPayload *OCCreateKeepAlivePayload(int64_t interval)
871 {
872     OIC_LOG_V(DEBUG, TAG, "Create KeepAlive Payload, interval is [%" PRId64 "]", interval);
873
874     OCRepPayload *payload = OCRepPayloadCreate();
875     if (!payload)
876     {
877         OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
878         return NULL;
879     }
880     payload->base.type = PAYLOAD_TYPE_REPRESENTATION;
881     OCRepPayloadSetPropInt(payload, INTERVAL, interval);
882
883     return payload;
884 }
885
886 OCStackResult OCAddResourceTypeNameToPayload(OCRepPayload *payload)
887 {
888     uint8_t numElement = 0;
889     OCStackResult res = OCGetNumberOfResourceTypes(g_keepAliveHandle, &numElement);
890     if (OC_STACK_OK == res)
891     {
892         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
893         char **rt = (char **)OICMalloc(sizeof(char *) * numElement);
894         if (!rt)
895         {
896             OIC_LOG(ERROR, TAG, "Could not allocate memory for rf");
897             return OC_STACK_NO_MEMORY;
898         }
899         for (uint8_t i = 0; i < numElement; ++i)
900         {
901             const char *value = OCGetResourceTypeName(g_keepAliveHandle, i);
902             OIC_LOG_V(DEBUG, TAG, "value: %s", value);
903             rt[i] = OICStrdup(value);
904             if (NULL == rt[i])
905             {
906                 OIC_LOG_V(ERROR, TAG, "Creating duplicate string for rt failed!");
907                 for (uint8_t j = 0; j < i; ++j)
908                 {
909                     OICFree(rt[j]);
910                 }
911                 OICFree(rt);
912                 return OC_STACK_NO_MEMORY;
913             }
914         }
915         OCRepPayloadSetStringArray(payload, OC_RSRVD_RESOURCE_TYPE, (const char **) rt, rtDim);
916         for (uint8_t i = 0; i < numElement; ++i)
917         {
918             OICFree(rt[i]);
919         }
920         OICFree(rt);
921     }
922
923     return res;
924 }
925
926 OCStackResult OCAddResourceInterfaceNameToPayload(OCRepPayload *payload)
927 {
928     uint8_t numElement = 0;
929     OCStackResult res = OCGetNumberOfResourceInterfaces(g_keepAliveHandle, &numElement);
930     if (OC_STACK_OK == res)
931     {
932         size_t ifDim[MAX_REP_ARRAY_DEPTH] = {numElement, 0, 0};
933         char **itf = (char **)OICMalloc(sizeof(char *) * numElement);
934         if (!itf)
935         {
936             OIC_LOG(ERROR, TAG, "Could not allocate memory for itf");
937             return OC_STACK_NO_MEMORY;
938         }
939
940         for (uint8_t i = 0; i < numElement; ++i)
941         {
942             const char *value = OCGetResourceInterfaceName(g_keepAliveHandle, i);
943             OIC_LOG_V(DEBUG, TAG, "value: %s", value);
944             itf[i] = OICStrdup(value);
945             if (NULL == itf[i])
946             {
947                 OIC_LOG_V(ERROR, TAG, "Creating duplicate string for itf failed!");
948                 for (uint8_t j = 0; j < i; ++j)
949                 {
950                     OICFree(itf[j]);
951                 }
952                 OICFree(itf);
953                 return OC_STACK_NO_MEMORY;
954             }
955         }
956         OCRepPayloadSetStringArray(payload, OC_RSRVD_INTERFACE, (const char **) itf, ifDim);
957         for (uint8_t i = 0; i < numElement; ++i)
958         {
959             OICFree(itf[i]);
960         }
961         OICFree(itf);
962     }
963
964     return res;
965 }