API change , Retransmission Callback on expiry , remove glib source for dynamic linking
[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 #include "caethernetinterface.h"
22
23 #include <sys/types.h>
24 #include <ifaddrs.h>
25 #include <net/if.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "caadapterutils.h"
32 #include "umutex.h"
33 #include "logger.h"
34 #include "oic_malloc.h"
35
36 #define ETHERNET_MONITOR_TAG "ETHERNET_MONITOR"
37
38 /**
39  * @var nwConnectivityStatus
40  * @brief  Maintains network status.
41  */
42 static CANetworkStatus_t nwConnectivityStatus;
43
44 /**
45  * @var gEthernetNetInfoMutex
46  * @brief  Mutex for synchronizing access to cached interface and IP address information.
47  */
48 static u_mutex gEthernetNetInfoMutex = NULL;
49
50 /**
51  * @var gEthernetInterfaceName
52  * @brief  Maintains interface name.
53  */
54 static char *gEthernetInterfaceName = NULL;
55
56 /**
57  * @var gEthernetIPAddress
58  * @brief  Maintains interface IP address.
59  */
60 static char *gEthernetIPAddress = NULL;
61
62 /**
63  * @var gEthernetSubnetMask
64  * @brief  Maintains interface subnetmask.
65  */
66 static char *gEthernetSubnetMask = NULL;
67
68 /**
69  * @var gThreadPool
70  * @brief ThreadPool for storing u_thread_pool_t handle passed from adapter
71  */
72 static u_thread_pool_t gThreadPool = NULL;
73
74 /**
75  * @var gStopNetworkMonitor
76  * @brief Flag to control the Network Monitor Thread
77  */
78 static bool gStopNetworkMonitor = false;
79
80 /**
81  * @var gNetworkChangeCb
82  * @brief  Maintains network connection state change callback.
83  */
84 static CAEthernetConnectionStateChangeCallback gNetworkChangeCb = NULL;
85
86 /**
87  * @fn CAEthernetGetInterfaceInformation
88  * @brief This methods gets local interface name and IP address information.
89  */
90 static void CAEthernetGetInterfaceInformation(char **interfaceName, char **ipAddress,
91         char **subnetMask);
92
93 static void CANetworkMonitorThread(void *threadData);
94
95 CAResult_t CAEthernetInitializeNetworkMonitor(const u_thread_pool_t threadPool)
96 {
97     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
98
99     gThreadPool = threadPool;
100
101     if (!gEthernetNetInfoMutex)
102     {
103         gEthernetNetInfoMutex = u_mutex_new();
104     }
105
106     u_mutex_lock(gEthernetNetInfoMutex);
107     CAEthernetGetInterfaceInformation(&gEthernetInterfaceName, &gEthernetIPAddress,
108                                       &gEthernetSubnetMask);
109     u_mutex_unlock(gEthernetNetInfoMutex);
110
111     nwConnectivityStatus = (gEthernetIPAddress) ? CA_INTERFACE_UP : CA_INTERFACE_DOWN;
112
113     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
114     return CA_STATUS_OK;
115 }
116
117 void CAEthernetTerminateNetworkMonitor(void)
118 {
119     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
120
121     gThreadPool = NULL;
122
123     if (gEthernetInterfaceName)
124     {
125         OICFree(gEthernetInterfaceName);
126         gEthernetInterfaceName = NULL;
127     }
128
129     if (gEthernetIPAddress)
130     {
131         OICFree(gEthernetIPAddress);
132         gEthernetIPAddress = NULL;
133     }
134
135     if (gEthernetNetInfoMutex)
136     {
137         u_mutex_free(gEthernetNetInfoMutex);
138         gEthernetNetInfoMutex = NULL;
139     }
140
141     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
142 }
143
144 CAResult_t CAEthernetStartNetworkMonitor(void)
145 {
146     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
147
148     u_mutex_lock(gEthernetNetInfoMutex);
149     gStopNetworkMonitor = false;
150     u_mutex_unlock(gEthernetNetInfoMutex);
151
152     if (gStopNetworkMonitor)
153     {
154         OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Stop network monitor requested");
155         return CA_STATUS_FAILED;
156     }
157
158     if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, (void *) CANetworkMonitorThread,
159             (void *)NULL))
160     {
161         OIC_LOG(ERROR, ETHERNET_MONITOR_TAG, "[ThreadPool] thread_pool_add_task failed!");
162         return CA_STATUS_FAILED;
163     }
164
165     OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
166     return CA_STATUS_OK;
167 }
168
169 CAResult_t CAEthernetStopNetworkMonitor(void)
170 {
171     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
172
173     if (gStopNetworkMonitor)
174     {
175         OIC_LOG(DEBUG, ETHERNET_MONITOR_TAG, "CAEthernetStopNetworkMonitor, already stopped!");
176         return CA_STATUS_OK;
177     }
178
179     u_mutex_lock(gEthernetNetInfoMutex);
180     gStopNetworkMonitor = true;
181     u_mutex_unlock(gEthernetNetInfoMutex);
182
183     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
184     return CA_STATUS_OK;
185 }
186
187 CAResult_t CAEthernetGetInterfaceInfo(char **interfaceName, char **ipAddress)
188 {
189     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
190
191     VERIFY_NON_NULL(interfaceName, ETHERNET_MONITOR_TAG, "interface name");
192     VERIFY_NON_NULL(ipAddress, ETHERNET_MONITOR_TAG, "ip address");
193
194     // Get the interface and ipaddress information from cache
195     u_mutex_lock(gEthernetNetInfoMutex);
196     if (gEthernetInterfaceName == NULL || gEthernetIPAddress == NULL)
197     {
198         OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "Network not enabled");
199         return CA_ADAPTER_NOT_ENABLED;
200     }
201
202     *interfaceName = (gEthernetInterfaceName) ? strndup(gEthernetInterfaceName,
203                      strlen(gEthernetInterfaceName)) : NULL;
204     *ipAddress = (gEthernetIPAddress) ? strndup(gEthernetIPAddress, strlen(gEthernetIPAddress))
205                  : NULL;
206
207     u_mutex_unlock(gEthernetNetInfoMutex);
208
209     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
210     return CA_STATUS_OK;
211 }
212
213 CAResult_t CAEthernetGetInterfaceSubnetMask(char **subnetMask)
214 {
215     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
216
217     VERIFY_NON_NULL(subnetMask, ETHERNET_MONITOR_TAG, "subnet mask");
218
219     u_mutex_lock(gEthernetNetInfoMutex);
220     if (NULL == gEthernetSubnetMask)
221     {
222         OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "There is no subnet mask information!");
223         return CA_STATUS_FAILED;
224     }
225
226     *subnetMask = (gEthernetSubnetMask) ? strndup(gEthernetSubnetMask, strlen(gEthernetSubnetMask))
227                   : NULL;
228     u_mutex_unlock(gEthernetNetInfoMutex);
229
230     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
231     return CA_STATUS_OK;
232 }
233
234 bool CAEthernetIsConnected(void)
235 {
236     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
237
238     if (CA_INTERFACE_DOWN == nwConnectivityStatus)
239         return false;
240
241     return true;
242 }
243
244 void CAEthernetSetConnectionStateChangeCallback(CAEthernetConnectionStateChangeCallback callback)
245 {
246     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
247     gNetworkChangeCb = callback;
248 }
249
250 void CAEthernetGetInterfaceInformation(char **interfaceName, char **ipAddress, char **subnetMask)
251 {
252     struct ifaddrs *ifa = NULL;
253     struct ifaddrs *ifp = NULL;
254     const char *matchName = "eth";
255
256     if (!interfaceName || !ipAddress || !subnetMask)
257     {
258         OIC_LOG(ERROR, ETHERNET_MONITOR_TAG, "Invalid input: interface/ipaddress holder is NULL!");
259         return;
260     }
261
262     if (-1 == getifaddrs(&ifp))
263     {
264         OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Failed to get interface list!, Error code: %s",
265                   strerror(errno));
266         return;
267     }
268
269     for (ifa = ifp; ifa; ifa = ifa->ifa_next)
270     {
271         char interfaceAddress[CA_IPADDR_SIZE];
272         char interfaceSubnetMask[CA_IPADDR_SIZE] = {0};
273         socklen_t len = sizeof(struct sockaddr_in);
274
275         if (NULL == ifa->ifa_addr)
276         {
277             continue;
278         }
279
280         int type = ifa->ifa_addr->sa_family;
281         if (ifa->ifa_flags & IFF_LOOPBACK
282             || !((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
283         {
284             continue;
285         }
286
287         if (AF_INET != type)
288         {
289             continue;
290         }
291
292         if (!strncasecmp(ifa->ifa_name, matchName, strlen(matchName)))
293         {
294             // get the interface ip address
295             if (0 != getnameinfo(ifa->ifa_addr, len, interfaceAddress,
296                                  sizeof(interfaceAddress), NULL, 0, NI_NUMERICHOST))
297             {
298                 OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Failed to get IPAddress, Error code: %s",
299                           strerror(errno));
300                 break;
301             }
302
303             // get the interface subnet mask
304             if (0 != getnameinfo(ifa->ifa_netmask, len, interfaceSubnetMask,
305                                  sizeof(interfaceSubnetMask), NULL, 0, NI_NUMERICHOST))
306             {
307                 OIC_LOG_V(ERROR, ETHERNET_MONITOR_TAG, "Failed to get subnet mask, Error code: %s",
308                           strerror(errno));
309                 break;
310             }
311
312             // set interface name
313             *interfaceName = strndup(ifa->ifa_name, strlen(ifa->ifa_name));
314
315             // set local ip address
316             *ipAddress = strndup(interfaceAddress, strlen(interfaceAddress));
317
318             // set subnet mask
319             *subnetMask = strndup(interfaceSubnetMask, strlen(interfaceSubnetMask));
320             break;
321         }
322     }
323
324     freeifaddrs(ifp);
325 }
326
327 void CANetworkMonitorThread(void *threadData)
328 {
329     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "IN");
330
331     while (!gStopNetworkMonitor)
332     {
333         // Get network information
334         CANetworkStatus_t currNetworkStatus;
335         char *interfaceName = NULL;
336         char *ipAddress = NULL;
337         char *subnetMask = NULL;
338         CAEthernetGetInterfaceInformation(&interfaceName, &ipAddress, &subnetMask);
339
340         // check current network status
341         currNetworkStatus = (ipAddress) ? CA_INTERFACE_UP : CA_INTERFACE_DOWN;
342
343         // if network status is changed
344         if (currNetworkStatus != nwConnectivityStatus)
345         {
346             // set current network information
347             u_mutex_lock(gEthernetNetInfoMutex);
348
349             nwConnectivityStatus = currNetworkStatus;
350
351             OICFree(gEthernetInterfaceName);
352             OICFree(gEthernetIPAddress);
353             OICFree(gEthernetSubnetMask);
354             gEthernetInterfaceName = (interfaceName) ? strndup(interfaceName, strlen(interfaceName)) : NULL;
355             gEthernetIPAddress = (ipAddress) ? strndup(ipAddress, strlen(ipAddress)) : NULL;
356             gEthernetSubnetMask = (subnetMask) ? strndup(subnetMask, strlen(subnetMask)) : NULL;
357
358             u_mutex_unlock(gEthernetNetInfoMutex);
359
360             if (gNetworkChangeCb)
361             {
362                 gNetworkChangeCb(gEthernetIPAddress, nwConnectivityStatus);
363             }
364         }
365         OICFree(interfaceName);
366         OICFree(ipAddress);
367         OICFree(subnetMask);
368     }
369
370     OIC_LOG_V(DEBUG, ETHERNET_MONITOR_TAG, "OUT");
371 }