android_net_NetUtils.cpp revision bcc76d345cdad2eff0f64d1dca9f92f94c8b9f07
1/*
2 * Copyright 2008, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "NetUtils"
18
19#include "jni.h"
20#include "JNIHelp.h"
21#include "NetdClient.h"
22#include "resolv_netid.h"
23#include <utils/misc.h>
24#include <android_runtime/AndroidRuntime.h>
25#include <utils/Log.h>
26#include <arpa/inet.h>
27#include <cutils/properties.h>
28
29extern "C" {
30int ifc_enable(const char *ifname);
31int ifc_disable(const char *ifname);
32int ifc_reset_connections(const char *ifname, int reset_mask);
33
34int dhcp_do_request(const char * const ifname,
35                    const char *ipaddr,
36                    const char *gateway,
37                    uint32_t *prefixLength,
38                    const char *dns[],
39                    const char *server,
40                    uint32_t *lease,
41                    const char *vendorInfo,
42                    const char *domains,
43                    const char *mtu);
44
45int dhcp_do_request_renew(const char * const ifname,
46                    const char *ipaddr,
47                    const char *gateway,
48                    uint32_t *prefixLength,
49                    const char *dns[],
50                    const char *server,
51                    uint32_t *lease,
52                    const char *vendorInfo,
53                    const char *domains,
54                    const char *mtu);
55
56int dhcp_stop(const char *ifname);
57int dhcp_release_lease(const char *ifname);
58char *dhcp_get_errmsg();
59}
60
61#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
62
63namespace android {
64
65/*
66 * The following remembers the jfieldID's of the fields
67 * of the DhcpInfo Java object, so that we don't have
68 * to look them up every time.
69 */
70static struct fieldIds {
71    jmethodID clear;
72    jmethodID setInterfaceName;
73    jmethodID addLinkAddress;
74    jmethodID addGateway;
75    jmethodID addDns;
76    jmethodID setDomains;
77    jmethodID setServerAddress;
78    jmethodID setLeaseDuration;
79    jmethodID setVendorInfo;
80} dhcpResultsFieldIds;
81
82static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
83{
84    int result;
85
86    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
87    result = ::ifc_enable(nameStr);
88    env->ReleaseStringUTFChars(ifname, nameStr);
89    return (jint)result;
90}
91
92static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
93{
94    int result;
95
96    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
97    result = ::ifc_disable(nameStr);
98    env->ReleaseStringUTFChars(ifname, nameStr);
99    return (jint)result;
100}
101
102static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
103      jstring ifname, jint mask)
104{
105    int result;
106
107    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
108
109    ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
110          env, clazz, nameStr, mask);
111
112    result = ::ifc_reset_connections(nameStr, mask);
113    env->ReleaseStringUTFChars(ifname, nameStr);
114    return (jint)result;
115}
116
117static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
118        jobject dhcpResults, bool renew)
119{
120    int result;
121    char  ipaddr[PROPERTY_VALUE_MAX];
122    uint32_t prefixLength;
123    char gateway[PROPERTY_VALUE_MAX];
124    char    dns1[PROPERTY_VALUE_MAX];
125    char    dns2[PROPERTY_VALUE_MAX];
126    char    dns3[PROPERTY_VALUE_MAX];
127    char    dns4[PROPERTY_VALUE_MAX];
128    const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
129    char  server[PROPERTY_VALUE_MAX];
130    uint32_t lease;
131    char vendorInfo[PROPERTY_VALUE_MAX];
132    char domains[PROPERTY_VALUE_MAX];
133    char mtu[PROPERTY_VALUE_MAX];
134
135    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
136    if (nameStr == NULL) return (jboolean)false;
137
138    if (renew) {
139        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
140                dns, server, &lease, vendorInfo, domains, mtu);
141    } else {
142        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
143                dns, server, &lease, vendorInfo, domains, mtu);
144    }
145    if (result != 0) {
146        ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
147    }
148
149    env->ReleaseStringUTFChars(ifname, nameStr);
150    if (result == 0) {
151        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
152
153        // set mIfaceName
154        // dhcpResults->setInterfaceName(ifname)
155        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname);
156
157        // set the linkAddress
158        // dhcpResults->addLinkAddress(inetAddress, prefixLength)
159        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress,
160                env->NewStringUTF(ipaddr), prefixLength);
161    }
162
163    if (result == 0) {
164        // set the gateway
165        // dhcpResults->addGateway(gateway)
166        result = env->CallBooleanMethod(dhcpResults,
167                dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway));
168    }
169
170    if (result == 0) {
171        // dhcpResults->addDns(new InetAddress(dns1))
172        result = env->CallBooleanMethod(dhcpResults,
173                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
174    }
175
176    if (result == 0) {
177        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
178                env->NewStringUTF(domains));
179
180        result = env->CallBooleanMethod(dhcpResults,
181                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
182
183        if (result == 0) {
184            result = env->CallBooleanMethod(dhcpResults,
185                    dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
186            if (result == 0) {
187                result = env->CallBooleanMethod(dhcpResults,
188                        dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
189            }
190        }
191    }
192
193    if (result == 0) {
194        // dhcpResults->setServerAddress(new InetAddress(server))
195        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
196                env->NewStringUTF(server));
197    }
198
199    if (result == 0) {
200        // dhcpResults->setLeaseDuration(lease)
201        env->CallVoidMethod(dhcpResults,
202                dhcpResultsFieldIds.setLeaseDuration, lease);
203
204        // dhcpResults->setVendorInfo(vendorInfo)
205        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
206                env->NewStringUTF(vendorInfo));
207    }
208    return (jboolean)(result == 0);
209}
210
211
212static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
213{
214    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
215}
216
217static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname,
218        jobject info)
219{
220    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
221}
222
223
224static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
225{
226    int result;
227
228    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
229    result = ::dhcp_stop(nameStr);
230    env->ReleaseStringUTFChars(ifname, nameStr);
231    return (jboolean)(result == 0);
232}
233
234static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
235{
236    int result;
237
238    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
239    result = ::dhcp_release_lease(nameStr);
240    env->ReleaseStringUTFChars(ifname, nameStr);
241    return (jboolean)(result == 0);
242}
243
244static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
245{
246    return env->NewStringUTF(::dhcp_get_errmsg());
247}
248
249static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, jint mark)
250{
251    if (setsockopt(socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
252        jniThrowException(env, "java/lang/IllegalStateException", "Error marking socket");
253    }
254}
255
256static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
257{
258    return (jboolean) !setNetworkForProcess(netId);
259}
260
261static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz)
262{
263    return getNetworkForProcess();
264}
265
266static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz,
267        jint netId)
268{
269    return (jboolean) !setNetworkForResolv(netId);
270}
271
272static jboolean android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket,
273        jint netId)
274{
275    return (jboolean) !setNetworkForSocket(netId, socket);
276}
277
278static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
279{
280    return (jboolean) !protectFromVpn(socket);
281}
282
283// ----------------------------------------------------------------------------
284
285/*
286 * JNI registration.
287 */
288static JNINativeMethod gNetworkUtilMethods[] = {
289    /* name, signature, funcPtr */
290
291    { "enableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_enableInterface },
292    { "disableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_disableInterface },
293    { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
294    { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcp },
295    { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcpRenew },
296    { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
297    { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
298    { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
299    { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
300    { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
301    { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess },
302    { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
303    { "bindSocketToNetwork", "(II)Z", (void*) android_net_utils_bindSocketToNetwork },
304    { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
305};
306
307int register_android_net_NetworkUtils(JNIEnv* env)
308{
309    jclass dhcpResultsClass = env->FindClass("android/net/DhcpResults");
310    LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
311    dhcpResultsFieldIds.clear =
312            env->GetMethodID(dhcpResultsClass, "clear", "()V");
313    dhcpResultsFieldIds.setInterfaceName =
314            env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V");
315    dhcpResultsFieldIds.addLinkAddress =
316            env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z");
317    dhcpResultsFieldIds.addGateway =
318            env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z");
319    dhcpResultsFieldIds.addDns =
320            env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
321    dhcpResultsFieldIds.setDomains =
322            env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V");
323    dhcpResultsFieldIds.setServerAddress =
324            env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z");
325    dhcpResultsFieldIds.setLeaseDuration =
326            env->GetMethodID(dhcpResultsClass, "setLeaseDuration", "(I)V");
327    dhcpResultsFieldIds.setVendorInfo =
328            env->GetMethodID(dhcpResultsClass, "setVendorInfo", "(Ljava/lang/String;)V");
329
330    return AndroidRuntime::registerNativeMethods(env,
331            NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
332}
333
334}; // namespace android
335