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