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_INET;
121 * If we don't specify a socket type, every address will appear twice, once
122 * for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
123 * anyway, just pick one.
125 hints.ai_socktype = SOCK_STREAM;
127 int result = getaddrinfo(name, NULL, &hints, &addressList);
128 if (result == 0 && addressList) {
129 // Count results so we know how to size the output array.
130 int addressCount = 0;
131 for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
132 if (addrInfo->ai_family == AF_INET ||
133 addrInfo->ai_family == AF_INET6) {
138 // Prepare output array.
139 addressArray = env->NewObjectArray(addressCount, byteArrayClass, NULL);
140 if (addressArray == NULL) {
141 // Appropriate exception will be thrown.
142 LOGE("getAllByNameUsingDns: could not allocate output array");
143 freeaddrinfo(addrInfo);
147 // Examine returned addresses one by one, save them in the output array.
149 for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
150 struct sockaddr* address = addrInfo->ai_addr;
151 size_t addressLength = 0;
154 switch (addrInfo->ai_family) {
155 // Find the raw address length and start pointer.
159 &((struct sockaddr_in6*) address)->sin6_addr.s6_addr;
160 logIpString(addrInfo, name);
165 &((struct sockaddr_in*) address)->sin_addr.s_addr;
166 logIpString(addrInfo, name);
169 // Unknown address family. Skip this address.
170 LOGE("getAllByNameUsingDns: Unknown address family %d",
171 addrInfo->ai_family);
175 // Convert each IP address into a Java byte array.
176 jbyteArray bytearray = env->NewByteArray(addressLength);
177 if (bytearray == NULL) {
178 // Out of memory error will be thrown on return.
179 LOGE("getAllByNameUsingDns: Can't allocate %d-byte array",
184 env->SetByteArrayRegion(bytearray, 0, addressLength,
185 (jbyte*) rawAddress);
186 env->SetObjectArrayElement(addressArray, index, bytearray);
187 env->DeleteLocalRef(bytearray);
190 } else if (result == EAI_SYSTEM && errno == EACCES) {
191 /* No permission to use network */
193 env, "java/lang/SecurityException",
194 "Permission denied (maybe missing INTERNET permission)");
196 // Do nothing. Return value will be null and the caller will throw an
197 // UnknownHostExeption.
201 freeaddrinfo(addressList);
207 jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
209 jboolean preferIPv4Stack)
211 if (javaName == NULL) {
212 throwNullPointerException(env);
216 const char* name = env->GetStringUTFChars(javaName, NULL);
217 jobjectArray out = NULL;
219 char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
220 char adbConnected[PROPERTY_VALUE_MAX];
221 property_get("android.net.use-adb-networking",
222 useAdbNetworkingProperty, "");
223 property_get("adb.connected",
226 // Any non-empty string value for use-adb-networking is considered "set"
227 if ((strlen(useAdbNetworkingProperty) > 0)
228 && (strlen(adbConnected) > 0) ) {
229 out = getAllByNameUsingAdb(env, name);
231 out = getAllByNameUsingDns(env, name, preferIPv4Stack);
235 LOGI("Unknown host %s, throwing UnknownHostException", name);
236 jniThrowException(env, "java/net/UnknownHostException", name);
238 env->ReleaseStringUTFChars(javaName, name);
243 static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
244 jbyteArray javaAddress)
246 if (javaAddress == NULL) {
247 throwNullPointerException(env);
251 size_t addrlen = env->GetArrayLength(javaAddress);
252 jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
253 if (rawAddress == NULL) {
254 throwNullPointerException(env);
258 // Convert the raw address bytes into a socket address structure.
259 struct sockaddr_storage ss;
260 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
261 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
265 socklen = sizeof(struct sockaddr_in);
266 memset(sin, 0, sizeof(struct sockaddr_in));
267 sin->sin_family = AF_INET;
268 memcpy(&sin->sin_addr.s_addr, rawAddress, 4);
269 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
272 socklen = sizeof(struct sockaddr_in6);
273 memset(sin6, 0, sizeof(struct sockaddr_in6));
274 sin6->sin6_family = AF_INET6;
275 memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 16);
276 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
279 env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
280 jniThrowException(env, "java/net/UnknownHostException",
281 "Invalid address length");
286 // Convert the socket address structure to an IP string for logging.
288 char ipstr[INET6_ADDRSTRLEN];
289 ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr),
290 NULL, 0, NI_NUMERICHOST);
292 LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret));
296 // Look up the IP address from the socket address structure.
297 jstring result = NULL;
298 char name[NI_MAXHOST];
299 ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
302 LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name);
303 result = env->NewStringUTF(name);
305 LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr,
315 static JNINativeMethod gMethods[] = {
316 /* name, signature, funcPtr */
317 { "gethostbyaddr", "([B)Ljava/lang/String;",
318 (void*) InetAddress_gethostbyaddr },
319 { "getallbyname", "(Ljava/lang/String;Z)[[B",
320 (void*) InetAddress_getallbyname },
321 { "gethostname", "()Ljava/lang/String;",
322 (void*) InetAddress_gethostname },
325 extern "C" int register_java_net_InetAddress(JNIEnv* env)
327 jclass tempClass = env->FindClass("[B");
329 byteArrayClass = (jclass) env->NewGlobalRef(tempClass);
331 if (!byteArrayClass) {
332 LOGE("register_java_net_InetAddress: cannot allocate byte array class");
335 return jniRegisterNativeMethods(env, "java/net/InetAddress",
336 gMethods, NELEM(gMethods));