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"
22 #include "utils/Log.h"
31 #include <cutils/properties.h>
32 #include <cutils/adb_networking.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <sys/socket.h>
38 static jclass byteArrayClass = NULL;
40 static jstring InetAddress_gethostname(JNIEnv* env, jobject obj)
43 int r = gethostname(name, 256);
45 return env->NewStringUTF(name);
51 static void throwNullPointerException(JNIEnv* env)
53 const char* className = "java/lang/NullPointerException";
55 jclass exClass = env->FindClass(className);
57 if (exClass == NULL) {
58 LOGE("Unable to find class %s", className);
60 env->ThrowNew(exClass, NULL);
65 static void logIpString(struct addrinfo* ai, const char* name)
67 char ipString[INET6_ADDRSTRLEN];
68 int result = getnameinfo(ai->ai_addr, ai->ai_addrlen, ipString,
69 sizeof(ipString), NULL, 0, NI_NUMERICHOST);
71 LOGD("%s: %s (family %d, proto %d)", name, ipString, ai->ai_family,
74 LOGE("%s: getnameinfo: %s", name, gai_strerror(result));
78 static inline void logIpString(struct addrinfo* ai, const char* name)
83 static jobjectArray getAllByNameUsingAdb(JNIEnv* env, const char* name)
85 struct in_addr outaddr;
86 jobjectArray addressArray = NULL;
90 LOGI("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
91 err, (unsigned int)outaddr.a.s_addr,
92 outaddr.j[0],outaddr.j[1],
93 outaddr.j[2],outaddr.j[3]);
96 if (adb_networking_gethostbyname(name, &outaddr) >= 0) {
97 addressArray = env->NewObjectArray(1, byteArrayClass, NULL);
98 byteArray = env->NewByteArray(4);
99 if (addressArray && byteArray) {
100 env->SetByteArrayRegion(byteArray, 0, 4, (jbyte*) &outaddr.s_addr);
101 env->SetObjectArrayElement(addressArray, 1, byteArray);
107 static jobjectArray getAllByNameUsingDns(JNIEnv* env, const char* name,
108 jboolean preferIPv4Stack)
110 struct addrinfo hints, *addressList = NULL, *addrInfo;
111 jobjectArray addressArray = NULL;
113 memset(&hints, 0, sizeof(hints));
115 * IPv4 only for now until the socket code supports IPv6; otherwise, the
116 * resolver will create two separate requests, one for IPv4 and one,
117 * currently unnecessary, for IPv6.
119 hints.ai_family = AF_UNSPEC;
120 hints.ai_flags = AI_ADDRCONFIG;
122 * If we don't specify a socket type, every address will appear twice, once
123 * for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
124 * anyway, just pick one.
126 hints.ai_socktype = SOCK_STREAM;
128 int result = getaddrinfo(name, NULL, &hints, &addressList);
129 if (result == 0 && addressList) {
130 // Count results so we know how to size the output array.
131 int addressCount = 0;
132 for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
133 if (addrInfo->ai_family == AF_INET ||
134 addrInfo->ai_family == AF_INET6) {
139 // Prepare output array.
140 addressArray = env->NewObjectArray(addressCount, byteArrayClass, NULL);
141 if (addressArray == NULL) {
142 // Appropriate exception will be thrown.
143 LOGE("getAllByNameUsingDns: could not allocate output array");
144 freeaddrinfo(addrInfo);
148 // Examine returned addresses one by one, save them in the output array.
150 for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
151 struct sockaddr* address = addrInfo->ai_addr;
152 size_t addressLength = 0;
155 switch (addrInfo->ai_family) {
156 // Find the raw address length and start pointer.
160 &((struct sockaddr_in6*) address)->sin6_addr.s6_addr;
161 logIpString(addrInfo, name);
166 &((struct sockaddr_in*) address)->sin_addr.s_addr;
167 logIpString(addrInfo, name);
170 // Unknown address family. Skip this address.
171 LOGE("getAllByNameUsingDns: Unknown address family %d",
172 addrInfo->ai_family);
176 // Convert each IP address into a Java byte array.
177 jbyteArray bytearray = env->NewByteArray(addressLength);
178 if (bytearray == NULL) {
179 // Out of memory error will be thrown on return.
180 LOGE("getAllByNameUsingDns: Can't allocate %d-byte array",
185 env->SetByteArrayRegion(bytearray, 0, addressLength,
186 (jbyte*) rawAddress);
187 env->SetObjectArrayElement(addressArray, index, bytearray);
188 env->DeleteLocalRef(bytearray);
191 } else if (result == EAI_SYSTEM && errno == EACCES) {
192 /* No permission to use network */
194 env, "java/lang/SecurityException",
195 "Permission denied (maybe missing INTERNET permission)");
197 // Do nothing. Return value will be null and the caller will throw an
198 // UnknownHostExeption.
202 freeaddrinfo(addressList);
208 jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
210 jboolean preferIPv4Stack)
212 if (javaName == NULL) {
213 throwNullPointerException(env);
217 const char* name = env->GetStringUTFChars(javaName, NULL);
218 jobjectArray out = NULL;
220 char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
221 char adbConnected[PROPERTY_VALUE_MAX];
222 property_get("android.net.use-adb-networking",
223 useAdbNetworkingProperty, "");
224 property_get("adb.connected",
227 // Any non-empty string value for use-adb-networking is considered "set"
228 if ((strlen(useAdbNetworkingProperty) > 0)
229 && (strlen(adbConnected) > 0) ) {
230 out = getAllByNameUsingAdb(env, name);
232 out = getAllByNameUsingDns(env, name, preferIPv4Stack);
236 LOGI("Unknown host %s, throwing UnknownHostException", name);
237 jniThrowException(env, "java/net/UnknownHostException", name);
239 env->ReleaseStringUTFChars(javaName, name);
244 static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
245 jbyteArray javaAddress)
247 if (javaAddress == NULL) {
248 throwNullPointerException(env);
252 size_t addrlen = env->GetArrayLength(javaAddress);
253 jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
254 if (rawAddress == NULL) {
255 throwNullPointerException(env);
259 // Convert the raw address bytes into a socket address structure.
260 struct sockaddr_storage ss;
261 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
262 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
266 socklen = sizeof(struct sockaddr_in);
267 memset(sin, 0, sizeof(struct sockaddr_in));
268 sin->sin_family = AF_INET;
269 memcpy(&sin->sin_addr.s_addr, rawAddress, 4);
270 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
273 socklen = sizeof(struct sockaddr_in6);
274 memset(sin6, 0, sizeof(struct sockaddr_in6));
275 sin6->sin6_family = AF_INET6;
276 memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 16);
277 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
280 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
281 jniThrowException(env, "java/net/UnknownHostException",
282 "Invalid address length");
287 // Convert the socket address structure to an IP string for logging.
289 char ipstr[INET6_ADDRSTRLEN];
290 ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr),
291 NULL, 0, NI_NUMERICHOST);
293 LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret));
297 // Look up the IP address from the socket address structure.
298 jstring result = NULL;
299 char name[NI_MAXHOST];
300 ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
303 LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name);
304 result = env->NewStringUTF(name);
306 LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr,
316 static JNINativeMethod gMethods[] = {
317 /* name, signature, funcPtr */
318 { "gethostbyaddr", "([B)Ljava/lang/String;",
319 (void*) InetAddress_gethostbyaddr },
320 { "getallbyname", "(Ljava/lang/String;Z)[[B",
321 (void*) InetAddress_getallbyname },
322 { "gethostname", "()Ljava/lang/String;",
323 (void*) InetAddress_gethostname },
326 extern "C" int register_java_net_InetAddress(JNIEnv* env)
328 jclass tempClass = env->FindClass("[B");
330 byteArrayClass = (jclass) env->NewGlobalRef(tempClass);
332 if (!byteArrayClass) {
333 LOGE("register_java_net_InetAddress: cannot allocate byte array class");
336 return jniRegisterNativeMethods(env, "java/net/InetAddress",
337 gMethods, NELEM(gMethods));