Imported Upstream version 0.9.2
[platform/upstream/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 "caipinterface.h"
28 #include "caqueueingthread.h"
29 #include "caadapterutils.h"
30 #ifdef __WITH_DTLS__
31 #include "caadapternetdtls.h"
32 #endif
33 #include "camutex.h"
34 #include "uarraylist.h"
35 #include "caremotehandler.h"
36 #include "logger.h"
37 #include "oic_malloc.h"
38 #include "oic_string.h"
39
40 /**
41  * @def TAG
42  * @brief Logging tag for module name
43  */
44 #define TAG "IP_ADAP"
45
46 #ifndef SINGLE_THREAD
47 /**
48  * @var CAIPData
49  * @brief 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;
58
59 /**
60  * @var g_sendQueueHandle
61  * @brief Queue handle for Send Data
62  */
63 static CAQueueingThread_t *g_sendQueueHandle = NULL;
64 #endif
65
66 /**
67  * @var g_networkPacketCallback
68  * @brief Network Packet Received Callback to CA
69  */
70 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
71
72 /**
73  * @var g_networkChangeCallback
74  * @brief Network Changed Callback to CA
75  */
76 static CANetworkChangeCallback g_networkChangeCallback = NULL;
77
78 /**
79  * @var g_errorCallback
80  * @brief error Callback to CA adapter
81  */
82 static CAErrorHandleCallback g_errorCallback = NULL;
83
84 static void CAIPPacketReceivedCB(const CAEndpoint_t *endpoint,
85                                  const void *data, uint32_t dataLength);
86 #ifdef __WITH_DTLS__
87 static void CAIPPacketSendCB(CAEndpoint_t *endpoint,
88                              const void *data, uint32_t dataLength);
89 #endif
90
91 #ifndef SINGLE_THREAD
92
93 static CAResult_t CAIPInitializeQueueHandles();
94
95 static void CAIPDeinitializeQueueHandles();
96
97 static void CAIPSendDataThread(void *threadData);
98
99 static CAIPData *CACreateIPData(const CAEndpoint_t *remoteEndpoint,
100                                 const void *data, uint32_t dataLength,
101                                 bool isMulticast);
102 void CAFreeIPData(CAIPData *ipData);
103
104 static void CADataDestroyer(void *data, uint32_t size);
105
106 CAResult_t CAIPInitializeQueueHandles()
107 {
108     OIC_LOG(DEBUG, TAG, "IN");
109
110     // Check if the message queue is already initialized
111     if (g_sendQueueHandle)
112     {
113         OIC_LOG(DEBUG, TAG, "send queue handle is already initialized!");
114         return CA_STATUS_OK;
115     }
116
117     // Create send message queue
118     g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
119     if (!g_sendQueueHandle)
120     {
121         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
122         return CA_MEMORY_ALLOC_FAILED;
123     }
124
125     if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
126                                 (const ca_thread_pool_t)caglobals.ip.threadpool,
127                                 CAIPSendDataThread, CADataDestroyer))
128     {
129         OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
130         OICFree(g_sendQueueHandle);
131         g_sendQueueHandle = NULL;
132         return CA_STATUS_FAILED;
133     }
134
135     OIC_LOG(DEBUG, TAG, "OUT");
136     return CA_STATUS_OK;
137 }
138
139 void CAIPDeinitializeQueueHandles()
140 {
141     OIC_LOG(DEBUG, TAG, "IN");
142
143     CAQueueingThreadDestroy(g_sendQueueHandle);
144     OICFree(g_sendQueueHandle);
145     g_sendQueueHandle = NULL;
146
147     OIC_LOG(DEBUG, TAG, "OUT");
148 }
149
150 #endif // SINGLE_THREAD
151
152 void CAIPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
153 {
154     OIC_LOG(DEBUG, TAG, "IN");
155 }
156
157 #ifdef __WITH_DTLS__
158 static void CAIPPacketSendCB(CAEndpoint_t *endpoint, const void *data, uint32_t dataLength)
159 {
160     OIC_LOG(DEBUG, TAG, "IN");
161
162     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
163     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
164
165     CAIPSendData(endpoint, data, dataLength, false);
166
167     OIC_LOG(DEBUG, TAG, "OUT");
168 }
169 #endif
170
171 void CAIPPacketReceivedCB(const CAEndpoint_t *endpoint, const void *data,
172                           uint32_t dataLength)
173 {
174     OIC_LOG(DEBUG, TAG, "IN");
175
176     VERIFY_NON_NULL_VOID(endpoint, TAG, "ipAddress is NULL");
177     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
178
179     OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", endpoint->addr, endpoint->port);
180
181     void *buf = OICCalloc(dataLength + 1, sizeof (char));
182     if (!buf)
183     {
184         OIC_LOG(ERROR, TAG, "Memory Allocation failed!");
185         return;
186     }
187     memcpy(buf, data, dataLength);
188
189     if (g_networkPacketCallback)
190     {
191         g_networkPacketCallback(endpoint, buf, dataLength);
192     }
193     else
194     {
195         OICFree(buf);
196     }
197     OIC_LOG(DEBUG, TAG, "OUT");
198 }
199
200 void CAIPErrorHandler (const CAEndpoint_t *endpoint, const void *data,
201                        uint32_t dataLength, CAResult_t result)
202 {
203     OIC_LOG(DEBUG, TAG, "IN");
204
205     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
206
207     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
208
209     void *buf = (void*)OICMalloc(sizeof(char) * dataLength);
210     if (!buf)
211     {
212         OIC_LOG(ERROR, TAG, "Memory Allocation failed!");
213         return;
214     }
215     memcpy(buf, data, dataLength);
216     if (g_errorCallback)
217     {
218         g_errorCallback(endpoint, buf, dataLength, result);
219     }
220     else
221     {
222         OICFree(buf);
223     }
224
225     OIC_LOG(DEBUG, TAG, "OUT");
226 }
227
228 static void CAInitializeIPGlobals()
229 {
230     caglobals.ip.u6.fd  = -1;
231     caglobals.ip.u6s.fd = -1;
232     caglobals.ip.u4.fd  = -1;
233     caglobals.ip.u4s.fd = -1;
234     caglobals.ip.m6.fd  = -1;
235     caglobals.ip.m6s.fd = -1;
236     caglobals.ip.m4.fd  = -1;
237     caglobals.ip.m4s.fd = -1;
238     caglobals.ip.u6.port  = 0;
239     caglobals.ip.u6s.port = 0;
240     caglobals.ip.u4.port  = 0;
241     caglobals.ip.u4s.port = 0;
242     caglobals.ip.m6.port  = CA_COAP;
243     caglobals.ip.m6s.port = CA_SECURE_COAP;
244     caglobals.ip.m4.port  = CA_COAP;
245     caglobals.ip.m4s.port = CA_SECURE_COAP;
246
247     CATransportFlags_t flags = 0;
248     if (caglobals.client)
249     {
250         flags |= caglobals.clientFlags;
251     }
252     if (caglobals.server)
253     {
254         flags |= caglobals.serverFlags;
255     }
256     caglobals.ip.ipv6enabled = flags & CA_IPV6;
257     caglobals.ip.ipv4enabled = flags & CA_IPV4;
258 }
259
260 CAResult_t CAInitializeIP(CARegisterConnectivityCallback registerCallback,
261                           CANetworkPacketReceivedCallback networkPacketCallback,
262                           CANetworkChangeCallback netCallback,
263                           CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
264 {
265     OIC_LOG(DEBUG, TAG, "IN");
266     VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
267     VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
268     VERIFY_NON_NULL(netCallback, TAG, "netCallback");
269 #ifndef SINGLE_THREAD
270     VERIFY_NON_NULL(handle, TAG, "thread pool handle");
271 #endif
272
273     g_networkChangeCallback = netCallback;
274     g_networkPacketCallback = networkPacketCallback;
275     g_errorCallback = errorCallback;
276
277     CAInitializeIPGlobals();
278     caglobals.ip.threadpool = handle;
279
280     CAIPSetPacketReceiveCallback(CAIPPacketReceivedCB);
281 #ifdef __WITH_DTLS__
282     CAAdapterNetDtlsInit();
283
284     CADTLSSetAdapterCallbacks(CAIPPacketReceivedCB, CAIPPacketSendCB, 0);
285 #endif
286
287     CAConnectivityHandler_t ipHandler;
288     ipHandler.startAdapter = CAStartIP;
289     ipHandler.startListenServer = CAStartIPListeningServer;
290     ipHandler.startDiscoveryServer = CAStartIPDiscoveryServer;
291     ipHandler.sendData = CASendIPUnicastData;
292     ipHandler.sendDataToAll = CASendIPMulticastData;
293     ipHandler.GetnetInfo = CAGetIPInterfaceInformation;
294     ipHandler.readData = CAReadIPData;
295     ipHandler.stopAdapter = CAStopIP;
296     ipHandler.terminate = CATerminateIP;
297     registerCallback(ipHandler, CA_ADAPTER_IP);
298
299     OIC_LOG(INFO, TAG, "OUT IntializeIP is Success");
300     return CA_STATUS_OK;
301 }
302
303 CAResult_t CAStartIP()
304 {
305     OIC_LOG(DEBUG, TAG, "IN");
306
307 #ifdef SINGLE_THREAD
308     uint16_t unicastPort = 55555;
309     // Address is hardcoded as we are using Single Interface
310     CAResult_t ret = CAIPStartServer();
311     if (CA_STATUS_OK != ret)
312     {
313         OIC_LOG_V(DEBUG, TAG, "CAIPStartServer failed[%d]", ret);
314         return ret;
315     }
316 #else
317     if (CA_STATUS_OK != CAIPInitializeQueueHandles())
318     {
319         OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
320         CATerminateIP();
321         return CA_STATUS_FAILED;
322     }
323
324     // Start send queue thread
325     if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
326     {
327         OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
328         return CA_STATUS_FAILED;
329     }
330
331     CAResult_t ret = CAIPStartServer((const ca_thread_pool_t)caglobals.ip.threadpool);
332     if (CA_STATUS_OK != ret)
333     {
334         OIC_LOG_V(ERROR, TAG, "Failed to start server![%d]", ret);
335         return ret;
336     }
337
338 #endif
339
340     OIC_LOG(DEBUG, TAG, "OUT");
341     return CA_STATUS_OK;
342 }
343
344 CAResult_t CAStartIPListeningServer()
345 {
346     OIC_LOG(DEBUG, TAG, "IN");
347
348     OIC_LOG(DEBUG, TAG, "OUT");
349     return CA_STATUS_OK;
350 }
351
352 CAResult_t CAStartIPDiscoveryServer()
353 {
354     OIC_LOG(DEBUG, TAG, "IN");
355     return CAStartIPListeningServer();
356 }
357
358 static int32_t CAQueueIPData(bool isMulticast, const CAEndpoint_t *endpoint,
359                             const void *data, uint32_t dataLength)
360 {
361     OIC_LOG(DEBUG, TAG, "IN");
362
363     VERIFY_NON_NULL_RET(endpoint, TAG, "remoteEndpoint", -1);
364     VERIFY_NON_NULL_RET(data, TAG, "data", -1);
365
366     if (0 == dataLength)
367     {
368         OIC_LOG(ERROR, TAG, "Invalid Data Length");
369         return -1;
370     }
371
372 #ifdef SINGLE_THREAD
373
374     CAIPSendData(endpoint, data, dataLength, isMulticast);
375
376 #else
377
378     VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
379     // Create IPData to add to queue
380     CAIPData *ipData = CACreateIPData(endpoint, data, dataLength, isMulticast);
381     if (!ipData)
382     {
383         OIC_LOG(ERROR, TAG, "Failed to create ipData!");
384         return -1;
385     }
386     // Add message to send queue
387     CAQueueingThreadAddData(g_sendQueueHandle, ipData, sizeof(CAIPData));
388
389     OIC_LOG(DEBUG, TAG, "OUT");
390     return dataLength;
391
392 #endif // SINGLE_THREAD
393 }
394
395 int32_t CASendIPUnicastData(const CAEndpoint_t *endpoint,
396                             const void *data, uint32_t dataLength)
397 {
398     OIC_LOG(DEBUG, TAG, "IN");
399     return CAQueueIPData(false, endpoint, data, dataLength);
400 }
401
402 int32_t CASendIPMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLength)
403 {
404     OIC_LOG(DEBUG, TAG, "IN");
405     return CAQueueIPData(true, endpoint, data, dataLength);
406 }
407
408 CAResult_t CAReadIPData()
409 {
410     OIC_LOG(DEBUG, TAG, "IN");
411     CAIPPullData();
412     OIC_LOG(DEBUG, TAG, "OUT");
413     return CA_STATUS_OK;
414 }
415
416 CAResult_t CAStopIP()
417 {
418     OIC_LOG(DEBUG, TAG, "IN");
419
420 #ifdef __WITH_DTLS__
421     CAAdapterNetDtlsDeInit();
422 #endif
423
424 #ifndef SINGLE_THREAD
425     if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
426     {
427         CAQueueingThreadStop(g_sendQueueHandle);
428     }
429
430     CAIPDeinitializeQueueHandles();
431 #endif
432
433     CAIPStopServer();
434
435     OIC_LOG(DEBUG, TAG, "OUT");
436     return CA_STATUS_OK;
437 }
438
439 void CATerminateIP()
440 {
441     OIC_LOG(DEBUG, TAG, "IN");
442
443 #ifdef __WITH_DTLS__
444     CADTLSSetAdapterCallbacks(NULL, NULL, 0);
445 #endif
446
447     CAIPSetPacketReceiveCallback(NULL);
448
449 #ifndef SINGLE_THREAD
450     CAIPDeinitializeQueueHandles();
451 #endif
452
453     OIC_LOG(DEBUG, TAG, "OUT");
454 }
455
456 #ifndef SINGLE_THREAD
457
458 void CAIPSendDataThread(void *threadData)
459 {
460     OIC_LOG(DEBUG, TAG, "IN");
461
462     CAIPData *ipData = (CAIPData *) threadData;
463     if (!ipData)
464     {
465         OIC_LOG(DEBUG, TAG, "Invalid ip data!");
466         return;
467     }
468
469     if (ipData->isMulticast)
470     {
471         //Processing for sending multicast
472         OIC_LOG(DEBUG, TAG, "Send Multicast Data is called");
473         CAIPSendData(ipData->remoteEndpoint, ipData->data, ipData->dataLen, true);
474     }
475     else
476     {
477         //Processing for sending unicast
478 #ifdef __WITH_DTLS__
479         if (ipData->remoteEndpoint->flags & CA_SECURE)
480         {
481             OIC_LOG(DEBUG, TAG, "CAAdapterNetDtlsEncrypt called!");
482             CAResult_t result = CAAdapterNetDtlsEncrypt(ipData->remoteEndpoint,
483                                                ipData->data, ipData->dataLen);
484             if (CA_STATUS_OK != result)
485             {
486                 OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
487             }
488             OIC_LOG_V(DEBUG, TAG,
489                       "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
490         }
491         else
492         {
493             OIC_LOG(DEBUG, TAG, "Send Unicast Data is called");
494             CAIPSendData(ipData->remoteEndpoint, ipData->data, ipData->dataLen, false);
495         }
496 #else
497         CAIPSendData(ipData->remoteEndpoint, ipData->data, ipData->dataLen, false);
498 #endif
499     }
500
501     OIC_LOG(DEBUG, TAG, "OUT");
502 }
503
504 #endif
505
506 #ifndef SINGLE_THREAD
507
508 CAIPData *CACreateIPData(const CAEndpoint_t *remoteEndpoint, const void *data,
509                                      uint32_t dataLength, bool isMulticast)
510 {
511     VERIFY_NON_NULL_RET(data, TAG, "IPData is NULL", NULL);
512
513     CAIPData *ipData = (CAIPData *) OICMalloc(sizeof(CAIPData));
514     if (!ipData)
515     {
516         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
517         return NULL;
518     }
519
520     ipData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
521     ipData->data = (void *) OICMalloc(dataLength);
522     if (!ipData->data)
523     {
524         OIC_LOG(ERROR, TAG, "Memory allocation failed!");
525         CAFreeIPData(ipData);
526         return NULL;
527     }
528
529     memcpy(ipData->data, data, dataLength);
530     ipData->dataLen = dataLength;
531
532     ipData->isMulticast = isMulticast;
533
534     return ipData;
535 }
536
537 void CAFreeIPData(CAIPData *ipData)
538 {
539     VERIFY_NON_NULL_VOID(ipData, TAG, "ipData is NULL");
540
541     CAFreeEndpoint(ipData->remoteEndpoint);
542     OICFree(ipData->data);
543     OICFree(ipData);
544 }
545
546 void CADataDestroyer(void *data, uint32_t size)
547 {
548     CAIPData *etdata = (CAIPData *) data;
549
550     CAFreeIPData(etdata);
551 }
552
553 #endif // SINGLE_THREAD
554