android_net_NetUtils.cpp revision 59b1a4ede7032c1b4d897e13dd4ede09b5e14743
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 <utils/misc.h>
21#include <android_runtime/AndroidRuntime.h>
22#include <utils/Log.h>
23#include <arpa/inet.h>
24#include <cutils/properties.h>
25
26extern "C" {
27int ifc_enable(const char *ifname);
28int ifc_disable(const char *ifname);
29int ifc_reset_connections(const char *ifname);
30
31int dhcp_do_request(const char *ifname,
32                    const char *ipaddr,
33                    const char *gateway,
34                    uint32_t  *prefixLength,
35                    const char *dns1,
36                    const char *dns2,
37                    const char *server,
38                    uint32_t  *lease);
39
40int dhcp_do_request_renew(const char *ifname,
41                    const char *ipaddr,
42                    const char *gateway,
43                    uint32_t  *prefixLength,
44                    const char *dns1,
45                    const char *dns2,
46                    const char *server,
47                    uint32_t  *lease);
48
49int dhcp_stop(const char *ifname);
50int dhcp_release_lease(const char *ifname);
51char *dhcp_get_errmsg();
52}
53
54#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
55
56namespace android {
57
58/*
59 * The following remembers the jfieldID's of the fields
60 * of the DhcpInfo Java object, so that we don't have
61 * to look them up every time.
62 */
63static struct fieldIds {
64    jclass dhcpInfoInternalClass;
65    jmethodID constructorId;
66    jfieldID ipaddress;
67    jfieldID prefixLength;
68    jfieldID dns1;
69    jfieldID dns2;
70    jfieldID serverAddress;
71    jfieldID leaseDuration;
72} dhcpInfoInternalFieldIds;
73
74static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
75{
76    int result;
77
78    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
79    result = ::ifc_enable(nameStr);
80    env->ReleaseStringUTFChars(ifname, nameStr);
81    return (jint)result;
82}
83
84static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname)
85{
86    int result;
87
88    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
89    result = ::ifc_disable(nameStr);
90    env->ReleaseStringUTFChars(ifname, nameStr);
91    return (jint)result;
92}
93
94static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstring ifname)
95{
96    int result;
97
98    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
99    result = ::ifc_reset_connections(nameStr);
100    env->ReleaseStringUTFChars(ifname, nameStr);
101    return (jint)result;
102}
103
104static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
105        jobject info, bool renew)
106{
107    int result;
108    char  ipaddr[PROPERTY_VALUE_MAX];
109    uint32_t prefixLength;
110    char gateway[PROPERTY_VALUE_MAX];
111    char    dns1[PROPERTY_VALUE_MAX];
112    char    dns2[PROPERTY_VALUE_MAX];
113    char  server[PROPERTY_VALUE_MAX];
114    uint32_t lease;
115
116    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
117    if (nameStr == NULL) return (jboolean)false;
118
119    if (renew) {
120        result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
121                dns1, dns2, server, &lease);
122    } else {
123        result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
124                dns1, dns2, server, &lease);
125    }
126
127    env->ReleaseStringUTFChars(ifname, nameStr);
128    if (result == 0 && dhcpInfoInternalFieldIds.dhcpInfoInternalClass != NULL) {
129        env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
130
131        // set the gateway
132        jclass cls = env->FindClass("java/net/InetAddress");
133        jmethodID method = env->GetStaticMethodID(cls, "getByName",
134                "(Ljava/lang/String;)Ljava/net/InetAddress;");
135        jvalue args[1];
136        args[0].l = env->NewStringUTF(gateway);
137        jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
138
139        if (!env->ExceptionOccurred()) {
140            cls = env->FindClass("android/net/RouteInfo");
141            method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
142            args[0].l = inetAddressObject;
143            jobject routeInfoObject = env->NewObjectA(cls, method, args);
144
145            cls = env->FindClass("android/net/DhcpInfoInternal");
146            method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
147            args[0].l = routeInfoObject;
148            env->CallVoidMethodA(info, method, args);
149        } else {
150            // if we have an exception (host not found perhaps), just don't add the route
151            env->ExceptionClear();
152        }
153
154        env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
155        env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
156        env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
157        env->SetObjectField(info, dhcpInfoInternalFieldIds.serverAddress,
158                env->NewStringUTF(server));
159        env->SetIntField(info, dhcpInfoInternalFieldIds.leaseDuration, lease);
160    }
161    return (jboolean)(result == 0);
162}
163
164static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
165{
166    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
167}
168
169static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
170{
171    return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
172}
173
174
175static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
176{
177    int result;
178
179    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
180    result = ::dhcp_stop(nameStr);
181    env->ReleaseStringUTFChars(ifname, nameStr);
182    return (jboolean)(result == 0);
183}
184
185static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
186{
187    int result;
188
189    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
190    result = ::dhcp_release_lease(nameStr);
191    env->ReleaseStringUTFChars(ifname, nameStr);
192    return (jboolean)(result == 0);
193}
194
195static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
196{
197    return env->NewStringUTF(::dhcp_get_errmsg());
198}
199
200// ----------------------------------------------------------------------------
201
202/*
203 * JNI registration.
204 */
205static JNINativeMethod gNetworkUtilMethods[] = {
206    /* name, signature, funcPtr */
207
208    { "enableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_enableInterface },
209    { "disableInterface", "(Ljava/lang/String;)I",  (void *)android_net_utils_disableInterface },
210    { "resetConnections", "(Ljava/lang/String;)I",  (void *)android_net_utils_resetConnections },
211    { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z",  (void *)android_net_utils_runDhcp },
212    { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z",  (void *)android_net_utils_runDhcpRenew },
213    { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
214    { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
215    { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
216};
217
218int register_android_net_NetworkUtils(JNIEnv* env)
219{
220    jclass netutils = env->FindClass(NETUTILS_PKG_NAME);
221    LOG_FATAL_IF(netutils == NULL, "Unable to find class " NETUTILS_PKG_NAME);
222
223    dhcpInfoInternalFieldIds.dhcpInfoInternalClass = env->FindClass("android/net/DhcpInfoInternal");
224    if (dhcpInfoInternalFieldIds.dhcpInfoInternalClass != NULL) {
225        dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "<init>", "()V");
226        dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;");
227        dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "prefixLength", "I");
228        dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "dns1", "Ljava/lang/String;");
229        dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "dns2", "Ljava/lang/String;");
230        dhcpInfoInternalFieldIds.serverAddress = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "serverAddress", "Ljava/lang/String;");
231        dhcpInfoInternalFieldIds.leaseDuration = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "leaseDuration", "I");
232    }
233
234    return AndroidRuntime::registerNativeMethods(env,
235            NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
236}
237
238}; // namespace android
239