Imported Upstream version 1.0.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / android / caipnwmonitor.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 "caipinterface.h"
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29
30 #include <arpa/inet.h>
31 #include <linux/if.h>
32
33 #include "caadapterutils.h"
34 #include "logger.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "org_iotivity_ca_CaIpInterface.h"
38
39 #define TAG "IP_MONITOR"
40
41 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
42                                          uint32_t addr, int flags);
43
44 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
45                             const char *name, int family, uint32_t addr, int flags);
46
47 CAResult_t CAIPJniInit();
48
49 #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF
50
51 CAResult_t CAIPStartNetworkMonitor()
52 {
53     return CAIPJniInit();
54 }
55
56 CAResult_t CAIPStopNetworkMonitor()
57 {
58     return CA_STATUS_OK;
59 }
60
61 int CAGetPollingInterval(int interval)
62 {
63     return interval;
64 }
65
66 CAInterface_t *CAFindInterfaceChange()
67 {
68     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
69     struct ifconf ifc  = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
70
71     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
72     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
73     {
74         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
75         return NULL;
76     }
77
78     CAInterface_t *foundNewInterface = NULL;
79
80     struct ifreq* ifr = ifc.ifc_req;
81     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
82     size_t ifreqsize = ifc.ifc_len;
83
84     CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
85     if (!previous)
86     {
87         OIC_LOG(ERROR, TAG, "OICMalloc failed");
88         return NULL;
89     }
90
91     memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
92     size_t numprevious = caglobals.ip.nm.numIfItems;
93
94     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
95     {
96
97         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
98         if (!items)
99         {
100             OIC_LOG(ERROR, TAG, "OICRealloc failed");
101             OICFree(previous);
102             return NULL;
103         }
104         caglobals.ip.nm.ifItems = items;
105         caglobals.ip.nm.sizeIfItems = ifreqsize;
106     }
107
108     caglobals.ip.nm.numIfItems = 0;
109     for (size_t i = 0; i < interfaces; i++)
110     {
111         struct ifreq* item = &ifr[i];
112         char *name = item->ifr_name;
113         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
114         uint32_t ipv4addr = sa4->sin_addr.s_addr;
115
116         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
117         {
118             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
119             continue;
120         }
121         int16_t flags = item->ifr_flags;
122         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
123         {
124             continue;
125         }
126         if (ioctl(s, SIOCGIFINDEX, item) < 0)
127         {
128             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
129             continue;
130         }
131
132         int ifIndex = item->ifr_ifindex;
133         caglobals.ip.nm.ifItems[i].ifIndex = ifIndex;  // refill interface list
134         caglobals.ip.nm.numIfItems++;
135
136         if (foundNewInterface)
137         {
138             continue;   // continue updating interface list
139         }
140
141         // see if this interface didn't previously exist
142         bool found = false;
143         for (size_t j = 0; j < numprevious; j++)
144         {
145             if (ifIndex == previous[j].ifIndex)
146             {
147                 found = true;
148                 break;
149             }
150         }
151         if (found)
152         {
153             OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
154             continue;
155         }
156
157         foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
158     }
159
160     OICFree(previous);
161     return foundNewInterface;
162 }
163
164 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
165 {
166     u_arraylist_t *iflist = u_arraylist_create();
167     if (!iflist)
168     {
169         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
170         return NULL;
171     }
172
173     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
174     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
175
176     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
177     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
178     {
179         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
180         u_arraylist_destroy(iflist);
181         return NULL;
182     }
183
184     struct ifreq* ifr = ifc.ifc_req;
185     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
186     size_t ifreqsize = ifc.ifc_len;
187
188     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
189     {
190         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
191         if (!items)
192         {
193             OIC_LOG(ERROR, TAG, "OICRealloc failed");
194             goto exit;
195         }
196         caglobals.ip.nm.ifItems = items;
197         caglobals.ip.nm.sizeIfItems = ifreqsize;
198     }
199
200     caglobals.ip.nm.numIfItems = 0;
201     for (size_t i = 0; i < interfaces; i++)
202     {
203         CAResult_t result = CA_STATUS_OK;
204         struct ifreq* item = &ifr[i];
205         char *name = item->ifr_name;
206         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
207         uint32_t ipv4addr = sa4->sin_addr.s_addr;
208
209         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
210         {
211             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
212             continue;
213         }
214         int16_t flags = item->ifr_flags;
215         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
216         {
217             continue;
218         }
219         if (ioctl(s, SIOCGIFINDEX, item) < 0)
220         {
221             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
222             continue;
223         }
224
225         int ifindex = item->ifr_ifindex;
226         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
227         caglobals.ip.nm.numIfItems++;
228
229         if (desiredIndex && (ifindex != desiredIndex))
230         {
231             continue;
232         }
233
234         // Add IPv4 interface
235         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
236         if (CA_STATUS_OK != result)
237         {
238             goto exit;
239         }
240
241         // Add IPv6 interface
242         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
243         if (CA_STATUS_OK != result)
244         {
245             goto exit;
246         }
247     }
248     return iflist;
249
250 exit:
251     u_arraylist_destroy(iflist);
252     return NULL;
253 }
254
255 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
256                             const char *name, int family, uint32_t addr, int flags)
257 {
258     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
259     if (!ifitem)
260     {
261         return CA_STATUS_FAILED;
262     }
263     bool result = u_arraylist_add(iflist, ifitem);
264     if (!result)
265     {
266         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
267         OICFree(ifitem);
268         return CA_STATUS_FAILED;
269     }
270
271     return CA_STATUS_OK;
272 }
273
274 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
275                                          uint32_t addr, int flags)
276 {
277     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
278     if (!ifitem)
279     {
280         OIC_LOG(ERROR, TAG, "Malloc failed");
281         return NULL;
282     }
283
284     OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
285     ifitem->index = index;
286     ifitem->family = family;
287     ifitem->ipv4addr = addr;
288     ifitem->flags = flags;
289
290     return ifitem;
291 }
292
293 CAResult_t CAIPJniInit()
294 {
295     OIC_LOG(DEBUG, TAG, "CAIPJniInit_IN");
296
297     JavaVM *jvm = CANativeJNIGetJavaVM();
298     if (!jvm)
299     {
300         OIC_LOG(ERROR, TAG, "Could not get JavaVM pointer");
301         return CA_STATUS_FAILED;
302     }
303
304     jobject context = CANativeJNIGetContext();
305     if (!context)
306     {
307         OIC_LOG(ERROR, TAG, "unable to get application context");
308         return CA_STATUS_FAILED;
309     }
310
311     JNIEnv* env;
312     if ((*jvm)->GetEnv(jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
313     {
314         OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
315         return CA_STATUS_FAILED;
316     }
317
318     jclass cls_Context = (*env)->FindClass(env, "android/content/Context");
319     if (!cls_Context)
320     {
321         OIC_LOG(ERROR, TAG, "Could not get context object class");
322         return CA_STATUS_FAILED;
323     }
324
325     jmethodID mid_getApplicationContext = (*env)->GetMethodID(env, cls_Context,
326                                                                 "getApplicationContext",
327                                                                 "()Landroid/content/Context;");
328     if (!mid_getApplicationContext)
329     {
330         OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
331         return CA_STATUS_FAILED;
332     }
333
334     jobject jApplicationContext = (*env)->CallObjectMethod(env, context,
335                                                            mid_getApplicationContext);
336     if (!jApplicationContext)
337     {
338         OIC_LOG(ERROR, TAG, "Could not get application context");
339         return CA_STATUS_FAILED;
340     }
341
342     jclass cls_CaIpInterface = (*env)->FindClass(env, "org/iotivity/ca/CaIpInterface");
343     if (!cls_CaIpInterface)
344     {
345         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface class");
346         return CA_STATUS_FAILED;
347     }
348
349     jmethodID mid_CaIpInterface_ctor = (*env)->GetMethodID(env, cls_CaIpInterface, "<init>",
350                                                                    "(Landroid/content/Context;)V");
351     if (!mid_CaIpInterface_ctor)
352     {
353         OIC_LOG(ERROR, TAG, "Could not get CaIpInterface constructor method");
354         return CA_STATUS_FAILED;
355     }
356
357     (*env)->NewObject(env, cls_CaIpInterface, mid_CaIpInterface_ctor, jApplicationContext);
358     OIC_LOG(DEBUG, TAG, "Create CaIpInterface instance, success");
359
360     OIC_LOG(DEBUG, TAG, "CAIPJniInit_OUT");
361     return CA_STATUS_OK;
362 }
363
364 JNIEXPORT void JNICALL
365 Java_org_iotivity_ca_CaIpInterface_caIpStateEnabled(JNIEnv *env, jclass class)
366 {
367     (void)env;
368     (void)class;
369     OIC_LOG(DEBUG, TAG, "caIpStateEnabled");
370
371     CAWakeUpForChange();
372 }
373
374 JNIEXPORT void JNICALL
375 Java_org_iotivity_ca_CaIpInterface_caIpStateDisabled(JNIEnv *env, jclass class)
376 {
377     (void)env;
378     (void)class;
379     OIC_LOG(DEBUG, TAG, "caIpStateDisabled");
380
381     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
382     if (!iflist)
383     {
384         OIC_LOG_V(ERROR, TAG, "get interface info failed");
385         return;
386     }
387     u_arraylist_destroy(iflist);
388 }