Drop arduino support: SINGLE_THREAD
[iotivity.git] / resource / csdk / connectivity / src / ip_adapter / caipadapter.c
1 /* ****************************************************************
2  *
3  * Copyright 2014 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 #include "caipadapter.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26
27 #include "caipnwmonitor.h"
28 #include "caipinterface.h"
29 #include "caqueueingthread.h"
30 #include "caadapterutils.h"
31 #ifdef __WITH_DTLS__
32 #include "ca_adapter_net_ssl.h"
33 #endif
34 #include "octhread.h"
35 #include "uarraylist.h"
36 #include "caremotehandler.h"
37 #include "experimental/logger.h"
38 #include "oic_malloc.h"
39 #include "oic_string.h"
40 #include "iotivity_debug.h"
41
42 /**
43  * Logging tag for module name.
44  */
45 #define TAG "OIC_CA_IP_ADAP"
46
47 /**
48  * Holds inter thread ip data information.
49  */
50 typedef struct
51 {
52     CAEndpoint_t *remoteEndpoint;
53     void *data;
54     uint32_t dataLen;
55     bool isMulticast;
56 } CAIPData_t;
57
58 /**
59  * Queue handle for Send Data.
60  */
61 static CAQueueingThread_t *g_sendQueueHandle = NULL;
62
63 /**
64  * List of the endpoint that has a stack-owned IP address.
65  */
66 static u_arraylist_t *g_ownIpEndpointList = NULL;
67
68 /**
69  * Network Packet Received Callback to CA.
70  */
71 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
72
73 /**
74  * Network Changed Callback to CA.
75  */
76 static CAAdapterChangeCallback g_networkChangeCallback = NULL;
77
78 /**
79  * error Callback to CA adapter.
80  */
81 static CAErrorHandleCallback g_errorCallback = NULL;
82
83 static void CAIPPacketReceivedCB(const CASecureEndpoint_t *endpoint,
84                                  const void *data, size_t dataLength);
85 #ifdef __WITH_DTLS__
86 static ssize_t CAIPPacketSendCB(CAEndpoint_t *endpoint,
87                                 const void *data, size_t dataLength);
88 #endif
89
90 static void CAUpdateStoredIPAddressInfo(CANetworkStatus_t status);
91
92
93 static CAResult_t CAIPInitializeQueueHandles();
94
95 static void CAIPDeinitializeQueueHandles();
96
97 static void CAIPSendDataThread(void *threadData);
98
99 static CAIPData_t *CACreateIPData(const CAEndpoint_t *remoteEndpoint,
100                                   const void *data, uint32_t dataLength,
101                                   bool isMulticast);
102
103 void CAFreeIPData(CAIPData_t *ipData);
104
105 static void CADataDestroyer(void *data, uint32_t size);
106
107 CAResult_t CAIPInitializeQueueHandles()
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     g_ownIpEndpointList = u_arraylist_create();
117     if (!g_ownIpEndpointList)
118     {
119         OIC_LOG(ERROR, TAG, "Memory allocation failed! (g_ownIpEndpointList)");
120         return CA_MEMORY_ALLOC_FAILED;
121     }
122
123     // Create send message queue
124     g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
125     if (!g_sendQueueHandle)
126     {
127         OIC_LOG(ERROR, TAG, "Memory allocation failed! (g_sendQueueHandle)");
128         u_arraylist_free(&g_ownIpEndpointList);
129         g_ownIpEndpointList = NULL;
130         return CA_MEMORY_ALLOC_FAILED;
131     }
132
133     if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
134                                 (const ca_thread_pool_t)caglobals.ip.threadpool,
135                                 CAIPSendDataThread, CADataDestroyer))
136     {
137         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
138         OICFree(g_sendQueueHandle);
139         g_sendQueueHandle = NULL;
140         u_arraylist_free(&g_ownIpEndpointList);
141         g_ownIpEndpointList = NULL;
142         return CA_STATUS_FAILED;
143     }
144
145     return CA_STATUS_OK;
146 }
147
148 void CAIPDeinitializeQueueHandles()
149 {
150     CAQueueingThreadDestroy(g_sendQueueHandle);
151     OICFree(g_sendQueueHandle);
152     g_sendQueueHandle = NULL;
153
154     // Since the items in g_ownIpEndpointList are allocated once in a big chunk, we only need to
155     // free the first item. Another location this is done is in the CA_INTERFACE_DOWN handler
156     // in CAUpdateStoredIPAddressInfo().
157     OICFree(u_arraylist_get(g_ownIpEndpointList, 0));
158     u_arraylist_free(&g_ownIpEndpointList);
159     g_ownIpEndpointList = NULL;
160 }
161
162
163 void CAIPAdapterHandler(CATransportAdapter_t adapter, CANetworkStatus_t status)
164 {
165     CAUpdateStoredIPAddressInfo(status);
166
167     if (g_networkChangeCallback)
168     {
169         g_networkChangeCallback(adapter, status);
170     }
171     else
172     {
173         OIC_LOG(ERROR, TAG, "g_networkChangeCallback is NULL");
174     }
175
176     if (CA_INTERFACE_DOWN == status)
177     {
178         OIC_LOG(DEBUG, TAG, "Network status for IP is down");
179 #ifdef __WITH_DTLS__
180         OIC_LOG(DEBUG, TAG, "close all ssl session");
181         CAcloseSslConnectionAll(CA_ADAPTER_IP);
182 #endif
183     }
184 }
185
186 static void CAUpdateStoredIPAddressInfo(CANetworkStatus_t status)
187 {
188     if (CA_INTERFACE_UP == status)
189     {
190         OIC_LOG(DEBUG, TAG, "IP adapter status is on. Store the own IP address info");
191
192         CAEndpoint_t *eps = NULL;
193         size_t numOfEps = 0;
194
195         CAResult_t res = CAGetIPInterfaceInformation(&eps, &numOfEps);
196         if (CA_STATUS_OK != res)
197         {
198             OIC_LOG(ERROR, TAG, "CAGetIPInterfaceInformation failed");
199             return;
200         }
201
202         for (size_t i = 0; i < numOfEps; i++)
203         {
204             u_arraylist_add(g_ownIpEndpointList, (void *)&eps[i]);
205         }
206     }
207     else // CA_INTERFACE_DOWN
208     {
209         OIC_LOG(DEBUG, TAG, "IP adapter status is off. Remove the own IP address info");
210
211         CAEndpoint_t *headEp = u_arraylist_get(g_ownIpEndpointList, 0);
212         OICFree(headEp);
213         headEp = NULL;
214
215         size_t len = u_arraylist_length(g_ownIpEndpointList);
216         for (size_t i = len; i > 0; i--)
217         {
218             u_arraylist_remove(g_ownIpEndpointList, i - 1);
219         }
220     }
221 }
222
223 #ifdef __WITH_DTLS__
224 static ssize_t CAIPPacketSendCB(CAEndpoint_t *endpoint, const void *data, size_t dataLength)
225 {
226     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint is NULL", -1);
227     VERIFY_NON_NULL_RET(data, TAG, "data is NULL", -1);
228
229     CAIPSendData(endpoint, data, dataLength, false);
230     return dataLength;
231 }
232 #endif
233
234 void CAIPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
235                           size_t dataLength)
236 {
237     VERIFY_NON_NULL_VOID(sep, TAG, "sep is NULL");
238     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
239
240     OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", sep->endpoint.addr, sep->endpoint.port);
241
242     if (g_networkPacketCallback)
243     {
244         g_networkPacketCallback(sep, data, dataLength);
245     }
246 }
247
248 bool CAIPIsLocalEndpoint(const CAEndpoint_t *ep)
249 {
250     char addr[MAX_ADDR_STR_SIZE_CA];
251     OICStrcpy(addr, MAX_ADDR_STR_SIZE_CA, ep->addr);
252
253     // drop the zone ID if the address of endpoint is IPv6. ifindex will be checked instead.
254     if ((ep->flags & CA_IPV6) && strchr(addr, '%'))
255     {
256         strtok(addr, "%");
257     }
258
259     size_t len = u_arraylist_length(g_ownIpEndpointList);
260     for (size_t i = 0; i < len; i++)
261     {
262         CAEndpoint_t *ownIpEp = u_arraylist_get(g_ownIpEndpointList, i);
263         if (!strcmp(addr, ownIpEp->addr) && ep->port == ownIpEp->port
264                                          && ep->ifindex == ownIpEp->ifindex)
265         {
266             return true;
267         }
268     }
269
270     return false;
271 }
272
273 void CAIPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
274                       size_t dataLength, CAResult_t result)
275 {
276     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
277     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
278
279     if (g_errorCallback)
280     {
281         g_errorCallback(endpoint, data, dataLength, result);
282     }
283 }
284
285 static void CAInitializeIPGlobals()
286 {
287     caglobals.ip.u6.fd  = OC_INVALID_SOCKET;
288     caglobals.ip.u6s.fd = OC_INVALID_SOCKET;
289     caglobals.ip.u4.fd  = OC_INVALID_SOCKET;
290     caglobals.ip.u4s.fd = OC_INVALID_SOCKET;
291     caglobals.ip.m6.fd  = OC_INVALID_SOCKET;
292     caglobals.ip.m6s.fd = OC_INVALID_SOCKET;
293     caglobals.ip.m4.fd  = OC_INVALID_SOCKET;
294     caglobals.ip.m4s.fd = OC_INVALID_SOCKET;
295     caglobals.ip.u6.port  = 0;
296     caglobals.ip.u6s.port = 0;
297     caglobals.ip.u4.port  = 0;
298     caglobals.ip.u4s.port = 0;
299     caglobals.ip.m6.port  = CA_COAP;
300     caglobals.ip.m6s.port = CA_SECURE_COAP;
301     caglobals.ip.m4.port  = CA_COAP;
302     caglobals.ip.m4s.port = CA_SECURE_COAP;
303
304     CATransportFlags_t flags = 0;
305     if (caglobals.client)
306     {
307         flags |= caglobals.clientFlags;
308     }
309     if (caglobals.server)
310     {
311         flags |= caglobals.serverFlags;
312     }
313     caglobals.ip.ipv6enabled = flags & CA_IPV6;
314     caglobals.ip.ipv4enabled = flags & CA_IPV4;
315     caglobals.ip.dualstack = caglobals.ip.ipv6enabled && caglobals.ip.ipv4enabled;
316 }
317
318 CAResult_t CAInitializeIP(CARegisterConnectivityCallback registerCallback,
319                           CANetworkPacketReceivedCallback networkPacketCallback,
320                           CAAdapterChangeCallback netCallback,
321                           CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
322 {
323     OIC_LOG(DEBUG, TAG, "IN");
324     VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
325     VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
326     VERIFY_NON_NULL(netCallback, TAG, "netCallback");
327     VERIFY_NON_NULL(handle, TAG, "thread pool handle");
328
329 #ifdef WSA_WAIT_EVENT_0
330     // Windows-specific initialization.
331     WORD wVersionRequested = MAKEWORD(2, 2);
332     WSADATA wsaData = {.wVersion = 0};
333     int err = WSAStartup(wVersionRequested, &wsaData);
334     if (0 != err)
335     {
336         OIC_LOG_V(ERROR, TAG, "%s: WSAStartup failed: %i", __func__, err);
337         return CA_STATUS_FAILED;
338     }
339     OIC_LOG(DEBUG, TAG, "WSAStartup Succeeded");
340 #endif
341
342     g_networkChangeCallback = netCallback;
343     g_networkPacketCallback = networkPacketCallback;
344     g_errorCallback = errorCallback;
345
346     CAInitializeIPGlobals();
347     caglobals.ip.threadpool = handle;
348
349     CAIPSetErrorHandler(CAIPErrorHandler);
350     CAIPSetPacketReceiveCallback(CAIPPacketReceivedCB);
351
352 #ifdef __WITH_DTLS__
353     if (CA_STATUS_OK != CAinitSslAdapter())
354     {
355         OIC_LOG(ERROR, TAG, "Failed to init SSL adapter");
356     }
357     else
358     {
359         CAsetSslAdapterCallbacks(CAIPPacketReceivedCB, CAIPPacketSendCB, CAIPErrorHandler, CA_ADAPTER_IP);
360     }
361 #endif
362
363     static const CAConnectivityHandler_t ipHandler =
364         {
365             .startAdapter = CAStartIP,
366             .stopAdapter = CAStopIP,
367             .startListenServer = CAStartIPListeningServer,
368             .stopListenServer = CAStopIPListeningServer,
369             .startDiscoveryServer = CAStartIPDiscoveryServer,
370             .sendData = CASendIPUnicastData,
371             .sendDataToAll = CASendIPMulticastData,
372             .GetnetInfo = CAGetIPInterfaceInformation,
373             .readData = CAReadIPData,
374             .terminate = CATerminateIP,
375             .cType = CA_ADAPTER_IP
376         };
377     registerCallback(ipHandler);
378
379     OIC_LOG(INFO, TAG, "OUT IntializeIP is Success");
380     return CA_STATUS_OK;
381 }
382
383 CAResult_t CAStartIP()
384 {
385     //Initializing the Globals
386     CAInitializeIPGlobals();
387
388     // Specific the port number received from application.
389     caglobals.ip.u6.port  = caglobals.ports.udp.u6;
390     caglobals.ip.u6s.port = caglobals.ports.udp.u6s;
391     caglobals.ip.u4.port  = caglobals.ports.udp.u4;
392     caglobals.ip.u4s.port = caglobals.ports.udp.u4s;
393
394     CAIPStartNetworkMonitor(CAIPAdapterHandler, CA_ADAPTER_IP);
395     if (CA_STATUS_OK != CAIPInitializeQueueHandles())
396     {
397         OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
398         CATerminateIP();
399         return CA_STATUS_FAILED;
400     }
401
402     // Start send queue thread
403     if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
404     {
405         OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
406         return CA_STATUS_FAILED;
407     }
408
409     CAResult_t ret = CAIPStartServer((const ca_thread_pool_t)caglobals.ip.threadpool);
410     if (CA_STATUS_OK != ret)
411     {
412         OIC_LOG_V(ERROR, TAG, "Failed to start server![%d]", ret);
413         return ret;
414     }
415
416
417     return CA_STATUS_OK;
418 }
419
420 CAResult_t CAStartIPListeningServer()
421 {
422     CAResult_t ret = CAIPStartListenServer();
423     if (CA_STATUS_OK != ret)
424     {
425         OIC_LOG_V(ERROR, TAG, "Failed to start listening server![%d]", ret);
426         return ret;
427     }
428
429     return CA_STATUS_OK;
430 }
431
432 CAResult_t CAStopIPListeningServer()
433 {
434     CAResult_t ret = CAIPStopListenServer();
435     if (CA_STATUS_OK != ret)
436     {
437         OIC_LOG_V(ERROR, TAG, "Failed to stop listening server![%d]", ret);
438     }
439
440     return ret;
441 }
442
443 CAResult_t CAStartIPDiscoveryServer()
444 {
445     return CAStartIPListeningServer();
446 }
447
448 static int32_t CAQueueIPData(bool isMulticast, const CAEndpoint_t *endpoint,
449                              const void *data, uint32_t dataLength)
450 {
451     VERIFY_NON_NULL_RET(endpoint, TAG, "remoteEndpoint", -1);
452     VERIFY_NON_NULL_RET(data, TAG, "data", -1);
453
454     if (0 == dataLength)
455     {
456         OIC_LOG(ERROR, TAG, "Invalid Data Length");
457         return -1;
458     }
459
460
461     VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
462     // Create IPData to add to queue
463     CAIPData_t *ipData = CACreateIPData(endpoint, data, dataLength, isMulticast);
464     if (!ipData)
465     {
466         OIC_LOG(ERROR, TAG, "Failed to create ipData!");
467         return -1;
468     }
469     // Add message to send queue
470     CAQueueingThreadAddData(g_sendQueueHandle, ipData, sizeof(CAIPData_t));
471
472
473     return dataLength;
474 }
475
476 int32_t CASendIPUnicastData(const CAEndpoint_t *endpoint,
477                             const void *data, uint32_t dataLength,
478                             CADataType_t dataType)
479 {
480     (void)dataType;
481     return CAQueueIPData(false, endpoint, data, dataLength);
482 }
483
484 int32_t CASendIPMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLength,
485                               CADataType_t dataType)
486 {
487     (void)dataType;
488     return CAQueueIPData(true, endpoint, data, dataLength);
489 }
490
491 CAResult_t CAReadIPData()
492 {
493     CAIPPullData();
494     return CA_STATUS_OK;
495 }
496
497 CAResult_t CAStopIP()
498 {
499 #ifdef __WITH_DTLS__
500     CAdeinitSslAdapter();
501 #endif
502
503     if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
504     {
505         CAQueueingThreadStop(g_sendQueueHandle);
506     }
507
508     CAIPStopNetworkMonitor(CA_ADAPTER_IP);
509     CAIPStopServer();
510
511     return CA_STATUS_OK;
512 }
513
514 void CATerminateIP()
515 {
516 #ifdef __WITH_DTLS__
517     CAsetSslAdapterCallbacks(NULL, NULL, NULL, CA_ADAPTER_IP);
518 #endif
519
520     CAIPSetPacketReceiveCallback(NULL);
521
522     CAIPDeinitializeQueueHandles();
523
524 #ifdef WSA_WAIT_EVENT_0
525     // Windows-specific clean-up.
526     OC_VERIFY(0 == WSACleanup());
527 #endif
528 }
529
530
531 void CAIPSendDataThread(void *threadData)
532 {
533     CAIPData_t *ipData = (CAIPData_t *) threadData;
534     if (!ipData)
535     {
536         OIC_LOG(DEBUG, TAG, "Invalid ip data!");
537         return;
538     }
539
540     if (ipData->isMulticast)
541     {
542         //Processing for sending multicast
543         OIC_LOG(DEBUG, TAG, "Send Multicast Data is called");
544         CAIPSendData(ipData->remoteEndpoint, ipData->data, ipData->dataLen, true);
545     }
546     else
547     {
548         //Processing for sending unicast
549 #ifdef __WITH_DTLS__
550         if (ipData->remoteEndpoint && ipData->remoteEndpoint->flags & CA_SECURE)
551         {
552             OIC_LOG(DEBUG, TAG, "DTLS encrypt called");
553             CAResult_t result = CAencryptSsl(ipData->remoteEndpoint, ipData->data, ipData->dataLen);
554             if (CA_STATUS_OK != result)
555             {
556                 OIC_LOG(ERROR, TAG, "CAencryptSsl failed!");
557             }
558             OIC_LOG_V(DEBUG, TAG, "CAencryptSsl returned with result[%d]", result);
559         }
560         else
561         {
562             OIC_LOG(DEBUG, TAG, "Send Unicast Data is called");
563             CAIPSendData(ipData->remoteEndpoint, ipData->data, ipData->dataLen, false);
564         }
565 #else
566         CAIPSendData(ipData->remoteEndpoint, ipData->data, ipData->dataLen, false);
567 #endif
568     }
569 }
570
571
572 CAIPData_t *CACreateIPData(const CAEndpoint_t *remoteEndpoint, const void *data,
573                            uint32_t dataLength, bool isMulticast)
574 {
575     VERIFY_NON_NULL_RET(remoteEndpoint, TAG, "remoteEndpoint is NULL", NULL);
576     VERIFY_NON_NULL_RET(data, TAG, "IPData is NULL", NULL);
577
578     CAIPData_t *ipData = (CAIPData_t *) OICMalloc(sizeof(*ipData));
579     if (!ipData)
580     {
581         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
582         return NULL;
583     }
584
585     ipData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
586     ipData->data = (void *) OICMalloc(dataLength);
587     if (!ipData->data)
588     {
589         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
590         CAFreeIPData(ipData);
591         return NULL;
592     }
593
594     memcpy(ipData->data, data, dataLength);
595     ipData->dataLen = dataLength;
596
597     ipData->isMulticast = isMulticast;
598
599     return ipData;
600 }
601
602 void CAFreeIPData(CAIPData_t *ipData)
603 {
604     VERIFY_NON_NULL_VOID(ipData, TAG, "ipData is NULL");
605
606     CAFreeEndpoint(ipData->remoteEndpoint);
607     OICFree(ipData->data);
608     OICFree(ipData);
609 }
610
611 void CADataDestroyer(void *data, uint32_t size)
612 {
613     if (size < sizeof(CAIPData_t))
614     {
615         OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %d", data, size);
616     }
617     CAIPData_t *etdata = (CAIPData_t *) data;
618
619     CAFreeIPData(etdata);
620 }
621