Replace glib threadpool usage with a 'dumb' thread implementation.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ethernet_adapter / linux / caethernetnwmonitor.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
21 // Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2008 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2008 base specification,
26 // Refer http://pubs.opengroup.org/stage7tc1/
27 //
28 // For this specific file, see use of strndup,
29 // Refer http://man7.org/linux/man-pages/man3/strdup.3.html
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
32 #endif
33
34 // Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
35 // definitions that may otherwise be skipped. Skipping can cause implicit
36 // declaration warnings and/or bugs and subtle problems in code execution.
37 // For glibc information on feature test macros,
38 // Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
39 //
40 // This file requires #define use due to IFF_LOOPBACK
41 #define _DEFAULT_SOURCE
42 #define _BSD_SOURCE
43 #include <net/if.h>
44
45 #include "caethernetinterface.h"
46
47 #include <sys/types.h>
48 #include <ifaddrs.h>
49 #include <sys/socket.h>
50 #include <netdb.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <errno.h>
54
55 #include "caadapterutils.h"
56 #include "camutex.h"
57 #include "logger.h"
58 #include "oic_malloc.h"
59 #include "oic_string.h"
60
61 #define ETHERNET_MONITOR_TAG "ETHERNET_MONITOR"
62
63 #ifdef __APPLE__
64 #define ETHERNET_INF_PREFIX "en"
65 #else
66 #define ETHERNET_INF_PREFIX "eth"
67 #endif
68
69 /**
70  * @var nwConnectivityStatus
71  * @brief  Maintains network status.
72  */
73 static CANetworkStatus_t nwConnectivityStatus;
74
75 /**
76  * @var g_ethernetNetInfoMutex
77  * @brief  Mutex for synchronizing access to cached interface and IP address information.
78  */
79 static ca_mutex g_ethernetNetInfoMutex = NULL;
80
81 /**
82  * @var g_ethernetInterfaceName
83  * @brief  Maintains interface name.
84  */
85 static char *g_ethernetInterfaceName = NULL;
86
87 /**
88  * @var g_ethernetIPAddress
89  * @brief  Maintains interface IP address.
90  */
91 static char *g_ethernetIPAddress = NULL;
92
93 /**
94  * @var g_ethernetSubnetMask
95  * @brief  Maintains interface subnetmask.
96  */
97 static char *g_ethernetSubnetMask = NULL;
98
99 /**
100  * @var g_threadPool
101  * @brief ThreadPool for storing ca_thread_pool_t handle passed from adapter
102  */
103 static ca_thread_pool_t g_threadPool = NULL;
104
105 /**
106  * @var g_stopNetworkMonitor
107  * @brief Flag to control the Network Monitor Thread
108  */
109 static bool g_stopNetworkMonitor = false;
110
111 /**
112  * @var g_networkChangeCb
113  * @brief  Maintains network connection state change callback.
114  */
115 static CAEthernetConnectionStateChangeCallback g_networkChangeCb = NULL;
116
117 /**
118  * @fn CAEthernetGetInterfaceInformation
119  * @brief This methods gets local interface name and IP address information.
120  */
121 static void CAEthernetGetInterfaceInformation(const char *interfacePrefix,
122         char **interfaceName, char **ipAddress,char **subnetMask);
123
124 static void CANetworkMonitorThread(void *threadData);
125
126 CAResult_t CAEthernetInitializeNetworkMonitor(const ca_thread_pool_t threadPool)
127 {
128     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
129
130     g_threadPool = threadPool;
131
132     if (!g_ethernetNetInfoMutex)
133     {
134         g_ethernetNetInfoMutex = ca_mutex_new();
135     }
136
137     ca_mutex_lock(g_ethernetNetInfoMutex);
138     CAEthernetGetInterfaceInformation(ETHERNET_INF_PREFIX,&g_ethernetInterfaceName, &g_ethernetIPAddress,
139                                       &g_ethernetSubnetMask);
140     ca_mutex_unlock(g_ethernetNetInfoMutex);
141
142     nwConnectivityStatus = (g_ethernetIPAddress) ? CA_INTERFACE_UP : CA_INTERFACE_DOWN;
143
144     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
145     return CA_STATUS_OK;
146 }
147
148 void CAEthernetTerminateNetworkMonitor(void)
149 {
150     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
151
152     g_threadPool = NULL;
153
154     if (g_ethernetInterfaceName)
155     {
156         OICFree(g_ethernetInterfaceName);
157         g_ethernetInterfaceName = NULL;
158     }
159
160     if (g_ethernetIPAddress)
161     {
162         OICFree(g_ethernetIPAddress);
163         g_ethernetIPAddress = NULL;
164     }
165
166     if (g_ethernetSubnetMask)
167     {
168         OICFree(g_ethernetSubnetMask);
169         g_ethernetSubnetMask = NULL;
170     }
171
172     if (g_ethernetNetInfoMutex)
173     {
174         ca_mutex_free(g_ethernetNetInfoMutex);
175         g_ethernetNetInfoMutex = NULL;
176     }
177
178     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
179 }
180
181 CAResult_t CAEthernetStartNetworkMonitor(void)
182 {
183     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
184
185     g_stopNetworkMonitor = false;
186
187     if (g_stopNetworkMonitor)
188     {
189         OIC_LOG(ERROR, ETHERNET_MONITOR_TAG, "Stop network monitor requested");
190         return CA_STATUS_FAILED;
191     }
192
193     if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPool, (void *) CANetworkMonitorThread,
194             (void *)NULL))
195     {
196         OIC_LOG(ERROR, ETHERNET_MONITOR_TAG, "[ThreadPool] thread_pool_add_task failed!");
197         return CA_STATUS_FAILED;
198     }
199
200     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
201     return CA_STATUS_OK;
202 }
203
204 CAResult_t CAEthernetStopNetworkMonitor(void)
205 {
206     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
207
208     if (g_stopNetworkMonitor)
209     {
210         OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "CAEthernetStopNetworkMonitor, already stopped!");
211         return CA_STATUS_OK;
212     }
213
214     g_stopNetworkMonitor = true;
215
216     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
217     return CA_STATUS_OK;
218 }
219
220 CAResult_t CAEthernetGetInterfaceInfo(char **interfaceName, char **ipAddress)
221 {
222     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
223
224     VERIFY_NON_NULL(interfaceName, ETHERNET_MONITOR_TAG, "interface name");
225     VERIFY_NON_NULL(ipAddress, ETHERNET_MONITOR_TAG, "ip address");
226
227     // Get the interface and ipaddress information from cache
228     ca_mutex_lock(g_ethernetNetInfoMutex);
229     if (g_ethernetInterfaceName == NULL || g_ethernetIPAddress == NULL)
230     {
231         OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "Network not enabled");
232
233         ca_mutex_unlock(g_ethernetNetInfoMutex);
234         return CA_ADAPTER_NOT_ENABLED;
235     }
236
237     *interfaceName = (g_ethernetInterfaceName) ? strndup(g_ethernetInterfaceName,
238                      strlen(g_ethernetInterfaceName)) : NULL;
239     *ipAddress = (g_ethernetIPAddress) ? OICStrdup((const char *)g_ethernetIPAddress)
240                  : NULL;
241
242     ca_mutex_unlock(g_ethernetNetInfoMutex);
243
244     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
245     return CA_STATUS_OK;
246 }
247
248 CAResult_t CAEthernetGetInterfaceSubnetMask(char **subnetMask)
249 {
250     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
251
252     VERIFY_NON_NULL(subnetMask, ETHERNET_MONITOR_TAG, "subnet mask");
253
254     ca_mutex_lock(g_ethernetNetInfoMutex);
255     if (NULL == g_ethernetSubnetMask)
256     {
257         OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "There is no subnet mask information!");
258
259         ca_mutex_unlock(g_ethernetNetInfoMutex);
260         return CA_STATUS_FAILED;
261     }
262
263     *subnetMask = (g_ethernetSubnetMask) ?
264                   strndup(g_ethernetSubnetMask, strlen(g_ethernetSubnetMask))
265                   : NULL;
266     ca_mutex_unlock(g_ethernetNetInfoMutex);
267
268     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
269     return CA_STATUS_OK;
270 }
271
272 bool CAEthernetIsConnected(void)
273 {
274     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
275
276     if (CA_INTERFACE_DOWN == nwConnectivityStatus) {
277         OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
278
279         return false;
280     }
281
282     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
283
284     return true;
285 }
286
287 void CAEthernetSetConnectionStateChangeCallback
288     (CAEthernetConnectionStateChangeCallback callback)
289 {
290     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
291     g_networkChangeCb = callback;
292
293     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
294 }
295
296 void CAEthernetGetInterfaceInformation(const char *interfaceNamePrefix,char **interfaceName,
297     char **ipAddress, char **subnetMask)
298 {
299     if (!interfaceName || !ipAddress || !subnetMask)
300     {
301         OIC_LOG(ERROR, ETHERNET_MONITOR_TAG, "Invalid input: interface/ipaddress/subnet mask holder is NULL!");
302         return;
303     }
304
305     struct ifaddrs *ifp = NULL;
306     if (-1 == getifaddrs(&ifp))
307     {
308         OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Failed to get interface list!, Error code: %s",
309                   strerror(errno));
310         return;
311     }
312
313     struct ifaddrs *ifa = NULL;
314     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
315     {
316         char interfaceAddress[CA_IPADDR_SIZE];
317         char interfaceSubnetMask[CA_IPADDR_SIZE] = {0};
318         socklen_t len = sizeof(struct sockaddr_in);
319
320         if (NULL == ifa->ifa_addr)
321         {
322             continue;
323         }
324
325         int type = ifa->ifa_addr->sa_family;
326         if (ifa->ifa_flags & IFF_LOOPBACK
327             || !((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
328         {
329             continue;
330         }
331
332         if (AF_INET != type)
333         {
334             continue;
335         }
336
337         int matchNameLen = strlen(interfaceNamePrefix);
338         if (!strncasecmp(ifa->ifa_name, interfaceNamePrefix, matchNameLen))
339         {
340             // get the interface ip address
341             if (0 != getnameinfo(ifa->ifa_addr, len, interfaceAddress,
342                                  sizeof(interfaceAddress), NULL, 0, NI_NUMERICHOST))
343             {
344                 OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Failed to get IPAddress, Error code: %s",
345                           strerror(errno));
346                 break;
347             }
348
349             // get the interface subnet mask
350             if (0 != getnameinfo(ifa->ifa_netmask, len, interfaceSubnetMask,
351                                  sizeof(interfaceSubnetMask), NULL, 0, NI_NUMERICHOST))
352             {
353                 OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Failed to get subnet mask, Error code: %s",
354                           strerror(errno));
355                 break;
356             }
357
358             // set interface name
359             *interfaceName = strndup(ifa->ifa_name, strlen(ifa->ifa_name));
360
361             // set local ip address
362             *ipAddress = strndup(interfaceAddress, strlen(interfaceAddress));
363
364             // set subnet mask
365             *subnetMask = strndup(interfaceSubnetMask, strlen(interfaceSubnetMask));
366             break;
367         }
368     }
369
370     freeifaddrs(ifp);
371 }
372
373 void CANetworkMonitorThread(void *threadData)
374 {
375     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "IN");
376
377     while (!g_stopNetworkMonitor)
378     {
379         // Get network information
380         char *interfaceName = NULL;
381         char *ipAddress = NULL;
382         char *subnetMask = NULL;
383         CAEthernetGetInterfaceInformation(ETHERNET_INF_PREFIX,&interfaceName, &ipAddress, &subnetMask);
384
385         // check current network status
386         CANetworkStatus_t currNetworkStatus;
387         currNetworkStatus = (ipAddress) ? CA_INTERFACE_UP : CA_INTERFACE_DOWN;
388
389         // if network status is changed
390         if (currNetworkStatus != nwConnectivityStatus)
391         {
392             // set current network information
393             ca_mutex_lock(g_ethernetNetInfoMutex);
394
395             nwConnectivityStatus = currNetworkStatus;
396
397             OICFree(g_ethernetInterfaceName);
398             OICFree(g_ethernetIPAddress);
399             OICFree(g_ethernetSubnetMask);
400             g_ethernetInterfaceName =
401                 (interfaceName) ? strndup(interfaceName, strlen(interfaceName)) : NULL;
402             g_ethernetIPAddress = (ipAddress) ? strndup(ipAddress, strlen(ipAddress)) : NULL;
403             g_ethernetSubnetMask = (subnetMask) ? strndup(subnetMask, strlen(subnetMask)) : NULL;
404
405             ca_mutex_unlock(g_ethernetNetInfoMutex);
406
407             if (g_networkChangeCb)
408             {
409                 g_networkChangeCb(g_ethernetIPAddress, nwConnectivityStatus);
410             }
411         }
412         OICFree(interfaceName);
413         OICFree(ipAddress);
414         OICFree(subnetMask);
415     }
416
417     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
418 }
419