keepalive for coap over tcp
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / tcp_adapter / catcpadapter.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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdint.h>
25
26 #define __STDC_FORMAT_MACROS
27 #include <inttypes.h>
28
29 #include "cainterface.h"
30 #include "catcpadapter.h"
31 #include "catcpinterface.h"
32 #include "caqueueingthread.h"
33 #include "caadapterutils.h"
34 #include "camutex.h"
35 #include "uarraylist.h"
36 #include "caremotehandler.h"
37 #include "logger.h"
38 #include "oic_malloc.h"
39 #include "oic_string.h"
40
41 /**
42  * Logging tag for module name.
43  */
44 #define TAG "OIC_CA_TCP_ADAP"
45
46 /**
47  * Holds internal thread TCP data information.
48  */
49 typedef struct
50 {
51     CAEndpoint_t *remoteEndpoint;
52     void *data;
53     size_t dataLen;
54     bool isMulticast;
55 } CATCPData;
56
57 #define CA_TCP_LISTEN_BACKLOG  3
58
59 #define CA_TCP_SELECT_TIMEOUT 10
60
61 /**
62  * Queue handle for Send Data.
63  */
64 static CAQueueingThread_t *g_sendQueueHandle = NULL;
65
66 /**
67  * Network Packet Received Callback to CA.
68  */
69 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
70
71 /**
72  * Network Changed Callback to CA.
73  */
74 static CANetworkChangeCallback g_networkChangeCallback = NULL;
75
76 /**
77  * error Callback to CA adapter.
78  */
79 static CAErrorHandleCallback g_errorCallback = NULL;
80
81 static void CATCPPacketReceivedCB(const CASecureEndpoint_t *sep,
82                                   const void *data, uint32_t dataLength);
83
84 /**
85  * KeepAlive Connected Callback to CA adapter.
86  */
87 static CAKeepAliveConnectedCallback g_connCallback = NULL;
88
89 /**
90  * KeepAlive Disconnected Callback to CA adapter.
91  */
92 static CAKeepAliveDisconnectedCallback g_disconnCallback = NULL;
93
94 static CAResult_t CATCPInitializeQueueHandles();
95
96 static void CATCPDeinitializeQueueHandles();
97
98 static void CATCPSendDataThread(void *threadData);
99
100 static CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint,
101                                   const void *data, size_t dataLength,
102                                   bool isMulticast);
103 void CAFreeTCPData(CATCPData *ipData);
104
105 static void CADataDestroyer(void *data, uint32_t size);
106
107 CAResult_t CATCPInitializeQueueHandles()
108 {
109     // Check if the message queue is already initialized
110     if (g_sendQueueHandle)
111     {
112         OIC_LOG(DEBUG, TAG, "send queue handle is already initialized!");
113         return CA_STATUS_OK;
114     }
115
116     // Create send message queue
117     g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
118     if (!g_sendQueueHandle)
119     {
120         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
121         return CA_MEMORY_ALLOC_FAILED;
122     }
123
124     if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
125                                 (const ca_thread_pool_t)caglobals.tcp.threadpool,
126                                 CATCPSendDataThread, CADataDestroyer))
127     {
128         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
129         OICFree(g_sendQueueHandle);
130         g_sendQueueHandle = NULL;
131         return CA_STATUS_FAILED;
132     }
133
134     return CA_STATUS_OK;
135 }
136
137 void CATCPDeinitializeQueueHandles()
138 {
139     CAQueueingThreadDestroy(g_sendQueueHandle);
140     OICFree(g_sendQueueHandle);
141     g_sendQueueHandle = NULL;
142 }
143
144 void CATCPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
145 {
146     (void)ipAddress;
147     (void)status;
148 }
149
150 void CATCPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
151                            uint32_t dataLength)
152 {
153     VERIFY_NON_NULL_VOID(sep, TAG, "sep is NULL");
154     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
155
156     OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", sep->endpoint.addr, sep->endpoint.port);
157
158     if (g_networkPacketCallback)
159     {
160         g_networkPacketCallback(sep, data, dataLength);
161     }
162 }
163
164 void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
165                        uint32_t dataLength, CAResult_t result)
166 {
167     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
168     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
169
170     if (g_errorCallback)
171     {
172         g_errorCallback(endpoint, data, dataLength, result);
173     }
174 }
175
176 static void CATCPKeepAliveHandler(const char *addr, uint16_t port, bool isConnected)
177 {
178     CAEndpoint_t endpoint = { .adapter =  CA_ADAPTER_TCP,
179                               .port = port };
180     OICStrcpy(endpoint.addr, sizeof(endpoint.addr), addr);
181
182     if (isConnected)
183     {
184         g_connCallback(&endpoint);
185     }
186     else
187     {
188         g_disconnCallback(&endpoint);
189     }
190 }
191
192 void CATCPSetKeepAliveCallbacks(CAKeepAliveConnectedCallback ConnHandler,
193                                 CAKeepAliveDisconnectedCallback DisconnHandler)
194 {
195     g_connCallback = ConnHandler;
196     g_disconnCallback = DisconnHandler;
197
198     CATCPSetKeepAliveCallback(CATCPKeepAliveHandler);
199 }
200
201 static void CAInitializeTCPGlobals()
202 {
203     caglobals.tcp.selectTimeout = CA_TCP_SELECT_TIMEOUT;
204     caglobals.tcp.listenBacklog = CA_TCP_LISTEN_BACKLOG;
205     caglobals.tcp.svrlist = NULL;
206
207     CATransportFlags_t flags = 0;
208     if (caglobals.client)
209     {
210         flags |= caglobals.clientFlags;
211     }
212     if (caglobals.server)
213     {
214         flags |= caglobals.serverFlags;
215     }
216
217     caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
218 }
219
220 CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
221                            CANetworkPacketReceivedCallback networkPacketCallback,
222                            CANetworkChangeCallback netCallback,
223                            CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
224 {
225     OIC_LOG(DEBUG, TAG, "IN");
226     VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
227     VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
228     VERIFY_NON_NULL(netCallback, TAG, "netCallback");
229     VERIFY_NON_NULL(handle, TAG, "thread pool handle");
230
231     g_networkChangeCallback = netCallback;
232     g_networkPacketCallback = networkPacketCallback;
233     g_errorCallback = errorCallback;
234
235     CAInitializeTCPGlobals();
236     caglobals.tcp.threadpool = handle;
237
238     CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
239     CATCPSetErrorHandler(CATCPErrorHandler);
240
241     CAConnectivityHandler_t TCPHandler = {
242         .startAdapter = CAStartTCP,
243         .startListenServer = CAStartTCPListeningServer,
244         .stopListenServer = CAStopTCPListeningServer,
245         .startDiscoveryServer = CAStartTCPDiscoveryServer,
246         .sendData = CASendTCPUnicastData,
247         .sendDataToAll = CASendTCPMulticastData,
248         .GetnetInfo = CAGetTCPInterfaceInformation,
249         .readData = CAReadTCPData,
250         .stopAdapter = CAStopTCP,
251         .terminate = CATerminateTCP };
252     registerCallback(TCPHandler, CA_ADAPTER_TCP);
253
254     OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
255     return CA_STATUS_OK;
256 }
257
258 CAResult_t CAStartTCP()
259 {
260     if (CA_STATUS_OK != CATCPInitializeQueueHandles())
261     {
262         OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
263         CATerminateTCP();
264         return CA_STATUS_FAILED;
265     }
266
267     // Start send queue thread
268     if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
269     {
270         OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
271         return CA_STATUS_FAILED;
272     }
273
274     CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
275     if (CA_STATUS_OK != ret)
276     {
277         OIC_LOG_V(ERROR, TAG, "Failed to start server![%d]", ret);
278         return ret;
279     }
280
281     return CA_STATUS_OK;
282 }
283
284 CAResult_t CAStartTCPListeningServer()
285 {
286     return CA_STATUS_OK;
287 }
288
289 CAResult_t CAStopTCPListeningServer()
290 {
291     return CA_STATUS_OK;
292 }
293
294 CAResult_t CAStartTCPDiscoveryServer()
295 {
296     return CA_STATUS_OK;
297 }
298
299 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
300                              const void *data, size_t dataLength)
301 {
302     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
303     VERIFY_NON_NULL_RET(data, TAG, "data", -1);
304
305     if (0 == dataLength)
306     {
307         OIC_LOG(ERROR, TAG, "Invalid Data Length");
308         return -1;
309     }
310
311     VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
312
313     // Create TCPData to add to queue
314     CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
315     if (!tcpData)
316     {
317         OIC_LOG(ERROR, TAG, "Failed to create ipData!");
318         return -1;
319     }
320     // Add message to send queue
321     CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
322
323     return dataLength;
324 }
325
326 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
327                              const void *data, uint32_t dataLength)
328 {
329     return CAQueueTCPData(false, endpoint, data, dataLength);
330 }
331
332 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
333                                const void *data, uint32_t dataLength)
334 {
335     return CAQueueTCPData(true, endpoint, data, dataLength);
336 }
337
338 CAResult_t CAReadTCPData()
339 {
340     return CA_STATUS_OK;
341 }
342
343 CAResult_t CAStopTCP()
344 {
345     if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
346     {
347         CAQueueingThreadStop(g_sendQueueHandle);
348     }
349
350     CATCPStopServer();
351
352     //Re-initializing the Globals to start them again
353     CAInitializeTCPGlobals();
354
355     return CA_STATUS_OK;
356 }
357
358 void CATerminateTCP()
359 {
360     CATCPSetPacketReceiveCallback(NULL);
361
362     CATCPDeinitializeQueueHandles();
363 }
364
365 void CATCPSendDataThread(void *threadData)
366 {
367     CATCPData *tcpData = (CATCPData *) threadData;
368     if (!tcpData)
369     {
370         OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
371         return;
372     }
373
374     if (tcpData->isMulticast)
375     {
376         //Processing for sending multicast
377         OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
378         return;
379     }
380     else
381     {
382         //Processing for sending unicast
383         CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen, false);
384     }
385 }
386
387 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
388                            size_t dataLength, bool isMulticast)
389 {
390     VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
391     VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
392
393     CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
394     if (!tcpData)
395     {
396         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
397         return NULL;
398     }
399
400     tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
401     tcpData->data = (void *) OICMalloc(dataLength);
402     if (!tcpData->data)
403     {
404         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
405         CAFreeTCPData(tcpData);
406         return NULL;
407     }
408
409     memcpy(tcpData->data, data, dataLength);
410     tcpData->dataLen = dataLength;
411
412     tcpData->isMulticast = isMulticast;
413
414     return tcpData;
415 }
416
417 void CAFreeTCPData(CATCPData *tcpData)
418 {
419     VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
420
421     CAFreeEndpoint(tcpData->remoteEndpoint);
422     OICFree(tcpData->data);
423     OICFree(tcpData);
424 }
425
426 void CADataDestroyer(void *data, uint32_t size)
427 {
428     if (size < sizeof(CATCPData))
429     {
430         OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
431     }
432     CATCPData *TCPData = (CATCPData *) data;
433
434     CAFreeTCPData(TCPData);
435 }