1 /*
2 * Copyright (c) 2000, 2018, 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 extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
46
47
48 #if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
49 extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
50
51 /* Use getaddrinfo(3), which is thread safe */
52 /************************************************************************
53 * Inet4AddressImpl
54 */
55
56 /*
57 * Class: java_net_Inet4AddressImpl
58 * Method: getLocalHostName
59 * Signature: ()Ljava/lang/String;
60 */
61 JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv * env,jobject this)62 Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
63 char hostname[NI_MAXHOST + 1];
64
65 hostname[0] = '\0';
66 if (JVM_GetHostName(hostname, NI_MAXHOST)) {
67 strcpy(hostname, "localhost");
68 #if defined(__solaris__)
69 } else {
70 // try to resolve hostname via nameservice
71 // if it is known but getnameinfo fails, hostname will still be the
72 // value from gethostname
73 struct addrinfo hints, *res;
74
75 // make sure string is null-terminated
76 hostname[NI_MAXHOST] = '\0';
77 memset(&hints, 0, sizeof(hints));
78 hints.ai_flags = AI_CANONNAME;
79 hints.ai_family = AF_INET;
80
81 if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
82 getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
83 NULL, 0, NI_NAMEREQD);
84 freeaddrinfo(res);
85 }
86 }
87 #else
88 } else {
89 // make sure string is null-terminated
90 hostname[NI_MAXHOST] = '\0';
91 }
92 #endif
93 return (*env)->NewStringUTF(env, hostname);
94 }
95
96 /*
97 * Find an internet address for a given hostname. Note that this
98 * code only works for addresses of type INET. The translation
99 * of %d.%d.%d.%d to an address (int) occurs in java now, so the
100 * String "host" shouldn't *ever* be a %d.%d.%d.%d string
101 *
102 * Class: java_net_Inet4AddressImpl
103 * Method: lookupAllHostAddr
104 * Signature: (Ljava/lang/String;)[[B
105 */
106
107 JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv * env,jobject this,jstring host)108 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
109 jstring host) {
110 const char *hostname;
111 jobject name;
112 jobjectArray ret = 0;
113 int retLen = 0;
114
115 int getaddrinfo_error=0;
116 struct addrinfo hints, *res, *resNew = NULL;
117
118 initInetAddressIDs(env);
119 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
120
121 if (IS_NULL(host)) {
122 JNU_ThrowNullPointerException(env, "host is null");
123 return 0;
124 }
125 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
126 CHECK_NULL_RETURN(hostname, NULL);
127
128 memset(&hints, 0, sizeof(hints));
129 hints.ai_flags = AI_CANONNAME;
130 hints.ai_family = AF_INET;
131
132 /*
133 * Workaround for Solaris bug 4160367 - if a hostname contains a
134 * white space then 0.0.0.0 is returned
135 */
136 if (isspace((unsigned char)hostname[0])) {
137 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
138 (char *)hostname);
139 JNU_ReleaseStringPlatformChars(env, host, hostname);
140 return NULL;
141 }
142
143 getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
144
145 #ifdef MACOSX
146 if (getaddrinfo_error) {
147 // If getaddrinfo fails try getifaddrs.
148 ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
149 if (ret != NULL || (*env)->ExceptionCheck(env)) {
150 JNU_ReleaseStringPlatformChars(env, host, hostname);
151 return ret;
152 }
153 }
154 #endif
155
156 if (getaddrinfo_error) {
157 /* report error */
158 ThrowUnknownHostExceptionWithGaiError(
159 env, hostname, getaddrinfo_error);
160 JNU_ReleaseStringPlatformChars(env, host, hostname);
161 return NULL;
162 } else {
163 int i = 0;
164 struct addrinfo *itr, *last = NULL, *iterator = res;
165 while (iterator != NULL) {
166 int skip = 0;
167 itr = resNew;
168
169 while (itr != NULL) {
170 struct sockaddr_in *addr1, *addr2;
171
172 addr1 = (struct sockaddr_in *)iterator->ai_addr;
173 addr2 = (struct sockaddr_in *)itr->ai_addr;
174 if (addr1->sin_addr.s_addr ==
175 addr2->sin_addr.s_addr) {
176 skip = 1;
177 break;
178 }
179
180 itr = itr->ai_next;
181 }
182
183 if (!skip) {
184 struct addrinfo *next
185 = (struct addrinfo*) malloc(sizeof(struct addrinfo));
186 if (!next) {
187 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
188 ret = NULL;
189 goto cleanupAndReturn;
190 }
191 memcpy(next, iterator, sizeof(struct addrinfo));
192 next->ai_next = NULL;
193 if (resNew == NULL) {
194 resNew = next;
195 } else {
196 last->ai_next = next;
197 }
198 last = next;
199 i++;
200 }
201 iterator = iterator->ai_next;
202 }
203
204 retLen = i;
205 iterator = resNew;
206 i = 0;
207
208 name = (*env)->NewStringUTF(env, hostname);
209 if (IS_NULL(name)) {
210 goto cleanupAndReturn;
211 }
212
213 ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
214 if (IS_NULL(ret)) {
215 /* we may have memory to free at the end of this */
216 goto cleanupAndReturn;
217 }
218
219 while (iterator != NULL) {
220 /* We need 4 bytes to store ipv4 address; */
221 int len = 4;
222
223 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
224 if (IS_NULL(iaObj)) {
225 /* we may have memory to free at the end of this */
226 ret = NULL;
227 goto cleanupAndReturn;
228 }
229 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
230 if ((*env)->ExceptionCheck(env))
231 goto cleanupAndReturn;
232 setInetAddress_hostName(env, iaObj, name);
233 if ((*env)->ExceptionCheck(env))
234 goto cleanupAndReturn;
235 (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
236 i++;
237 iterator = iterator->ai_next;
238 }
239 }
240
241 cleanupAndReturn:
242 {
243 struct addrinfo *iterator, *tmp;
244 iterator = resNew;
245 while (iterator != NULL) {
246 tmp = iterator;
247 iterator = iterator->ai_next;
248 free(tmp);
249 }
250 JNU_ReleaseStringPlatformChars(env, host, hostname);
251 }
252
253 freeaddrinfo(res);
254
255 return ret;
256
257 }
258
259 /*
260 * Class: java_net_Inet4AddressImpl
261 * Method: getHostByAddr
262 * Signature: (I)Ljava/lang/String;
263 */
264 JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv * env,jobject this,jbyteArray addrArray)265 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
266 jbyteArray addrArray) {
267 jstring ret = NULL;
268
269 char host[NI_MAXHOST+1];
270 jfieldID fid;
271 int error = 0;
272 jint family;
273 struct sockaddr *him ;
274 int len = 0;
275 jbyte caddr[4];
276 jint addr;
277
278 struct sockaddr_in him4;
279 struct sockaddr *sa;
280
281 /*
282 * For IPv4 addresses construct a sockaddr_in structure.
283 */
284 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
285 addr = ((caddr[0]<<24) & 0xff000000);
286 addr |= ((caddr[1] <<16) & 0xff0000);
287 addr |= ((caddr[2] <<8) & 0xff00);
288 addr |= (caddr[3] & 0xff);
289 memset((char *) &him4, 0, sizeof(him4));
290 him4.sin_addr.s_addr = (uint32_t) htonl(addr);
291 him4.sin_family = AF_INET;
292 sa = (struct sockaddr *) &him4;
293 len = sizeof(him4);
294
295 error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
296 NI_NAMEREQD);
297
298 if (!error) {
299 ret = (*env)->NewStringUTF(env, host);
300 }
301
302 if (ret == NULL) {
303 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
304 }
305
306 return ret;
307
308 }
309
310 #else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
311
312 /* the initial size of our hostent buffers */
313 #ifndef NI_MAXHOST
314 #define NI_MAXHOST 1025
315 #endif
316
317 /************************************************************************
318 * Inet4AddressImpl
319 */
320
321 /*
322 * Class: java_net_Inet4AddressImpl
323 * Method: getLocalHostName
324 * Signature: ()Ljava/lang/String;
325 */
326 JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv * env,jobject this)327 Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
328 char hostname[NI_MAXHOST+1];
329
330 hostname[0] = '\0';
331 if (JVM_GetHostName(hostname, sizeof(hostname))) {
332 /* Something went wrong, maybe networking is not setup? */
333 strcpy(hostname, "localhost");
334 } else {
335 struct addrinfo hints, *res;
336 int error;
337
338 hostname[NI_MAXHOST] = '\0';
339 memset(&hints, 0, sizeof(hints));
340 hints.ai_flags = AI_CANONNAME;
341 hints.ai_family = AF_INET;
342
343 error = getaddrinfo(hostname, NULL, &hints, &res);
344
345 if (error == 0) {/* host is known to name service */
346 getnameinfo(res->ai_addr,
347 res->ai_addrlen,
348 hostname,
349 NI_MAXHOST,
350 NULL,
351 0,
352 NI_NAMEREQD);
353
354 /* if getnameinfo fails hostname is still the value
355 from gethostname */
356
357 freeaddrinfo(res);
358 }
359 }
360 return (*env)->NewStringUTF(env, hostname);
361 }
362
363 /*
364 * Find an internet address for a given hostname. Note that this
365 * code only works for addresses of type INET. The translation
366 * of %d.%d.%d.%d to an address (int) occurs in java now, so the
367 * String "host" shouldn't *ever* be a %d.%d.%d.%d string
368 *
369 * Class: java_net_Inet4AddressImpl
370 * Method: lookupAllHostAddr
371 * Signature: (Ljava/lang/String;)[[B
372 */
373
374 JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv * env,jobject this,jstring host)375 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
376 jstring host) {
377 const char *hostname;
378 jobjectArray ret = 0;
379 int retLen = 0;
380 int error = 0;
381 struct addrinfo hints, *res, *resNew = NULL;
382
383 initInetAddressIDs(env);
384 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
385
386 if (IS_NULL(host)) {
387 JNU_ThrowNullPointerException(env, "host is null");
388 return 0;
389 }
390 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
391 CHECK_NULL_RETURN(hostname, NULL);
392
393 /* Try once, with our static buffer. */
394 memset(&hints, 0, sizeof(hints));
395 hints.ai_flags = AI_CANONNAME;
396 hints.ai_family = AF_INET;
397
398 #ifdef __solaris__
399 /*
400 * Workaround for Solaris bug 4160367 - if a hostname contains a
401 * white space then 0.0.0.0 is returned
402 */
403 if (isspace((unsigned char)hostname[0])) {
404 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
405 (char *)hostname);
406 JNU_ReleaseStringPlatformChars(env, host, hostname);
407 return NULL;
408 }
409 #endif
410
411 #ifdef _ALLBSD_SOURCE
412 /* If we're looking up the local machine, bypass DNS lookups and get
413 * address from getifaddrs.
414 */
415 ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
416 if (ret != NULL || (*env)->ExceptionCheck(env)) {
417 JNU_ReleaseStringPlatformChars(env, host, hostname);
418 return ret;
419 }
420 #endif
421
422 error = getaddrinfo(hostname, NULL, &hints, &res);
423
424 if (error) {
425 /* report error */
426 ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
427 JNU_ReleaseStringPlatformChars(env, host, hostname);
428 return NULL;
429 } else {
430 int i = 0;
431 struct addrinfo *itr, *last = NULL, *iterator = res;
432
433 while (iterator != NULL) {
434 // remove the duplicate one
435 int skip = 0;
436 itr = resNew;
437 while (itr != NULL) {
438 struct sockaddr_in *addr1, *addr2;
439 addr1 = (struct sockaddr_in *)iterator->ai_addr;
440 addr2 = (struct sockaddr_in *)itr->ai_addr;
441 if (addr1->sin_addr.s_addr ==
442 addr2->sin_addr.s_addr) {
443 skip = 1;
444 break;
445 }
446 itr = itr->ai_next;
447 }
448
449 if (!skip) {
450 struct addrinfo *next
451 = (struct addrinfo*) malloc(sizeof(struct addrinfo));
452 if (!next) {
453 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
454 ret = NULL;
455 goto cleanupAndReturn;
456 }
457 memcpy(next, iterator, sizeof(struct addrinfo));
458 next->ai_next = NULL;
459 if (resNew == NULL) {
460 resNew = next;
461 } else {
462 last->ai_next = next;
463 }
464 last = next;
465 i++;
466 }
467 iterator = iterator->ai_next;
468 }
469
470 retLen = i;
471 iterator = resNew;
472
473 ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
474
475 if (IS_NULL(ret)) {
476 /* we may have memory to free at the end of this */
477 goto cleanupAndReturn;
478 }
479
480 i = 0;
481 while (iterator != NULL) {
482 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
483 if (IS_NULL(iaObj)) {
484 ret = NULL;
485 goto cleanupAndReturn;
486 }
487 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
488 if ((*env)->ExceptionCheck(env))
489 goto cleanupAndReturn;
490 setInetAddress_hostName(env, iaObj, host);
491 if ((*env)->ExceptionCheck(env))
492 goto cleanupAndReturn;
493 (*env)->SetObjectArrayElement(env, ret, i++, iaObj);
494 iterator = iterator->ai_next;
495 }
496 }
497
498 cleanupAndReturn:
499 {
500 struct addrinfo *iterator, *tmp;
501 iterator = resNew;
502 while (iterator != NULL) {
503 tmp = iterator;
504 iterator = iterator->ai_next;
505 free(tmp);
506 }
507 JNU_ReleaseStringPlatformChars(env, host, hostname);
508 }
509
510 freeaddrinfo(res);
511
512 return ret;
513 }
514
515 /*
516 * Class: java_net_Inet4AddressImpl
517 * Method: getHostByAddr
518 * Signature: (I)Ljava/lang/String;
519 */
520 JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv * env,jobject this,jbyteArray addrArray)521 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
522 jbyteArray addrArray) {
523 jstring ret = NULL;
524
525 char host[NI_MAXHOST+1];
526 int error = 0;
527 int len = 0;
528 jbyte caddr[4];
529
530 struct sockaddr_in him4;
531 struct sockaddr *sa;
532
533 jint addr;
534 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
535 addr = ((caddr[0]<<24) & 0xff000000);
536 addr |= ((caddr[1] <<16) & 0xff0000);
537 addr |= ((caddr[2] <<8) & 0xff00);
538 addr |= (caddr[3] & 0xff);
539 memset((void *) &him4, 0, sizeof(him4));
540 him4.sin_addr.s_addr = (uint32_t) htonl(addr);
541 him4.sin_family = AF_INET;
542 sa = (struct sockaddr *) &him4;
543 len = sizeof(him4);
544
545 error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
546 NI_NAMEREQD);
547
548 if (!error) {
549 ret = (*env)->NewStringUTF(env, host);
550 }
551
552 if (ret == NULL) {
553 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
554 }
555
556 return ret;
557 }
558
559 #endif /* _ALLBSD_SOURCE */
560
561 #define SET_NONBLOCKING(fd) { \
562 int flags = fcntl(fd, F_GETFL); \
563 flags |= O_NONBLOCK; \
564 fcntl(fd, F_SETFL, flags); \
565 }
566
567 /**
568 * ping implementation.
569 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
570 * expires or a answer is received.
571 * Returns true is an ECHO_REPLY is received, otherwise, false.
572 */
573 static jboolean
ping4(JNIEnv * env,jint fd,struct sockaddr_in * him,jint timeout,struct sockaddr_in * netif,jint ttl)574 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
575 struct sockaddr_in* netif, jint ttl) {
576 jint size;
577 jint n, hlen1, icmplen;
578 socklen_t len;
579 char sendbuf[1500];
580 char recvbuf[1500];
581 struct icmp *icmp;
582 struct ip *ip;
583 struct sockaddr_in sa_recv;
584 jchar pid;
585 jint tmout2, seq = 1;
586 struct timeval tv;
587 size_t plen;
588
589 /* icmp_id is a 16 bit data type, therefore down cast the pid */
590 pid = (jchar)getpid();
591 size = 60*1024;
592 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
593 /*
594 * sets the ttl (max number of hops)
595 */
596 if (ttl > 0) {
597 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
598 }
599 /*
600 * a specific interface was specified, so let's bind the socket
601 * to that interface to ensure the requests are sent only through it.
602 */
603 if (netif != NULL) {
604 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
605 NET_ThrowNew(env, errno, "Can't bind socket");
606 close(fd);
607 return JNI_FALSE;
608 }
609 }
610 /*
611 * Make the socket non blocking so we can use select
612 */
613 SET_NONBLOCKING(fd);
614 do {
615 /*
616 * create the ICMP request
617 */
618 icmp = (struct icmp *) sendbuf;
619 icmp->icmp_type = ICMP_ECHO;
620 icmp->icmp_code = 0;
621 icmp->icmp_id = htons(pid);
622 icmp->icmp_seq = htons(seq);
623 seq++;
624 gettimeofday(&tv, NULL);
625 memcpy(icmp->icmp_data, &tv, sizeof(tv));
626 plen = ICMP_ADVLENMIN + sizeof(tv);
627 icmp->icmp_cksum = 0;
628 icmp->icmp_cksum = in_cksum((u_short *)icmp, plen);
629 /*
630 * send it
631 */
632 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him,
633 sizeof(struct sockaddr));
634 if (n < 0 && errno != EINPROGRESS ) {
635 #ifdef __linux__
636 if (errno != EINVAL && errno != EHOSTUNREACH)
637 /*
638 * On some Linux versions, when a socket is bound to the loopback
639 * interface, sendto will fail and errno will be set to
640 * EINVAL or EHOSTUNREACH. When that happens, don't throw an
641 * exception, just return false.
642 */
643 #endif /*__linux__ */
644 NET_ThrowNew(env, errno, "Can't send ICMP packet");
645 close(fd);
646 return JNI_FALSE;
647 }
648
649 tmout2 = timeout > 1000 ? 1000 : timeout;
650 do {
651 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
652 if (tmout2 >= 0) {
653 len = sizeof(sa_recv);
654 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len);
655 ip = (struct ip*) recvbuf;
656 hlen1 = (ip->ip_hl) << 2;
657 icmp = (struct icmp *) (recvbuf + hlen1);
658 icmplen = n - hlen1;
659 /*
660 * We did receive something, but is it what we were expecting?
661 * I.E.: A ICMP_ECHOREPLY packet with the proper PID.
662 */
663 if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY
664 && (ntohs(icmp->icmp_id) == pid)) {
665 if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
666 close(fd);
667 return JNI_TRUE;
668 }
669
670 if (him->sin_addr.s_addr == 0) {
671 close(fd);
672 return JNI_TRUE;
673 }
674 }
675
676 }
677 } while (tmout2 > 0);
678 timeout -= 1000;
679 } while (timeout >0);
680 close(fd);
681 return JNI_FALSE;
682 }
683
684 /*
685 * Class: java_net_Inet4AddressImpl
686 * Method: isReachable0
687 * Signature: ([bI[bI)Z
688 */
689 JNIEXPORT jboolean JNICALL
Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv * env,jobject this,jbyteArray addrArray,jint timeout,jbyteArray ifArray,jint ttl)690 Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
691 jbyteArray addrArray,
692 jint timeout,
693 jbyteArray ifArray,
694 jint ttl) {
695 jint addr;
696 jbyte caddr[4];
697 jint fd;
698 struct sockaddr_in him;
699 struct sockaddr_in* netif = NULL;
700 struct sockaddr_in inf;
701 int len = 0;
702 int connect_rv = -1;
703 int sz;
704
705 memset((char *) caddr, 0, sizeof(caddr));
706 memset((char *) &him, 0, sizeof(him));
707 memset((char *) &inf, 0, sizeof(inf));
708 sz = (*env)->GetArrayLength(env, addrArray);
709 if (sz != 4) {
710 return JNI_FALSE;
711 }
712 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
713 addr = ((caddr[0]<<24) & 0xff000000);
714 addr |= ((caddr[1] <<16) & 0xff0000);
715 addr |= ((caddr[2] <<8) & 0xff00);
716 addr |= (caddr[3] & 0xff);
717 addr = htonl(addr);
718 him.sin_addr.s_addr = addr;
719 him.sin_family = AF_INET;
720 len = sizeof(him);
721 /*
722 * If a network interface was specified, let's create the address
723 * for it.
724 */
725 if (!(IS_NULL(ifArray))) {
726 memset((char *) caddr, 0, sizeof(caddr));
727 (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
728 addr = ((caddr[0]<<24) & 0xff000000);
729 addr |= ((caddr[1] <<16) & 0xff0000);
730 addr |= ((caddr[2] <<8) & 0xff00);
731 addr |= (caddr[3] & 0xff);
732 addr = htonl(addr);
733 inf.sin_addr.s_addr = addr;
734 inf.sin_family = AF_INET;
735 inf.sin_port = 0;
736 netif = &inf;
737 }
738
739 /*
740 * Let's try to create a RAW socket to send ICMP packets
741 * This usually requires "root" privileges, so it's likely to fail.
742 */
743 fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
744 if (fd != -1) {
745 /*
746 * It didn't fail, so we can use ICMP_ECHO requests.
747 */
748 return ping4(env, fd, &him, timeout, netif, ttl);
749 }
750
751 /*
752 * Can't create a raw socket, so let's try a TCP socket
753 */
754 fd = JVM_Socket(AF_INET, SOCK_STREAM, 0);
755 if (fd == JVM_IO_ERR) {
756 /* note: if you run out of fds, you may not be able to load
757 * the exception class, and get a NoClassDefFoundError
758 * instead.
759 */
760 NET_ThrowNew(env, errno, "Can't create socket");
761 return JNI_FALSE;
762 }
763 if (ttl > 0) {
764 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
765 }
766
767 /*
768 * A network interface was specified, so let's bind to it.
769 */
770 if (netif != NULL) {
771 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
772 NET_ThrowNew(env, errno, "Can't bind socket");
773 close(fd);
774 return JNI_FALSE;
775 }
776 }
777
778 /*
779 * Make the socket non blocking so we can use select/poll.
780 */
781 SET_NONBLOCKING(fd);
782
783 /* no need to use NET_Connect as non-blocking */
784 him.sin_port = htons(7); /* Echo */
785 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him, len);
786
787 /**
788 * connection established or refused immediately, either way it means
789 * we were able to reach the host!
790 */
791 if (connect_rv == 0 || errno == ECONNREFUSED) {
792 close(fd);
793 return JNI_TRUE;
794 } else {
795 int optlen;
796
797 switch (errno) {
798 case ENETUNREACH: /* Network Unreachable */
799 case EAFNOSUPPORT: /* Address Family not supported */
800 case EADDRNOTAVAIL: /* address is not available on the remote machine */
801 #ifdef __linux__
802 case EINVAL:
803 case EHOSTUNREACH:
804 /*
805 * On some Linux versions, when a socket is bound to the loopback
806 * interface, connect will fail and errno will be set to EINVAL
807 * or EHOSTUNREACH. When that happens, don't throw an exception,
808 * just return false.
809 */
810 #endif /* __linux__ */
811 close(fd);
812 return JNI_FALSE;
813 }
814
815 if (errno != EINPROGRESS) {
816 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
817 "connect failed");
818 close(fd);
819 return JNI_FALSE;
820 }
821
822 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
823 if (timeout >= 0) {
824 /* has connection been established? */
825 optlen = sizeof(connect_rv);
826 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
827 &optlen) <0) {
828 connect_rv = errno;
829 }
830 if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
831 close(fd);
832 return JNI_TRUE;
833 }
834 }
835 close(fd);
836 return JNI_FALSE;
837 }
838 }
839