2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "InetAddress"
20 #include "utils/Log.h"
29 #include <cutils/properties.h>
30 #include <cutils/adb_networking.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <sys/socket.h>
36 static jclass byteArrayClass = NULL;
38 static jstring InetAddress_gethostname(JNIEnv* env, jobject obj)
41 int r = gethostname(name, 256);
43 return env->NewStringUTF(name);
49 static void throwNullPointerException(JNIEnv* env)
51 const char* className = "java/lang/NullPointerException";
53 jclass exClass = env->FindClass(className);
55 if (exClass == NULL) {
56 LOGE("Unable to find class %s", className);
58 env->ThrowNew(exClass, NULL);
62 static void logIpString(struct addrinfo* ai, const char* name)
64 char ipString[INET6_ADDRSTRLEN];
65 int result = getnameinfo(ai->ai_addr, ai->ai_addrlen, ipString,
66 sizeof(ipString), NULL, 0, NI_NUMERICHOST);
68 LOGD("%s: %s (family %d, proto %d)", name, ipString, ai->ai_family,
71 LOGE("%s: getnameinfo: %s", name, gai_strerror(result));
75 static jobjectArray getAllByNameUsingAdb(JNIEnv* env, const char* name)
77 struct in_addr outaddr;
78 jobjectArray addressArray = NULL;
82 LOGI("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
83 err, (unsigned int)outaddr.a.s_addr,
84 outaddr.j[0],outaddr.j[1],
85 outaddr.j[2],outaddr.j[3]);
88 if (adb_networking_gethostbyname(name, &outaddr) >= 0) {
89 addressArray = env->NewObjectArray(1, byteArrayClass, NULL);
90 byteArray = env->NewByteArray(4);
91 if (addressArray && byteArray) {
92 env->SetByteArrayRegion(byteArray, 0, 4, (jbyte*) &outaddr.s_addr);
93 env->SetObjectArrayElement(addressArray, 1, byteArray);
99 static jobjectArray getAllByNameUsingDns(JNIEnv* env, const char* name,
100 jboolean preferIPv4Stack)
102 struct addrinfo hints, *addressList = NULL, *addrInfo;
103 jobjectArray addressArray = NULL;
105 memset(&hints, 0, sizeof(hints));
107 * IPv4 only for now until the socket code supports IPv6; otherwise, the
108 * resolver will create two separate requests, one for IPv4 and one,
109 * currently unnecessary, for IPv6.
111 hints.ai_family = AF_INET;
113 * If we don't specify a socket type, every address will appear twice, once
114 * for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
115 * anyway, just pick one.
117 hints.ai_socktype = SOCK_STREAM;
119 int result = getaddrinfo(name, NULL, &hints, &addressList);
120 if (result == 0 && addressList) {
121 // Count results so we know how to size the output array.
122 int addressCount = 0;
123 for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
124 if (addrInfo->ai_family == AF_INET ||
125 addrInfo->ai_family == AF_INET6) {
130 // Prepare output array.
131 addressArray = env->NewObjectArray(addressCount, byteArrayClass, NULL);
132 if (addressArray == NULL) {
133 // Appropriate exception will be thrown.
134 LOGE("getAllByNameUsingDns: could not allocate output array");
135 freeaddrinfo(addrInfo);
139 // Examine returned addresses one by one, save them in the output array.
141 for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
142 struct sockaddr* address = addrInfo->ai_addr;
143 size_t addressLength = 0;
146 switch (addrInfo->ai_family) {
147 // Find the raw address length and start pointer.
151 &((struct sockaddr_in6*) address)->sin6_addr.s6_addr;
152 logIpString(addrInfo, name);
157 &((struct sockaddr_in*) address)->sin_addr.s_addr;
158 logIpString(addrInfo, name);
161 // Unknown address family. Skip this address.
162 LOGE("getAllByNameUsingDns: Unknown address family %d",
163 addrInfo->ai_family);
167 // Convert each IP address into a Java byte array.
168 jbyteArray bytearray = env->NewByteArray(addressLength);
169 if (bytearray == NULL) {
170 // Out of memory error will be thrown on return.
171 LOGE("getAllByNameUsingDns: Can't allocate %d-byte array",
176 env->SetByteArrayRegion(bytearray, 0, addressLength,
177 (jbyte*) rawAddress);
178 env->SetObjectArrayElement(addressArray, index, bytearray);
179 env->DeleteLocalRef(bytearray);
182 } else if (result == EAI_SYSTEM && errno == EACCES) {
183 /* No permission to use network */
185 env, "java/lang/SecurityException",
186 "Permission denied (maybe missing INTERNET permission)");
188 // Do nothing. Return value will be null and the caller will throw an
189 // UnknownHostExeption.
193 freeaddrinfo(addressList);
199 jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
201 jboolean preferIPv4Stack)
203 if (javaName == NULL) {
204 throwNullPointerException(env);
208 const char* name = env->GetStringUTFChars(javaName, NULL);
209 jobjectArray out = NULL;
211 char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
212 char adbConnected[PROPERTY_VALUE_MAX];
213 property_get("android.net.use-adb-networking",
214 useAdbNetworkingProperty, "");
215 property_get("adb.connected",
218 // Any non-empty string value for use-adb-networking is considered "set"
219 if ((strlen(useAdbNetworkingProperty) > 0)
220 && (strlen(adbConnected) > 0) ) {
221 out = getAllByNameUsingAdb(env, name);
223 out = getAllByNameUsingDns(env, name, preferIPv4Stack);
227 LOGI("Unknown host %s, throwing UnknownHostException", name);
228 jniThrowException(env, "java/net/UnknownHostException", name);
230 env->ReleaseStringUTFChars(javaName, name);
235 static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
236 jbyteArray javaAddress)
238 if (javaAddress == NULL) {
239 throwNullPointerException(env);
243 size_t addrlen = env->GetArrayLength(javaAddress);
244 jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
245 if (rawAddress == NULL) {
246 throwNullPointerException(env);
250 // Convert the raw address bytes into a socket address structure.
251 struct sockaddr_storage ss;
252 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
253 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
257 socklen = sizeof(struct sockaddr_in);
258 memset(sin, 0, sizeof(struct sockaddr_in));
259 sin->sin_family = AF_INET;
260 memcpy(&sin->sin_addr.s_addr, rawAddress, 4);
261 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
264 socklen = sizeof(struct sockaddr_in6);
265 memset(sin6, 0, sizeof(struct sockaddr_in6));
266 sin6->sin6_family = AF_INET6;
267 memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 4);
268 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
271 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
272 jniThrowException(env, "java/net/UnknownHostException",
273 "Invalid address length");
278 // Convert the socket address structure to an IP string for logging.
280 char ipstr[INET6_ADDRSTRLEN];
281 ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr),
282 NULL, 0, NI_NUMERICHOST);
284 LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret));
288 // Look up the IP address from the socket address structure.
289 jstring result = NULL;
290 char name[NI_MAXHOST];
291 ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
294 LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name);
295 result = env->NewStringUTF(name);
297 LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr,
307 static JNINativeMethod gMethods[] = {
308 /* name, signature, funcPtr */
309 { "gethostbyaddr", "([B)Ljava/lang/String;",
310 (void*) InetAddress_gethostbyaddr },
311 { "getallbyname", "(Ljava/lang/String;Z)[[B",
312 (void*) InetAddress_getallbyname },
313 { "gethostname", "()Ljava/lang/String;",
314 (void*) InetAddress_gethostname },
317 extern "C" int register_java_net_InetAddress(JNIEnv* env)
319 jclass tempClass = env->FindClass("[B");
321 byteArrayClass = (jclass) env->NewGlobalRef(tempClass);
323 if (!byteArrayClass) {
324 LOGE("register_java_net_InetAddress: cannot allocate byte array class");
327 return jniRegisterNativeMethods(env, "java/net/InetAddress",
328 gMethods, NELEM(gMethods));