1 /* 2 * Copyright 2000-2009 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any 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.h> 31 #include <netdb.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <stdlib.h> 35 #include <ctype.h> 36 37 #include "jvm.h" 38 #include "jni_util.h" 39 #include "net_util.h" 40 #ifndef IPV6_DEFS_H 41 #include <netinet/icmp6.h> 42 #endif 43 44 #include "java_net_Inet4AddressImpl.h" 45 #include "java_net_Inet6AddressImpl.h" 46 47 /* the initial size of our hostent buffers */ 48 #ifndef NI_MAXHOST 49 #define NI_MAXHOST 1025 50 #endif 51 52 53 /************************************************************************ 54 * Inet6AddressImpl 55 */ 56 57 /* 58 * Class: java_net_Inet6AddressImpl 59 * Method: getLocalHostName 60 * Signature: ()Ljava/lang/String; 61 */ 62 JNIEXPORT jstring JNICALL 63 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { 64 char hostname[NI_MAXHOST+1]; 65 66 hostname[0] = '\0'; 67 if (JVM_GetHostName(hostname, MAXHOSTNAMELEN)) { 68 /* Something went wrong, maybe networking is not setup? */ 69 strcpy(hostname, "localhost"); 70 } else { 71 #ifdef __linux__ 72 /* On Linux gethostname() says "host.domain.sun.com". On 73 * Solaris gethostname() says "host", so extra work is needed. 74 */ 75 #else 76 /* Solaris doesn't want to give us a fully qualified domain name. 77 * We do a reverse lookup to try and get one. This works 78 * if DNS occurs before NIS in /etc/resolv.conf, but fails 79 * if NIS comes first (it still gets only a partial name). 80 * We use thread-safe system calls. 81 */ 82 #ifdef AF_INET6 83 if (NET_addrtransAvailable()) { 84 struct addrinfo hints, *res; 85 int error; 86 87 bzero(&hints, sizeof(hints)); 88 hints.ai_flags = AI_CANONNAME; 89 hints.ai_family = AF_UNSPEC; 90 91 error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res); 92 93 if (error == 0) { 94 /* host is known to name service */ 95 error = (*getnameinfo_ptr)(res->ai_addr, 96 res->ai_addrlen, 97 hostname, 98 NI_MAXHOST, 99 NULL, 100 0, 101 NI_NAMEREQD); 102 103 /* if getnameinfo fails hostname is still the value 104 from gethostname */ 105 106 (*freeaddrinfo_ptr)(res); 107 } 108 } 109 #endif /* AF_INET6 */ 110 #endif /* __linux__ */ 111 } 112 return (*env)->NewStringUTF(env, hostname); 113 } 114 115 /* 116 * Find an internet address for a given hostname. Not this this 117 * code only works for addresses of type INET. The translation 118 * of %d.%d.%d.%d to an address (int) occurs in java now, so the 119 * String "host" shouldn't *ever* be a %d.%d.%d.%d string 120 * 121 * Class: java_net_Inet6AddressImpl 122 * Method: lookupAllHostAddr 123 * Signature: (Ljava/lang/String;)[[B 124 */ 125 126 JNIEXPORT jobjectArray JNICALL 127 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 128 jstring host) { 129 const char *hostname; 130 jobjectArray ret = 0; 131 int retLen = 0; 132 jboolean preferIPv6Address; 133 134 int error=0; 135 #ifdef AF_INET6 136 struct addrinfo hints, *res, *resNew = NULL; 137 #endif /* AF_INET6 */ 138 139 init(env); 140 141 if (IS_NULL(host)) { 142 JNU_ThrowNullPointerException(env, "host is null"); 143 return 0; 144 } 145 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); 146 CHECK_NULL_RETURN(hostname, NULL); 147 148 #ifdef AF_INET6 149 if (NET_addrtransAvailable()) { 150 /* get the address preference */ 151 preferIPv6Address 152 = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID); 153 154 /* Try once, with our static buffer. */ 155 bzero(&hints, sizeof(hints)); 156 hints.ai_flags = AI_CANONNAME; 157 hints.ai_family = AF_UNSPEC; 158 159 #ifdef __solaris__ 160 /* 161 * Workaround for Solaris bug 4160367 - if a hostname contains a 162 * white space then 0.0.0.0 is returned 163 */ 164 if (isspace((unsigned char)hostname[0])) { 165 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 166 (char *)hostname); 167 JNU_ReleaseStringPlatformChars(env, host, hostname); 168 return NULL; 169 } 170 #endif 171 172 error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res); 173 174 if (error) { 175 /* report error */ 176 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 177 (char *)hostname); 178 JNU_ReleaseStringPlatformChars(env, host, hostname); 179 return NULL; 180 } else { 181 int i = 0; 182 int inetCount = 0, inet6Count = 0, inetIndex, inet6Index; 183 struct addrinfo *itr, *last = NULL, *iterator = res; 184 while (iterator != NULL) { 185 int skip = 0; 186 itr = resNew; 187 while (itr != NULL) { 188 if (iterator->ai_family == itr->ai_family && 189 iterator->ai_addrlen == itr->ai_addrlen) { 190 if (itr->ai_family == AF_INET) { /* AF_INET */ 191 struct sockaddr_in *addr1, *addr2; 192 addr1 = (struct sockaddr_in *)iterator->ai_addr; 193 addr2 = (struct sockaddr_in *)itr->ai_addr; 194 if (addr1->sin_addr.s_addr == 195 addr2->sin_addr.s_addr) { 196 skip = 1; 197 break; 198 } 199 } else { 200 int t; 201 struct sockaddr_in6 *addr1, *addr2; 202 addr1 = (struct sockaddr_in6 *)iterator->ai_addr; 203 addr2 = (struct sockaddr_in6 *)itr->ai_addr; 204 205 for (t = 0; t < 16; t++) { 206 if (addr1->sin6_addr.s6_addr[t] != 207 addr2->sin6_addr.s6_addr[t]) { 208 break; 209 } 210 } 211 if (t < 16) { 212 itr = itr->ai_next; 213 continue; 214 } else { 215 skip = 1; 216 break; 217 } 218 } 219 } else if (iterator->ai_family != AF_INET && 220 iterator->ai_family != AF_INET6) { 221 /* we can't handle other family types */ 222 skip = 1; 223 break; 224 } 225 itr = itr->ai_next; 226 } 227 228 if (!skip) { 229 struct addrinfo *next 230 = (struct addrinfo*) malloc(sizeof(struct addrinfo)); 231 if (!next) { 232 JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); 233 ret = NULL; 234 goto cleanupAndReturn; 235 } 236 memcpy(next, iterator, sizeof(struct addrinfo)); 237 next->ai_next = NULL; 238 if (resNew == NULL) { 239 resNew = next; 240 } else { 241 last->ai_next = next; 242 } 243 last = next; 244 i++; 245 if (iterator->ai_family == AF_INET) { 246 inetCount ++; 247 } else if (iterator->ai_family == AF_INET6) { 248 inet6Count ++; 249 } 250 } 251 iterator = iterator->ai_next; 252 } 253 retLen = i; 254 iterator = resNew; 255 256 ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL); 257 258 if (IS_NULL(ret)) { 259 /* we may have memory to free at the end of this */ 260 goto cleanupAndReturn; 261 } 262 263 if (preferIPv6Address) { 264 /* AF_INET addresses will be offset by inet6Count */ 265 inetIndex = inet6Count; 266 inet6Index = 0; 267 } else { 268 /* AF_INET6 addresses will be offset by inetCount */ 269 inetIndex = 0; 270 inet6Index = inetCount; 271 } 272 273 while (iterator != NULL) { 274 if (iterator->ai_family == AF_INET) { 275 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 276 if (IS_NULL(iaObj)) { 277 ret = NULL; 278 goto cleanupAndReturn; 279 } 280 (*env)->SetIntField(env, iaObj, ia_addressID, 281 ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); 282 (*env)->SetObjectField(env, iaObj, ia_hostNameID, host); 283 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); 284 inetIndex++; 285 } else if (iterator->ai_family == AF_INET6) { 286 jint scope = 0; 287 jbyteArray ipaddress; 288 289 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 290 if (IS_NULL(iaObj)) { 291 ret = NULL; 292 goto cleanupAndReturn; 293 } 294 ipaddress = (*env)->NewByteArray(env, 16); 295 if (IS_NULL(ipaddress)) { 296 ret = NULL; 297 goto cleanupAndReturn; 298 } 299 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16, 300 (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr)); 301 #ifdef __linux__ 302 if (!kernelIsV22()) { 303 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id; 304 } 305 #else 306 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id; 307 #endif 308 if (scope != 0) { /* zero is default value, no need to set */ 309 (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); 310 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); 311 } 312 (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress); 313 (*env)->SetObjectField(env, iaObj, ia_hostNameID, host); 314 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); 315 inet6Index++; 316 } 317 iterator = iterator->ai_next; 318 } 319 } 320 } 321 322 cleanupAndReturn: 323 { 324 struct addrinfo *iterator, *tmp; 325 iterator = resNew; 326 while (iterator != NULL) { 327 tmp = iterator; 328 iterator = iterator->ai_next; 329 free(tmp); 330 } 331 JNU_ReleaseStringPlatformChars(env, host, hostname); 332 } 333 334 if (NET_addrtransAvailable()) 335 (*freeaddrinfo_ptr)(res); 336 #endif /* AF_INET6 */ 337 338 return ret; 339 } 340 341 /* 342 * Class: java_net_Inet6AddressImpl 343 * Method: getHostByAddr 344 * Signature: (I)Ljava/lang/String; 345 */ 346 JNIEXPORT jstring JNICALL 347 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 348 jbyteArray addrArray) { 349 350 jstring ret = NULL; 351 352 #ifdef AF_INET6 353 char host[NI_MAXHOST+1]; 354 int error = 0; 355 int len = 0; 356 jbyte caddr[16]; 357 358 if (NET_addrtransAvailable()) { 359 struct sockaddr_in him4; 360 struct sockaddr_in6 him6; 361 struct sockaddr *sa; 362 363 /* 364 * For IPv4 addresses construct a sockaddr_in structure. 365 */ 366 if ((*env)->GetArrayLength(env, addrArray) == 4) { 367 jint addr; 368 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 369 addr = ((caddr[0]<<24) & 0xff000000); 370 addr |= ((caddr[1] <<16) & 0xff0000); 371 addr |= ((caddr[2] <<8) & 0xff00); 372 addr |= (caddr[3] & 0xff); 373 memset((char *) &him4, 0, sizeof(him4)); 374 him4.sin_addr.s_addr = (uint32_t) htonl(addr); 375 him4.sin_family = AF_INET; 376 sa = (struct sockaddr *) &him4; 377 len = sizeof(him4); 378 } else { 379 /* 380 * For IPv6 address construct a sockaddr_in6 structure. 381 */ 382 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 383 memset((char *) &him6, 0, sizeof(him6)); 384 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); 385 him6.sin6_family = AF_INET6; 386 sa = (struct sockaddr *) &him6 ; 387 len = sizeof(him6) ; 388 } 389 390 error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0, 391 NI_NAMEREQD); 392 393 if (!error) { 394 ret = (*env)->NewStringUTF(env, host); 395 } 396 } 397 #endif /* AF_INET6 */ 398 399 if (ret == NULL) { 400 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); 401 } 402 403 return ret; 404 } 405 406 #define SET_NONBLOCKING(fd) { \ 407 int flags = fcntl(fd, F_GETFL); \ 408 flags |= O_NONBLOCK; \ 409 fcntl(fd, F_SETFL, flags); \ 410 } 411 412 #ifdef AF_INET6 413 static jboolean 414 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout, 415 struct sockaddr_in6* netif, jint ttl) { 416 jint size; 417 jint n; 418 socklen_t len; 419 char sendbuf[1500]; 420 unsigned char recvbuf[1500]; 421 struct icmp6_hdr *icmp6; 422 struct sockaddr_in6 sa_recv; 423 jbyte *caddr, *recv_caddr; 424 jchar pid; 425 jint tmout2, seq = 1; 426 struct timeval tv; 427 size_t plen; 428 429 #ifdef __linux__ 430 { 431 int csum_offset; 432 /** 433 * For some strange reason, the linux kernel won't calculate the 434 * checksum of ICMPv6 packets unless you set this socket option 435 */ 436 csum_offset = 2; 437 setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int)); 438 } 439 #endif 440 441 caddr = (jbyte *)&(him->sin6_addr); 442 443 /* icmp_id is a 16 bit data type, therefore down cast the pid */ 444 pid = (jchar)getpid(); 445 size = 60*1024; 446 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 447 if (ttl > 0) { 448 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 449 } 450 if (netif != NULL) { 451 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) { 452 NET_ThrowNew(env, errno, "Can't bind socket"); 453 close(fd); 454 return JNI_FALSE; 455 } 456 } 457 SET_NONBLOCKING(fd); 458 459 do { 460 icmp6 = (struct icmp6_hdr *) sendbuf; 461 icmp6->icmp6_type = ICMP6_ECHO_REQUEST; 462 icmp6->icmp6_code = 0; 463 /* let's tag the ECHO packet with our pid so we can identify it */ 464 icmp6->icmp6_id = htons(pid); 465 icmp6->icmp6_seq = htons(seq); 466 seq++; 467 icmp6->icmp6_cksum = 0; 468 gettimeofday(&tv, NULL); 469 memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv)); 470 plen = sizeof(struct icmp6_hdr) + sizeof(tv); 471 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6)); 472 if (n < 0 && errno != EINPROGRESS) { 473 NET_ThrowNew(env, errno, "Can't send ICMP packet"); 474 return JNI_FALSE; 475 } 476 477 tmout2 = timeout > 1000 ? 1000 : timeout; 478 do { 479 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); 480 481 if (tmout2 >= 0) { 482 len = sizeof(sa_recv); 483 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len); 484 icmp6 = (struct icmp6_hdr *) (recvbuf); 485 recv_caddr = (jbyte *)&(sa_recv.sin6_addr); 486 /* 487 * We did receive something, but is it what we were expecting? 488 * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and 489 * from the host that we are trying to determine is reachable. 490 */ 491 if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY && 492 (ntohs(icmp6->icmp6_id) == pid) && 493 NET_IsEqual(caddr, recv_caddr)) { 494 close(fd); 495 return JNI_TRUE; 496 } 497 } 498 } while (tmout2 > 0); 499 timeout -= 1000; 500 } while (timeout > 0); 501 close(fd); 502 return JNI_FALSE; 503 } 504 #endif /* AF_INET6 */ 505 506 /* 507 * Class: java_net_Inet6AddressImpl 508 * Method: isReachable0 509 * Signature: ([bII[bI)Z 510 */ 511 JNIEXPORT jboolean JNICALL 512 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, 513 jbyteArray addrArray, 514 jint scope, 515 jint timeout, 516 jbyteArray ifArray, 517 jint ttl, jint if_scope) { 518 #ifdef AF_INET6 519 jbyte caddr[16]; 520 jint fd, sz; 521 struct sockaddr_in6 him6; 522 struct sockaddr_in6 inf6; 523 struct sockaddr_in6* netif = NULL; 524 int len = 0; 525 int connect_rv = -1; 526 527 /* 528 * If IPv6 is not enable, then we can't reach an IPv6 address, can we? 529 */ 530 if (!ipv6_available()) { 531 return JNI_FALSE; 532 } 533 /* 534 * If it's an IPv4 address, ICMP won't work with IPv4 mapped address, 535 * therefore, let's delegate to the Inet4Address method. 536 */ 537 sz = (*env)->GetArrayLength(env, addrArray); 538 if (sz == 4) { 539 return Java_java_net_Inet4AddressImpl_isReachable0(env, this, 540 addrArray, 541 timeout, 542 ifArray, ttl); 543 } 544 545 memset((char *) caddr, 0, 16); 546 memset((char *) &him6, 0, sizeof(him6)); 547 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 548 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); 549 him6.sin6_family = AF_INET6; 550 #ifdef __linux__ 551 if (scope > 0) 552 him6.sin6_scope_id = scope; 553 else 554 him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr)); 555 len = sizeof(struct sockaddr_in6); 556 #else 557 if (scope > 0) 558 him6.sin6_scope_id = scope; 559 len = sizeof(struct sockaddr_in6); 560 #endif 561 /* 562 * If a network interface was specified, let's create the address 563 * for it. 564 */ 565 if (!(IS_NULL(ifArray))) { 566 memset((char *) caddr, 0, 16); 567 memset((char *) &inf6, 0, sizeof(inf6)); 568 (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr); 569 memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) ); 570 inf6.sin6_family = AF_INET6; 571 inf6.sin6_scope_id = if_scope; 572 netif = &inf6; 573 } 574 /* 575 * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST 576 * otherwise we'll try a tcp socket to the Echo port (7). 577 * Note that this is empiric, and not connecting could mean it's blocked 578 * or the echo servioe has been disabled. 579 */ 580 581 fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 582 583 if (fd != -1) { /* Good to go, let's do a ping */ 584 return ping6(env, fd, &him6, timeout, netif, ttl); 585 } 586 587 /* No good, let's fall back on TCP */ 588 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0); 589 if (fd == JVM_IO_ERR) { 590 /* note: if you run out of fds, you may not be able to load 591 * the exception class, and get a NoClassDefFoundError 592 * instead. 593 */ 594 NET_ThrowNew(env, errno, "Can't create socket"); 595 return JNI_FALSE; 596 } 597 if (ttl > 0) { 598 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 599 } 600 601 /* 602 * A network interface was specified, so let's bind to it. 603 */ 604 if (netif != NULL) { 605 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) { 606 NET_ThrowNew(env, errno, "Can't bind socket"); 607 close(fd); 608 return JNI_FALSE; 609 } 610 } 611 SET_NONBLOCKING(fd); 612 613 /* no need to use NET_Connect as non-blocking */ 614 him6.sin6_port = htons((short) 7); /* Echo port */ 615 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len); 616 617 /** 618 * connection established or refused immediately, either way it means 619 * we were able to reach the host! 620 */ 621 if (connect_rv == 0 || errno == ECONNREFUSED) { 622 close(fd); 623 return JNI_TRUE; 624 } else { 625 int optlen; 626 627 switch (errno) { 628 case ENETUNREACH: /* Network Unreachable */ 629 case EAFNOSUPPORT: /* Address Family not supported */ 630 case EADDRNOTAVAIL: /* address is not available on the remote machine */ 631 #ifdef __linux__ 632 case EINVAL: 633 /* 634 * On some Linuxes, when bound to the loopback interface, connect 635 * will fail and errno will be set to EINVAL. When that happens, 636 * don't throw an exception, just return false. 637 */ 638 #endif /* __linux__ */ 639 close(fd); 640 return JNI_FALSE; 641 } 642 643 if (errno != EINPROGRESS) { 644 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 645 "connect failed"); 646 close(fd); 647 return JNI_FALSE; 648 } 649 650 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 651 652 if (timeout >= 0) { 653 /* has connection been established */ 654 optlen = sizeof(connect_rv); 655 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 656 &optlen) <0) { 657 connect_rv = errno; 658 } 659 if (connect_rv == 0 || ECONNREFUSED) { 660 close(fd); 661 return JNI_TRUE; 662 } 663 } 664 close(fd); 665 return JNI_FALSE; 666 } 667 #else /* AF_INET6 */ 668 return JNI_FALSE; 669 #endif /* AF_INET6 */ 670 }