[IOT-1554] Added error callback when adapter is terminated
[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 #ifndef __STDC_FORMAT_MACROS
27 #define __STDC_FORMAT_MACROS
28 #endif
29 #include <inttypes.h>
30
31 #include "cainterface.h"
32 #include "caipnwmonitor.h"
33 #include "catcpadapter.h"
34 #include "catcpinterface.h"
35 #include "caqueueingthread.h"
36 #include "caadapterutils.h"
37 #include "camutex.h"
38 #include "uarraylist.h"
39 #include "caremotehandler.h"
40 #include "logger.h"
41 #include "oic_malloc.h"
42 #ifdef __WITH_TLS__
43 #include "ca_adapter_net_ssl.h"
44 #endif
45
46 /**
47  * Logging tag for module name.
48  */
49 #define TAG "OIC_CA_TCP_ADAP"
50
51 /**
52  * Holds internal thread TCP data information.
53  */
54 typedef struct
55 {
56     CAEndpoint_t *remoteEndpoint;
57     void *data;
58     size_t dataLen;
59     bool isMulticast;
60 } CATCPData;
61
62 #define CA_TCP_LISTEN_BACKLOG  3
63
64 #define CA_TCP_SELECT_TIMEOUT 10
65
66 /**
67  * Queue handle for Send Data.
68  */
69 static CAQueueingThread_t *g_sendQueueHandle = NULL;
70
71 /**
72  * Network Packet Received Callback to CA.
73  */
74 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
75
76 /**
77  * Adapter Changed Callback to CA.
78  */
79 static CAAdapterChangeCallback g_networkChangeCallback = NULL;
80
81 /**
82  * Connection Changed Callback to CA.
83  */
84 static CAConnectionChangeCallback g_connectionChangeCallback = NULL;
85
86 /**
87  * error Callback to CA adapter.
88  */
89 static CAErrorHandleCallback g_errorCallback = NULL;
90
91 static void CATCPPacketReceivedCB(const CASecureEndpoint_t *sep,
92                                   const void *data, uint32_t dataLength);
93
94 static void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
95                               size_t dataLength, CAResult_t result);
96
97 /**
98  * KeepAlive Connected or Disconnected Callback to CA adapter.
99  */
100 static CAKeepAliveConnectionCallback g_connKeepAliveCallback = NULL;
101
102 static CAResult_t CATCPInitializeQueueHandles();
103
104 static void CATCPDeinitializeQueueHandles();
105
106 static void CATCPSendDataThread(void *threadData);
107
108 static CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint,
109                                   const void *data, size_t dataLength,
110                                   bool isMulticast);
111 void CAFreeTCPData(CATCPData *ipData);
112
113 static void CADataDestroyer(void *data, uint32_t size);
114
115 CAResult_t CATCPInitializeQueueHandles()
116 {
117     // Check if the message queue is already initialized
118     if (g_sendQueueHandle)
119     {
120         OIC_LOG(DEBUG, TAG, "send queue handle is already initialized!");
121         return CA_STATUS_OK;
122     }
123
124     // Create send message queue
125     g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
126     if (!g_sendQueueHandle)
127     {
128         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
129         return CA_MEMORY_ALLOC_FAILED;
130     }
131
132     if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
133                                 (const ca_thread_pool_t)caglobals.tcp.threadpool,
134                                 CATCPSendDataThread, CADataDestroyer))
135     {
136         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
137         OICFree(g_sendQueueHandle);
138         g_sendQueueHandle = NULL;
139         return CA_STATUS_FAILED;
140     }
141
142     return CA_STATUS_OK;
143 }
144
145 void CATCPDeinitializeQueueHandles()
146 {
147     CAQueueingThreadDestroy(g_sendQueueHandle);
148     OICFree(g_sendQueueHandle);
149     g_sendQueueHandle = NULL;
150 }
151
152 void CATCPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
153 {
154     (void)ipAddress;
155     (void)status;
156 }
157
158 void CATCPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
159                            uint32_t dataLength)
160 {
161     VERIFY_NON_NULL_VOID(sep, TAG, "sep is NULL");
162     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
163
164     OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", sep->endpoint.addr, sep->endpoint.port);
165
166     if (g_networkPacketCallback)
167     {
168         g_networkPacketCallback(sep, data, dataLength);
169     }
170 }
171
172 #ifdef __WITH_TLS__
173 static ssize_t CATCPPacketSendCB(CAEndpoint_t *endpoint, const void *data, size_t dataLength)
174 {
175     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
176     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", -1);
177     VERIFY_NON_NULL_RET(data, TAG, "data is NULL", -1);
178
179     OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", endpoint->addr, endpoint->port);
180     OIC_LOG_BUFFER(DEBUG, TAG, data, dataLength);
181
182     ssize_t ret = CATCPSendData(endpoint, data, dataLength);
183     if (-1 == ret)
184     {
185         CASearchAndDeleteTCPSession(endpoint);
186         CATCPErrorHandler(endpoint, data, dataLength, CA_SEND_FAILED);
187     }
188     OIC_LOG_V(DEBUG, TAG, "Out %s : %d bytes sent", __func__, ret);
189     return ret;
190 }
191 #endif
192
193 static void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
194                               size_t dataLength, CAResult_t result)
195 {
196     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
197     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
198
199     if (g_errorCallback)
200     {
201         g_errorCallback(endpoint, data, dataLength, result);
202     }
203 }
204
205 static void CATCPConnectionHandler(const CAEndpoint_t *endpoint, bool isConnected)
206 {
207     // Pass the changed connection status to RI Layer for keepalive.
208     if (g_connKeepAliveCallback)
209     {
210         g_connKeepAliveCallback(endpoint, isConnected);
211     }
212
213     // Pass the changed connection status to CAUtil.
214     if (g_connectionChangeCallback)
215     {
216         g_connectionChangeCallback(endpoint, isConnected);
217     }
218 }
219
220 void CATCPSetKeepAliveCallbacks(CAKeepAliveConnectionCallback ConnHandler)
221 {
222     g_connKeepAliveCallback = ConnHandler;
223 }
224
225 void CATCPAdapterHandler(CATransportAdapter_t adapter, CANetworkStatus_t status)
226 {
227     if (g_networkChangeCallback)
228     {
229         g_networkChangeCallback(adapter, status);
230     }
231
232     if (CA_INTERFACE_DOWN == status)
233     {
234         OIC_LOG(DEBUG, TAG, "Network status is down, close all session");
235         CATCPStopServer();
236     }
237     else if (CA_INTERFACE_UP == status)
238     {
239         OIC_LOG(DEBUG, TAG, "Network status is up, create new socket for listening");
240
241         CAResult_t ret = CA_STATUS_FAILED;
242 #ifndef SINGLE_THREAD
243         ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
244 #else
245         ret = CATCPStartServer();
246 #endif
247         if (CA_STATUS_OK != ret)
248         {
249             OIC_LOG_V(DEBUG, TAG, "CATCPStartServer failed[%d]", ret);
250         }
251     }
252 }
253
254 static void CAInitializeTCPGlobals()
255 {
256     caglobals.tcp.ipv4.fd = -1;
257     caglobals.tcp.ipv6.fd = -1;
258     caglobals.tcp.selectTimeout = CA_TCP_SELECT_TIMEOUT;
259     caglobals.tcp.listenBacklog = CA_TCP_LISTEN_BACKLOG;
260     caglobals.tcp.svrlist = NULL;
261
262     CATransportFlags_t flags = 0;
263     if (caglobals.client)
264     {
265         flags |= caglobals.clientFlags;
266     }
267     if (caglobals.server)
268     {
269         flags |= caglobals.serverFlags;
270     }
271
272     caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
273     caglobals.tcp.ipv6tcpenabled = flags & CA_IPV6;
274 }
275
276 CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
277                            CANetworkPacketReceivedCallback networkPacketCallback,
278                            CAAdapterChangeCallback netCallback,
279                            CAConnectionChangeCallback connCallback,
280                            CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
281 {
282     OIC_LOG(DEBUG, TAG, "IN");
283     VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
284     VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
285     VERIFY_NON_NULL(netCallback, TAG, "netCallback");
286 #ifndef SINGLE_THREAD
287     VERIFY_NON_NULL(handle, TAG, "thread pool handle");
288 #endif
289
290     g_networkChangeCallback = netCallback;
291     g_connectionChangeCallback = connCallback;
292     g_networkPacketCallback = networkPacketCallback;
293     g_errorCallback = errorCallback;
294
295     CAInitializeTCPGlobals();
296 #ifndef SINGLE_THREAD
297     caglobals.tcp.threadpool = handle;
298 #endif
299
300     CATCPSetConnectionChangedCallback(CATCPConnectionHandler);
301     CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
302     CATCPSetErrorHandler(CATCPErrorHandler);
303
304 #ifdef __WITH_TLS__
305     if (CA_STATUS_OK != CAinitSslAdapter())
306     {
307         OIC_LOG(ERROR, TAG, "Failed to init SSL adapter");
308     }
309     else
310     {
311         CAsetSslAdapterCallbacks(CATCPPacketReceivedCB, CATCPPacketSendCB, CA_ADAPTER_TCP);
312     }
313 #endif
314
315     CAConnectivityHandler_t tcpHandler = {
316         .startAdapter = CAStartTCP,
317         .startListenServer = CAStartTCPListeningServer,
318         .stopListenServer = CAStopTCPListeningServer,
319         .startDiscoveryServer = CAStartTCPDiscoveryServer,
320         .sendData = CASendTCPUnicastData,
321         .sendDataToAll = CASendTCPMulticastData,
322         .GetnetInfo = CAGetTCPInterfaceInformation,
323         .readData = CAReadTCPData,
324         .stopAdapter = CAStopTCP,
325         .terminate = CATerminateTCP,
326         .cType = CA_ADAPTER_TCP};
327
328     registerCallback(tcpHandler);
329
330     OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
331     return CA_STATUS_OK;
332 }
333
334 CAResult_t CAStartTCP()
335 {
336     OIC_LOG(DEBUG, TAG, "IN");
337
338     // Start network monitoring to receive adapter status changes.
339     CAIPStartNetworkMonitor(CATCPAdapterHandler, CA_ADAPTER_TCP);
340
341     // Set the port number received from application.
342     caglobals.tcp.ipv4.port = caglobals.ports.tcp.u4;
343     caglobals.tcp.ipv6.port = caglobals.ports.tcp.u6;
344
345 #ifndef SINGLE_THREAD
346     if (CA_STATUS_OK != CATCPInitializeQueueHandles())
347     {
348         OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
349         CATerminateTCP();
350         return CA_STATUS_FAILED;
351     }
352
353     // Start send queue thread
354     if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
355     {
356         OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
357         return CA_STATUS_FAILED;
358     }
359 #else
360     CAResult_t ret = CATCPStartServer();
361     if (CA_STATUS_OK != ret)
362     {
363         OIC_LOG_V(DEBUG, TAG, "CATCPStartServer failed[%d]", ret);
364         return ret;
365     }
366 #endif
367
368     return CA_STATUS_OK;
369 }
370
371 CAResult_t CAStartTCPListeningServer()
372 {
373 #ifndef SINGLE_THREAD
374     if (!caglobals.server)
375     {
376         caglobals.server = true;    // only needed to run CA tests
377     }
378
379     CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
380     if (CA_STATUS_OK != ret)
381     {
382         OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
383         return ret;
384     }
385 #endif
386
387     return CA_STATUS_OK;
388 }
389
390 CAResult_t CAStopTCPListeningServer()
391 {
392     return CA_STATUS_OK;
393 }
394
395 CAResult_t CAStartTCPDiscoveryServer()
396 {
397     if (!caglobals.client)
398     {
399         caglobals.client = true;    // only needed to run CA tests
400     }
401
402     CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
403     if (CA_STATUS_OK != ret)
404     {
405         OIC_LOG_V(ERROR, TAG, "Failed to start discovery server![%d]", ret);
406         return ret;
407     }
408
409     return CA_STATUS_OK;
410 }
411
412 static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
413                              const void *data, size_t dataLength)
414 {
415     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", -1);
416     VERIFY_NON_NULL_RET(data, TAG, "data", -1);
417
418     if (0 == dataLength)
419     {
420         OIC_LOG(ERROR, TAG, "Invalid Data Length");
421         return -1;
422     }
423
424     VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
425
426     // Create TCPData to add to queue
427     CATCPData *tcpData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
428     if (!tcpData)
429     {
430         OIC_LOG(ERROR, TAG, "Failed to create ipData!");
431         return -1;
432     }
433     // Add message to send queue
434     CAQueueingThreadAddData(g_sendQueueHandle, tcpData, sizeof(CATCPData));
435
436     return dataLength;
437 }
438
439 int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
440                              const void *data, uint32_t dataLength,
441                              CADataType_t dataType)
442 {
443     OIC_LOG(DEBUG, TAG, "IN");
444     (void)dataType;
445 #ifndef SINGLE_THREAD
446     return CAQueueTCPData(false, endpoint, data, dataLength);
447 #else
448     return CATCPSendData(endpoint, data, dataLength);
449 #endif
450 }
451
452 int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
453                                const void *data, uint32_t dataLength,
454                                CADataType_t dataType)
455 {
456     (void)dataType;
457     return CAQueueTCPData(true, endpoint, data, dataLength);
458 }
459
460 CAResult_t CAReadTCPData()
461 {
462     OIC_LOG(DEBUG, TAG, "IN");
463 #ifdef SINGLE_THREAD
464     CATCPPullData();
465 #endif
466     return CA_STATUS_OK;
467 }
468
469 CAResult_t CAStopTCP()
470 {
471     CAIPStopNetworkMonitor(CA_ADAPTER_TCP);
472
473 #ifndef SINGLE_THREAD
474     if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
475     {
476         CAQueueingThreadStop(g_sendQueueHandle);
477     }
478     CATCPDeinitializeQueueHandles();
479 #endif
480
481     CATCPStopServer();
482
483     //Re-initializing the Globals to start them again
484     CAInitializeTCPGlobals();
485
486 #ifdef __WITH_TLS__
487     CAdeinitSslAdapter();
488 #endif
489
490     return CA_STATUS_OK;
491 }
492
493 void CATerminateTCP()
494 {
495     CAStopTCP();
496     CATCPSetPacketReceiveCallback(NULL);
497 }
498
499 void CATCPSendDataThread(void *threadData)
500 {
501     CATCPData *tcpData = (CATCPData *) threadData;
502     if (!tcpData)
503     {
504         OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
505         return;
506     }
507
508     if (caglobals.tcp.terminate)
509     {
510         OIC_LOG(DEBUG, TAG, "Adapter is not enabled");
511         CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
512                           CA_SEND_FAILED);
513         return;
514     }
515
516     if (tcpData->isMulticast)
517     {
518         //Processing for sending multicast
519         OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
520         return;
521     }
522     else
523     {
524         // Check payload length from CoAP over TCP format header.
525         CAResult_t result = CA_STATUS_OK;
526         size_t payloadLen = CACheckPayloadLengthFromHeader(tcpData->data, tcpData->dataLen);
527         if (!payloadLen)
528         {
529             // if payload length is zero, disconnect from remote device.
530             OIC_LOG(DEBUG, TAG, "payload length is zero, disconnect from remote device");
531 #ifdef __WITH_TLS__
532             if (CA_STATUS_OK != CAcloseSslConnection(tcpData->remoteEndpoint))
533             {
534                 OIC_LOG(ERROR, TAG, "Failed to close TLS session");
535             }
536 #endif
537             CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
538             return;
539         }
540
541 #ifdef __WITH_TLS__
542          if (tcpData->remoteEndpoint && tcpData->remoteEndpoint->flags & CA_SECURE)
543          {
544              OIC_LOG(DEBUG, TAG, "CAencryptSsl called!");
545              result = CAencryptSsl(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
546
547              if (CA_STATUS_OK != result)
548              {
549                  OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
550              }
551              OIC_LOG_V(DEBUG, TAG,
552                        "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
553             return;
554          }
555 #endif
556         //Processing for sending unicast
557          ssize_t dlen = CATCPSendData(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen);
558          if (-1 == dlen)
559          {
560              CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
561              CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
562                                CA_SEND_FAILED);
563          }
564     }
565 }
566
567 CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
568                            size_t dataLength, bool isMulticast)
569 {
570     VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
571     VERIFY_NON_NULL_RET(data, TAG, "data is NULL", NULL);
572
573     CATCPData *tcpData = (CATCPData *) OICCalloc(1, sizeof(*tcpData));
574     if (!tcpData)
575     {
576         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
577         return NULL;
578     }
579
580     tcpData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
581     tcpData->data = (void *) OICMalloc(dataLength);
582     if (!tcpData->data)
583     {
584         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
585         CAFreeTCPData(tcpData);
586         return NULL;
587     }
588
589     memcpy(tcpData->data, data, dataLength);
590     tcpData->dataLen = dataLength;
591
592     tcpData->isMulticast = isMulticast;
593
594     return tcpData;
595 }
596
597 void CAFreeTCPData(CATCPData *tcpData)
598 {
599     VERIFY_NON_NULL_VOID(tcpData, TAG, "tcpData is NULL");
600
601     CAFreeEndpoint(tcpData->remoteEndpoint);
602     OICFree(tcpData->data);
603     OICFree(tcpData);
604 }
605
606 void CADataDestroyer(void *data, uint32_t size)
607 {
608     if (size < sizeof(CATCPData))
609     {
610         OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %" PRIu32, data, size);
611     }
612     CATCPData *TCPData = (CATCPData *) data;
613
614     CAFreeTCPData(TCPData);
615 }
616
617 #ifdef SINGLE_THREAD
618 size_t CAGetTotalLengthFromPacketHeader(const unsigned char *recvBuffer, size_t size)
619 {
620     OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
621
622     if (NULL == recvBuffer || !size)
623     {
624         OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
625         return 0;
626     }
627
628     coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
629             ((unsigned char *)recvBuffer)[0] >> 4);
630     size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
631                                                         transport);
632     size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
633
634     OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
635     OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
636     OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
637
638     OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
639     return headerLen + optPaylaodLen;
640 }
641
642 void CAGetTCPHeaderDetails(unsigned char* recvBuffer, coap_transport_t *transport,
643                            size_t *headerlen)
644 {
645     if (NULL == recvBuffer)
646     {
647         OIC_LOG(ERROR, TAG, "recvBuffer is NULL");
648         return;
649     }
650
651     if (NULL == transport)
652     {
653         OIC_LOG(ERROR, TAG, "transport is NULL");
654         return;
655     }
656
657     if (NULL == headerlen)
658     {
659         OIC_LOG(ERROR, TAG, "headerlen is NULL");
660         return;
661     }
662
663     *transport = coap_get_tcp_header_type_from_initbyte(
664         ((unsigned char *)recvBuffer)[0] >> 4);
665     *headerlen = coap_get_tcp_header_length_for_transport(*transport);
666 }
667 #endif