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