OSDN Git Service

am 2b2e488b: Exposed default trust manager.
[android-x86/dalvik.git] / libcore / luni / src / main / native / java_net_InetAddress.cpp
1 /*
2  * Copyright (C) 2006 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 "InetAddress"
18
19 #define LOG_DNS 0
20
21 #include "JNIHelp.h"
22 #include "utils/Log.h"
23 #include "jni.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <netdb.h>
29 #include <errno.h>
30
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>
36
37
38 static jclass byteArrayClass = NULL;
39
40 static jstring InetAddress_gethostname(JNIEnv* env, jobject obj)
41 {
42     char name[256];
43     int r = gethostname(name, 256);
44     if (r == 0) {
45         return env->NewStringUTF(name);
46     } else {
47         return NULL;
48     }
49 }
50
51 static void throwNullPointerException(JNIEnv* env)
52 {
53     const char* className = "java/lang/NullPointerException";
54
55     jclass exClass = env->FindClass(className);
56
57     if (exClass == NULL) {
58         LOGE("Unable to find class %s", className);
59     } else {
60         env->ThrowNew(exClass, NULL);
61     }
62 }
63
64 #if LOG_DNS
65 static void logIpString(struct addrinfo* ai, const char* name)
66 {
67     char ipString[INET6_ADDRSTRLEN];
68     int result = getnameinfo(ai->ai_addr, ai->ai_addrlen, ipString,
69                              sizeof(ipString), NULL, 0, NI_NUMERICHOST);
70     if (result == 0) {
71         LOGD("%s: %s (family %d, proto %d)", name, ipString, ai->ai_family,
72              ai->ai_protocol);
73     } else {
74         LOGE("%s: getnameinfo: %s", name, gai_strerror(result));
75     }
76 }
77 #else
78 static inline void logIpString(struct addrinfo* ai, const char* name)
79 {
80 }
81 #endif
82
83 static jobjectArray getAllByNameUsingAdb(JNIEnv* env, const char* name)
84 {
85     struct in_addr outaddr;
86     jobjectArray addressArray = NULL;
87     jbyteArray byteArray;
88
89 #if 0
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]);
94 #endif
95
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);
102         }
103     }
104     return addressArray;
105 }
106
107 static jobjectArray getAllByNameUsingDns(JNIEnv* env, const char* name, 
108                                          jboolean preferIPv4Stack)
109 {
110     struct addrinfo hints, *addressList = NULL, *addrInfo;
111     jobjectArray addressArray = NULL;
112
113     memset(&hints, 0, sizeof(hints));
114     /*
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.
118      */
119     hints.ai_family = AF_UNSPEC;
120     hints.ai_flags = AI_ADDRCONFIG;
121     /*
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.
125      */
126     hints.ai_socktype = SOCK_STREAM;
127
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) {
135                 addressCount++;
136             }
137         }
138
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);
145             return NULL;
146         }
147
148         // Examine returned addresses one by one, save them in the output array.
149         int index = 0;
150         for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
151             struct sockaddr* address = addrInfo->ai_addr;
152             size_t addressLength = 0;
153             void* rawAddress;
154
155             switch (addrInfo->ai_family) {
156                 // Find the raw address length and start pointer.
157                 case AF_INET6:
158                     addressLength = 16;
159                     rawAddress =
160                         &((struct sockaddr_in6*) address)->sin6_addr.s6_addr;
161                     logIpString(addrInfo, name);
162                     break;
163                 case AF_INET:
164                     addressLength = 4;
165                     rawAddress =
166                         &((struct sockaddr_in*) address)->sin_addr.s_addr;
167                     logIpString(addrInfo, name);
168                     break;
169                 default:
170                     // Unknown address family. Skip this address.
171                     LOGE("getAllByNameUsingDns: Unknown address family %d",
172                          addrInfo->ai_family);
173                     continue;
174             }
175
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",
181                      addressLength);
182                 addressArray = NULL;
183                 break;
184             }
185             env->SetByteArrayRegion(bytearray, 0, addressLength,
186                                     (jbyte*) rawAddress);
187             env->SetObjectArrayElement(addressArray, index, bytearray);
188             env->DeleteLocalRef(bytearray);
189             index++;
190         }
191     } else if (result == EAI_SYSTEM && errno == EACCES) {
192         /* No permission to use network */
193         jniThrowException(
194             env, "java/lang/SecurityException",
195             "Permission denied (maybe missing INTERNET permission)");
196     } else {
197         // Do nothing. Return value will be null and the caller will throw an
198         // UnknownHostExeption.
199     }
200
201     if (addressList) {
202         freeaddrinfo(addressList);
203     }
204
205     return addressArray;
206 }
207
208 jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
209                                       jstring javaName,
210                                       jboolean preferIPv4Stack)
211 {
212     if (javaName == NULL) {
213         throwNullPointerException(env);
214         return NULL;
215     }
216
217     const char* name = env->GetStringUTFChars(javaName, NULL);
218     jobjectArray out = NULL;
219
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",
225             adbConnected, "");
226
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);
231     } else {
232         out = getAllByNameUsingDns(env, name, preferIPv4Stack);
233     }
234
235     if (!out) {
236         LOGI("Unknown host %s, throwing UnknownHostException", name);
237         jniThrowException(env, "java/net/UnknownHostException", name);
238     }
239     env->ReleaseStringUTFChars(javaName, name);
240     return out;
241 }
242
243
244 static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
245                                          jbyteArray javaAddress)
246 {
247     if (javaAddress == NULL) {
248         throwNullPointerException(env);
249         return NULL;
250     }
251
252     size_t addrlen = env->GetArrayLength(javaAddress);
253     jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
254     if (rawAddress == NULL) {
255         throwNullPointerException(env);
256         return NULL;
257     }
258
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;
263     size_t socklen;
264     switch (addrlen) {
265         case 4:
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);
271             break;
272         case 16:
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);
278             break;
279         default:
280             env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
281             jniThrowException(env, "java/net/UnknownHostException",
282                                    "Invalid address length");
283             return NULL;
284     }
285
286
287     // Convert the socket address structure to an IP string for logging.
288     int ret;
289     char ipstr[INET6_ADDRSTRLEN];
290     ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr),
291                       NULL, 0, NI_NUMERICHOST);
292     if (ret) {
293         LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret));
294         return NULL;
295     }
296
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),
301                       NULL, 0, 0);
302     if (ret == 0) {
303         LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name);
304         result = env->NewStringUTF(name);
305     } else {
306         LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr,
307              gai_strerror(ret));
308     }
309
310     return result;
311 }
312
313 /*
314  * JNI registration
315  */
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  },
324 };
325
326 extern "C" int register_java_net_InetAddress(JNIEnv* env)
327 {
328     jclass tempClass = env->FindClass("[B");
329     if (tempClass) {
330         byteArrayClass = (jclass) env->NewGlobalRef(tempClass);
331     }
332     if (!byteArrayClass) {
333         LOGE("register_java_net_InetAddress: cannot allocate byte array class");
334         return -1;
335     }
336     return jniRegisterNativeMethods(env, "java/net/InetAddress",
337                 gMethods, NELEM(gMethods));
338 }