android_net_NetUtils.cpp revision ec90545b5ff0e651154f8b9ab107b34e3a1124d8
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 <utils/misc.h>
22#include <android_runtime/AndroidRuntime.h>
23#include <utils/Log.h>
24#include <arpa/inet.h>
25#include <cutils/properties.h>
26
27extern "C" {
28int ifc_enable(const char *ifname);
29int ifc_disable(const char *ifname);
30int ifc_reset_connections(const char *ifname, int reset_mask);
31
32int dhcp_do_request(const char * const ifname,
33                    const char *ipaddr,
34                    const char *gateway,
35                    uint32_t *prefixLength,
36                    const char *dns[],
37                    const char *server,
38                    uint32_t *lease,
39                    const char *vendorInfo,
40                    const char *domains,
41                    const char *mtu);
42
43int dhcp_do_request_renew(const char * const ifname,
44                    const char *ipaddr,
45                    const char *gateway,
46                    uint32_t *prefixLength,
47                    const char *dns[],
48                    const char *server,
49                    uint32_t *lease,
50                    const char *vendorInfo,
51                    const char *domains,
52                    const char *mtu);
53
54int dhcp_stop(const char *ifname);
55int dhcp_release_lease(const char *ifname);
56char *dhcp_get_errmsg();
57}
58
59#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
60
61namespace android {
62
63/*
64 * The following remembers the jfieldID's of the fields
65 * of the DhcpInfo Java object, so that we don't have
66 * to look them up every time.
67 */
68static struct fieldIds {
69    jmethodID clear;
70    jmethodID setInterfaceName;
71    jmethodID addLinkAddress;
72    jmethodID addGateway;
73    jmethodID addDns;
74    jmethodID setDomains;
75    jmethodID setServerAddress;
76    jmethodID setLeaseDuration;
77    jmethodID setVendorInfo;
78} dhcpResultsFieldIds;
79
80static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
81{
82    int result;
83
84    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
85    result = ::ifc_enable(nameStr);
86    env->ReleaseStringUTFChars(ifname, nameStr);
87    return (jint)result;
88}
89
90static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
91{
92    int result;
93
94    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
95    result = ::ifc_disable(nameStr);
96    env->ReleaseStringUTFChars(ifname, nameStr);
97    return (jint)result;
98}
99
100static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
101      jstring ifname, jint mask)
102{
103    int result;
104
105    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
106
107    ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n",
108          env, clazz, nameStr, mask);
109
110    result = ::ifc_reset_connections(nameStr, mask);
111    env->ReleaseStringUTFChars(ifname, nameStr);
112    return (jint)result;
113}
114
115static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
116        jobject dhcpResults, bool renew)
117{
118    int result;
119    char  ipaddr[PROPERTY_VALUE_MAX];
120    uint32_t prefixLength;
121    char gateway[PROPERTY_VALUE_MAX];
122    char    dns1[PROPERTY_VALUE_MAX];
123    char    dns2[PROPERTY_VALUE_MAX];
124    char    dns3[PROPERTY_VALUE_MAX];
125    char    dns4[PROPERTY_VALUE_MAX];
126    const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
127    char  server[PROPERTY_VALUE_MAX];
128    uint32_t lease;
129    char vendorInfo[PROPERTY_VALUE_MAX];
130    char domains[PROPERTY_VALUE_MAX];
131    char mtu[PROPERTY_VALUE_MAX];
132
133    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
134    if (nameStr == NULL) return (jboolean)false;
135
136    if (renew) {
137        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
138                dns, server, &lease, vendorInfo, domains, mtu);
139    } else {
140        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
141                dns, server, &lease, vendorInfo, domains, mtu);
142    }
143    if (result != 0) {
144        ALOGD("dhcp_do_request failed");
145    }
146
147    env->ReleaseStringUTFChars(ifname, nameStr);
148    if (result == 0) {
149        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
150
151        // set mIfaceName
152        // dhcpResults->setInterfaceName(ifname)
153        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname);
154
155        // set the linkAddress
156        // dhcpResults->addLinkAddress(inetAddress, prefixLength)
157        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress,
158                env->NewStringUTF(ipaddr), prefixLength);
159    }
160
161    if (result == 0) {
162        // set the gateway
163        // dhcpResults->addGateway(gateway)
164        result = env->CallBooleanMethod(dhcpResults,
165                dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway));
166    }
167
168    if (result == 0) {
169        // dhcpResults->addDns(new InetAddress(dns1))
170        result = env->CallBooleanMethod(dhcpResults,
171                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
172    }
173
174    if (result == 0) {
175        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
176                env->NewStringUTF(domains));
177
178        result = env->CallBooleanMethod(dhcpResults,
179                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
180
181        if (result == 0) {
182            result = env->CallBooleanMethod(dhcpResults,
183                    dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
184            if (result == 0) {
185                result = env->CallBooleanMethod(dhcpResults,
186                        dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
187            }
188        }
189    }
190
191    if (result == 0) {
192        // dhcpResults->setServerAddress(new InetAddress(server))
193        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
194                env->NewStringUTF(server));
195    }
196
197    if (result == 0) {
198        // dhcpResults->setLeaseDuration(lease)
199        env->CallVoidMethod(dhcpResults,
200                dhcpResultsFieldIds.setLeaseDuration, lease);
201
202        // dhcpResults->setVendorInfo(vendorInfo)
203        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
204                env->NewStringUTF(vendorInfo));
205    }
206    return (jboolean)(result == 0);
207}
208
209
210static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
211{
212    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
213}
214
215static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
216{
217    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
218}
219
220
221static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
222{
223    int result;
224
225    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
226    result = ::dhcp_stop(nameStr);
227    env->ReleaseStringUTFChars(ifname, nameStr);
228    return (jboolean)(result == 0);
229}
230
231static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
232{
233    int result;
234
235    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
236    result = ::dhcp_release_lease(nameStr);
237    env->ReleaseStringUTFChars(ifname, nameStr);
238    return (jboolean)(result == 0);
239}
240
241static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
242{
243    return env->NewStringUTF(::dhcp_get_errmsg());
244}
245
246static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, jint mark)
247{
248    if (setsockopt(socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
249        jniThrowException(env, "java/lang/IllegalStateException", "Error marking socket");
250    }
251}
252
253// ----------------------------------------------------------------------------
254
255/*
256 * JNI registration.
257 */
258static JNINativeMethod gNetworkUtilMethods[] = {
259    /* name, signature, funcPtr */
260
261    { "enableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_enableInterface },
262    { "disableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_disableInterface },
263    { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
264    { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcp },
265    { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_runDhcpRenew },
266    { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
267    { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
268    { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
269    { "markSocket", "(II)V", (void*) android_net_utils_markSocket },
270};
271
272int register_android_net_NetworkUtils(JNIEnv* env)
273{
274    jclass dhcpResultsClass = env->FindClass("android/net/DhcpResults");
275    LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults");
276    dhcpResultsFieldIds.clear =
277            env->GetMethodID(dhcpResultsClass, "clear", "()V");
278    dhcpResultsFieldIds.setInterfaceName =
279            env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V");
280    dhcpResultsFieldIds.addLinkAddress =
281            env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z");
282    dhcpResultsFieldIds.addGateway =
283            env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z");
284    dhcpResultsFieldIds.addDns =
285            env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z");
286    dhcpResultsFieldIds.setDomains =
287            env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V");
288    dhcpResultsFieldIds.setServerAddress =
289            env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z");
290    dhcpResultsFieldIds.setLeaseDuration =
291            env->GetMethodID(dhcpResultsClass, "setLeaseDuration", "(I)V");
292    dhcpResultsFieldIds.setVendorInfo =
293            env->GetMethodID(dhcpResultsClass, "setVendorInfo", "(Ljava/lang/String;)V");
294
295    return AndroidRuntime::registerNativeMethods(env,
296            NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
297}
298
299}; // namespace android
300