1 /*
2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in_systm.h>
31 #include <netinet/in.h>
32 #include <netinet/ip.h>
33 #include <netinet/ip_icmp.h>
34 #include <netdb.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <ctype.h>
38
39 #include "jvm.h"
40 #include "jni_util.h"
41 #include "net_util.h"
42
43 #include "java_net_Inet4AddressImpl.h"
44
45 /* the initial size of our hostent buffers */
46 #define HENT_BUF_SIZE 1024
47 #define BIG_HENT_BUF_SIZE 10240 /* a jumbo-sized one */
48
49 /************************************************************************
50 * Inet4AddressImpl
51 */
52
53 /*
54 * Class: java_net_Inet4AddressImpl
55 * Method: getLocalHostName
56 * Signature: ()Ljava/lang/String;
57 */
58 JNIEXPORT jstring JNICALL
59 Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
60 char hostname[MAXHOSTNAMELEN+1];
61
62 hostname[0] = '\0';
63 if (JVM_GetHostName(hostname, MAXHOSTNAMELEN)) {
64 /* Something went wrong, maybe networking is not setup? */
65 strcpy(hostname, "localhost");
66 } else {
67 #ifdef __linux__
68 /* On Linux gethostname() says "host.domain.sun.com". On
69 * Solaris gethostname() says "host", so extra work is needed.
70 */
71 #else
72 /* Solaris doesn't want to give us a fully qualified domain name.
73 * We do a reverse lookup to try and get one. This works
74 * if DNS occurs before NIS in /etc/resolv.conf, but fails
75 * if NIS comes first (it still gets only a partial name).
76 * We use thread-safe system calls.
77 */
78 #endif /* __linux__ */
79 struct hostent res, res2, *hp;
80 // these buffers must be pointer-aligned so they are declared
81 // with pointer type
82 char *buf[HENT_BUF_SIZE/(sizeof (char *))];
83 char *buf2[HENT_BUF_SIZE/(sizeof (char *))];
84 int h_error=0;
85
86 #ifdef __GLIBC__
87 gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
88 #else
89 hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
90 #endif
91 if (hp) {
92 #ifdef __GLIBC__
93 gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
94 &res2, (char*)buf2, sizeof(buf2), &hp, &h_error);
95 #else
96 hp = gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
97 &res2, (char*)buf2, sizeof(buf2), &h_error);
98 #endif
99 if (hp) {
100 /*
101 * If gethostbyaddr_r() found a fully qualified host name,
102 * returns that name. Otherwise, returns the hostname
103 * found by gethostname().
104 */
105 char *p = hp->h_name;
106 if ((strlen(hp->h_name) > strlen(hostname))
107 && (strncmp(hostname, hp->h_name, strlen(hostname)) == 0)
108 && (*(p + strlen(hostname)) == '.'))
109 strcpy(hostname, hp->h_name);
110 }
111 }
112 }
113 return (*env)->NewStringUTF(env, hostname);
114 }
115
116 static jclass ni_iacls;
117 static jclass ni_ia4cls;
118 static jmethodID ni_ia4ctrID;
119 static jfieldID ni_iaaddressID;
120 static jfieldID ni_iahostID;
121 static jfieldID ni_iafamilyID;
122 static int initialized = 0;
123
124 /*
125 * Find an internet address for a given hostname. Note that this
126 * code only works for addresses of type INET. The translation
127 * of %d.%d.%d.%d to an address (int) occurs in java now, so the
128 * String "host" shouldn't *ever* be a %d.%d.%d.%d string
129 *
130 * Class: java_net_Inet4AddressImpl
131 * Method: lookupAllHostAddr
132 * Signature: (Ljava/lang/String;)[[B
133 */
134
135 JNIEXPORT jobjectArray JNICALL
136 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
137 jstring host) {
138 const char *hostname;
139 jobjectArray ret = 0;
140 struct hostent res, *hp = 0;
141 // this buffer must be pointer-aligned so is declared
142 // with pointer type
143 char *buf[HENT_BUF_SIZE/(sizeof (char *))];
144
145 /* temporary buffer, on the off chance we need to expand */
146 char *tmp = NULL;
147 int h_error=0;
148
149 if (!initialized) {
150 ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
151 ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
152 ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
153 ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
154 ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
155 ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I");
156 ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I");
157 ni_iahostID = (*env)->GetFieldID(env, ni_iacls, "hostName", "Ljava/lang/String;");
158 initialized = 1;
159 }
160
161 if (IS_NULL(host)) {
162 JNU_ThrowNullPointerException(env, "host is null");
163 return 0;
164 }
165 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
166 CHECK_NULL_RETURN(hostname, NULL);
167
168 #ifdef __solaris__
169 /*
170 * Workaround for Solaris bug 4160367 - if a hostname contains a
171 * white space then 0.0.0.0 is returned
172 */
173 if (isspace((unsigned char)hostname[0])) {
174 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
175 (char *)hostname);
176 JNU_ReleaseStringPlatformChars(env, host, hostname);
177 return NULL;
178 }
179 #endif
180
181 /* Try once, with our static buffer. */
182 #ifdef __GLIBC__
183 gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
184 #else
185 hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
186 #endif
187
188 /* With the re-entrant system calls, it's possible that the buffer
189 * we pass to it is not large enough to hold an exceptionally
190 * large DNS entry. This is signaled by errno->ERANGE. We try once
191 * more, with a very big size.
192 */
193 if (hp == NULL && errno == ERANGE) {
194 if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
195 #ifdef __GLIBC__
196 gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
197 &hp, &h_error);
198 #else
199 hp = gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
200 &h_error);
201 #endif
202 }
203 }
204 if (hp != NULL) {
205 struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
206 int i = 0;
207
208 while (*addrp != (struct in_addr *) 0) {
209 i++;
210 addrp++;
211 }
212
213 ret = (*env)->NewObjectArray(env, i, ni_iacls, NULL);
214 if (IS_NULL(ret)) {
215 /* we may have memory to free at the end of this */
216 goto cleanupAndReturn;
217 }
218 addrp = (struct in_addr **) hp->h_addr_list;
219 i = 0;
220 while (*addrp) {
221 jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
222 if (IS_NULL(iaObj)) {
223 ret = NULL;
224 goto cleanupAndReturn;
225 }
226 (*env)->SetIntField(env, iaObj, ni_iaaddressID,
227 ntohl((*addrp)->s_addr));
228 (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
229 (*env)->SetObjectArrayElement(env, ret, i, iaObj);
230 addrp++;
231 i++;
232 }
233 } else {
234 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
235 (char *)hostname);
236 ret = NULL;
237 }
238
239 cleanupAndReturn:
240 JNU_ReleaseStringPlatformChars(env, host, hostname);
241 if (tmp != NULL) {
242 free(tmp);
243 }
244 return ret;
245 }
246
247 /*
248 * Class: java_net_Inet4AddressImpl
249 * Method: getHostByAddr
250 * Signature: (I)Ljava/lang/String;
251 */
252 JNIEXPORT jstring JNICALL
253 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
254 jbyteArray addrArray) {
255 jstring ret = NULL;
256 jint addr;
257 struct hostent hent, *hp = 0;
258 // this buffer must be pointer-aligned so is declared
259 // with pointer type
260 char *buf[HENT_BUF_SIZE/(sizeof (char *))];
261 int h_error = 0;
262 char *tmp = NULL;
263
264 /*
265 * We are careful here to use the reentrant version of
266 * gethostbyname because at the Java level this routine is not
267 * protected by any synchronization.
268 *
269 * Still keeping the reentrant platform dependent calls temporarily
270 * We should probably conform to one interface later.
271 *
272 */
273 jbyte caddr[4];
274 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
275 addr = ((caddr[0]<<24) & 0xff000000);
276 addr |= ((caddr[1] <<16) & 0xff0000);
277 addr |= ((caddr[2] <<8) & 0xff00);
278 addr |= (caddr[3] & 0xff);
279 addr = htonl(addr);
280 #ifdef __GLIBC__
281 gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
282 (char*)buf, sizeof(buf), &hp, &h_error);
283 #else
284 hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
285 (char*)buf, sizeof(buf), &h_error);
286 #endif
287 /* With the re-entrant system calls, it's possible that the buffer
288 * we pass to it is not large enough to hold an exceptionally
289 * large DNS entry. This is signaled by errno->ERANGE. We try once
290 * more, with a very big size.
291 */
292 if (hp == NULL && errno == ERANGE) {
293 if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
294 #ifdef __GLIBC__
295 gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
296 &hent, tmp, BIG_HENT_BUF_SIZE, &hp, &h_error);
297 #else
298 hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
299 &hent, tmp, BIG_HENT_BUF_SIZE, &h_error);
300 #endif
301 } else {
302 JNU_ThrowOutOfMemoryError(env, "getHostByAddr");
303 }
304 }
305 if (hp == NULL) {
306 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
307 } else {
308 ret = (*env)->NewStringUTF(env, hp->h_name);
309 }
310 if (tmp) {
311 free(tmp);
312 }
313 return ret;
314 }
315
316 #define SET_NONBLOCKING(fd) { \
317 int flags = fcntl(fd, F_GETFL); \
318 flags |= O_NONBLOCK; \
319 fcntl(fd, F_SETFL, flags); \
320 }
321
322 /**
323 * ping implementation.
324 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
325 * expires or a answer is received.
326 * Returns true is an ECHO_REPLY is received, otherwise, false.
327 */
328 static jboolean
329 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
330 struct sockaddr_in* netif, jint ttl) {
331 jint size;
332 jint n, hlen1, icmplen;
333 socklen_t len;
334 char sendbuf[1500];
335 char recvbuf[1500];
336 struct icmp *icmp;
337 struct ip *ip;
338 struct sockaddr_in sa_recv;
339 jchar pid;
340 jint tmout2, seq = 1;
341 struct timeval tv;
342 size_t plen;
343
344 /* icmp_id is a 16 bit data type, therefore down cast the pid */
345 pid = (jchar)getpid();
346 size = 60*1024;
347 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
348 /*
349 * sets the ttl (max number of hops)
350 */
351 if (ttl > 0) {
352 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
353 }
354 /*
355 * a specific interface was specified, so let's bind the socket
356 * to that interface to ensure the requests are sent only through it.
357 */
358 if (netif != NULL) {
359 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
360 NET_ThrowNew(env, errno, "Can't bind socket");
361 close(fd);
362 return JNI_FALSE;
363 }
364 }
365 /*
366 * Make the socket non blocking so we can use select
367 */
368 SET_NONBLOCKING(fd);
369 do {
370 /*
371 * create the ICMP request
372 */
373 icmp = (struct icmp *) sendbuf;
374 icmp->icmp_type = ICMP_ECHO;
375 icmp->icmp_code = 0;
376 icmp->icmp_id = htons(pid);
377 icmp->icmp_seq = htons(seq);
378 seq++;
379 gettimeofday(&tv, NULL);
380 memcpy(icmp->icmp_data, &tv, sizeof(tv));
381 plen = ICMP_ADVLENMIN + sizeof(tv);
382 icmp->icmp_cksum = 0;
383 icmp->icmp_cksum = in_cksum((u_short *)icmp, plen);
384 /*
385 * send it
386 */
387 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him,
388 sizeof(struct sockaddr));
389 if (n < 0 && errno != EINPROGRESS ) {
390 #ifdef __linux__
391 if (errno != EINVAL)
392 /*
393 * On some Linuxes, when bound to the loopback interface, sendto
394 * will fail and errno will be set to EINVAL. When that happens,
395 * don't throw an exception, just return false.
396 */
397 #endif /*__linux__ */
398 NET_ThrowNew(env, errno, "Can't send ICMP packet");
399 close(fd);
400 return JNI_FALSE;
401 }
402
403 tmout2 = timeout > 1000 ? 1000 : timeout;
404 do {
405 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
406 if (tmout2 >= 0) {
407 len = sizeof(sa_recv);
408 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len);
409 ip = (struct ip*) recvbuf;
410 hlen1 = (ip->ip_hl) << 2;
411 icmp = (struct icmp *) (recvbuf + hlen1);
412 icmplen = n - hlen1;
413 /*
414 * We did receive something, but is it what we were expecting?
415 * I.E.: A ICMP_ECHOREPLY packet with the proper PID.
416 */
417 if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY &&
418 (ntohs(icmp->icmp_id) == pid) &&
419 (him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
420 close(fd);
421 return JNI_TRUE;
422 }
423 }
424 } while (tmout2 > 0);
425 timeout -= 1000;
426 } while (timeout >0);
427 close(fd);
428 return JNI_FALSE;
429 }
430
431 /*
432 * Class: java_net_Inet4AddressImpl
433 * Method: isReachable0
434 * Signature: ([bI[bI)Z
435 */
436 JNIEXPORT jboolean JNICALL
437 Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
438 jbyteArray addrArray,
439 jint timeout,
440 jbyteArray ifArray,
441 jint ttl) {
442 jint addr;
443 jbyte caddr[4];
444 jint fd;
445 struct sockaddr_in him;
446 struct sockaddr_in* netif = NULL;
447 struct sockaddr_in inf;
448 int len = 0;
449 int connect_rv = -1;
450 int sz;
451
452 memset((char *) caddr, 0, sizeof(caddr));
453 memset((char *) &him, 0, sizeof(him));
454 sz = (*env)->GetArrayLength(env, addrArray);
455 if (sz != 4) {
456 return JNI_FALSE;
457 }
458 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
459 addr = ((caddr[0]<<24) & 0xff000000);
460 addr |= ((caddr[1] <<16) & 0xff0000);
461 addr |= ((caddr[2] <<8) & 0xff00);
462 addr |= (caddr[3] & 0xff);
463 addr = htonl(addr);
464 him.sin_addr.s_addr = addr;
465 him.sin_family = AF_INET;
466 len = sizeof(him);
467 /*
468 * If a network interface was specified, let's create the address
469 * for it.
470 */
471 if (!(IS_NULL(ifArray))) {
472 memset((char *) caddr, 0, sizeof(caddr));
473 (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
474 addr = ((caddr[0]<<24) & 0xff000000);
475 addr |= ((caddr[1] <<16) & 0xff0000);
476 addr |= ((caddr[2] <<8) & 0xff00);
477 addr |= (caddr[3] & 0xff);
478 addr = htonl(addr);
479 inf.sin_addr.s_addr = addr;
480 inf.sin_family = AF_INET;
481 inf.sin_port = 0;
482 netif = &inf;
483 }
484
485 /*
486 * Let's try to create a RAW socket to send ICMP packets
487 * This usually requires "root" privileges, so it's likely to fail.
488 */
489 fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
490 if (fd != -1) {
491 /*
492 * It didn't fail, so we can use ICMP_ECHO requests.
493 */
494 return ping4(env, fd, &him, timeout, netif, ttl);
495 }
496
497 /*
498 * Can't create a raw socket, so let's try a TCP socket
499 */
500 fd = JVM_Socket(AF_INET, SOCK_STREAM, 0);
501 if (fd == JVM_IO_ERR) {
502 /* note: if you run out of fds, you may not be able to load
503 * the exception class, and get a NoClassDefFoundError
504 * instead.
505 */
506 NET_ThrowNew(env, errno, "Can't create socket");
507 return JNI_FALSE;
508 }
509 if (ttl > 0) {
510 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
511 }
512
513 /*
514 * A network interface was specified, so let's bind to it.
515 */
516 if (netif != NULL) {
517 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
518 NET_ThrowNew(env, errno, "Can't bind socket");
519 close(fd);
520 return JNI_FALSE;
521 }
522 }
523
524 /*
525 * Make the socket non blocking so we can use select/poll.
526 */
527 SET_NONBLOCKING(fd);
528
529 /* no need to use NET_Connect as non-blocking */
530 him.sin_port = htons(7); /* Echo */
531 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him, len);
532
533 /**
534 * connection established or refused immediately, either way it means
535 * we were able to reach the host!
536 */
537 if (connect_rv == 0 || errno == ECONNREFUSED) {
538 close(fd);
539 return JNI_TRUE;
540 } else {
541 int optlen;
542
543 switch (errno) {
544 case ENETUNREACH: /* Network Unreachable */
545 case EAFNOSUPPORT: /* Address Family not supported */
546 case EADDRNOTAVAIL: /* address is not available on the remote machine */
547 #ifdef __linux__
548 case EINVAL:
549 /*
550 * On some Linuxes, when bound to the loopback interface, connect
551 * will fail and errno will be set to EINVAL. When that happens,
552 * don't throw an exception, just return false.
553 */
554 #endif /* __linux__ */
555 close(fd);
556 return JNI_FALSE;
557 }
558
559 if (errno != EINPROGRESS) {
560 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
561 "connect failed");
562 close(fd);
563 return JNI_FALSE;
564 }
565
566 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
567 if (timeout >= 0) {
568 /* has connection been established? */
569 optlen = sizeof(connect_rv);
570 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
571 &optlen) <0) {
572 connect_rv = errno;
573 }
574 if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
575 close(fd);
576 return JNI_TRUE;
577 }
578 }
579 close(fd);
580 return JNI_FALSE;
581 }
582 }
--- EOF ---