1 /* 2 * Copyright 2000-2008 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 <windows.h> 27 #include <winsock2.h> 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <malloc.h> 32 #include <sys/types.h> 33 #include <process.h> 34 35 #include "java_net_InetAddress.h" 36 #include "java_net_Inet4AddressImpl.h" 37 #include "java_net_Inet6AddressImpl.h" 38 #include "net_util.h" 39 #include "icmp.h" 40 41 #ifdef WIN32 42 #ifndef _WIN64 43 44 /* Retain this code a little longer to support building in 45 * old environments. _MSC_VER is defined as: 46 * 1200 for MSVC++ 6.0 47 * 1310 for Vc7 48 */ 49 #if defined(_MSC_VER) && _MSC_VER < 1310 50 #define sockaddr_in6 SOCKADDR_IN6 51 #endif 52 #endif 53 #define uint32_t UINT32 54 #endif 55 56 /* 57 * Inet6AddressImpl 58 */ 59 60 /* 61 * Class: java_net_Inet6AddressImpl 62 * Method: getLocalHostName 63 * Signature: ()Ljava/lang/String; 64 */ 65 JNIEXPORT jstring JNICALL 66 Java_java_net_Inet6AddressImpl_getLocalHostName (JNIEnv *env, jobject this) { 67 char hostname [256]; 68 69 if (gethostname (hostname, sizeof (hostname)) == -1) { 70 strcpy (hostname, "localhost"); 71 } 72 return JNU_NewStringPlatform (env, hostname); 73 } 74 75 76 JNIEXPORT jobjectArray JNICALL 77 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 78 jstring host) { 79 const char *hostname; 80 jobjectArray ret = 0; 81 int retLen = 0; 82 jboolean preferIPv6Address; 83 84 int error=0; 85 struct addrinfo hints, *res, *resNew = NULL; 86 87 init(env); 88 89 if (IS_NULL(host)) { 90 JNU_ThrowNullPointerException(env, "host is null"); 91 return 0; 92 } 93 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); 94 CHECK_NULL_RETURN(hostname, NULL); 95 96 if (NET_addrtransAvailable()) { 97 /* get the address preference */ 98 preferIPv6Address 99 = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID); 100 101 /* Try once, with our static buffer. */ 102 memset(&hints, 0, sizeof(hints)); 103 hints.ai_flags = AI_CANONNAME; 104 hints.ai_family = AF_UNSPEC; 105 106 error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res); 107 108 if (error) { 109 /* report error */ 110 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 111 (char *)hostname); 112 JNU_ReleaseStringPlatformChars(env, host, hostname); 113 return NULL; 114 } else { 115 int i = 0; 116 int inetCount = 0, inet6Count = 0, inetIndex, inet6Index; 117 struct addrinfo *itr, *last, *iterator = res; 118 while (iterator != NULL) { 119 int skip = 0; 120 itr = resNew; 121 while (itr != NULL) { 122 if (iterator->ai_family == itr->ai_family && 123 iterator->ai_addrlen == itr->ai_addrlen) { 124 if (itr->ai_family == AF_INET) { /* AF_INET */ 125 struct sockaddr_in *addr1, *addr2; 126 addr1 = (struct sockaddr_in *)iterator->ai_addr; 127 addr2 = (struct sockaddr_in *)itr->ai_addr; 128 if (addr1->sin_addr.s_addr == 129 addr2->sin_addr.s_addr) { 130 skip = 1; 131 break; 132 } 133 } else { 134 int t; 135 struct sockaddr_in6 *addr1, *addr2; 136 addr1 = (struct sockaddr_in6 *)iterator->ai_addr; 137 addr2 = (struct sockaddr_in6 *)itr->ai_addr; 138 139 for (t = 0; t < 16; t++) { 140 if (addr1->sin6_addr.s6_addr[t] != 141 addr2->sin6_addr.s6_addr[t]) { 142 break; 143 } 144 } 145 if (t < 16) { 146 itr = itr->ai_next; 147 continue; 148 } else { 149 skip = 1; 150 break; 151 } 152 } 153 } else if (iterator->ai_family != AF_INET && 154 iterator->ai_family != AF_INET6) { 155 /* we can't handle other family types */ 156 skip = 1; 157 break; 158 } 159 itr = itr->ai_next; 160 } 161 162 if (!skip) { 163 struct addrinfo *next 164 = (struct addrinfo*) malloc(sizeof(struct addrinfo)); 165 if (!next) { 166 JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); 167 ret = NULL; 168 goto cleanupAndReturn; 169 } 170 memcpy(next, iterator, sizeof(struct addrinfo)); 171 next->ai_next = NULL; 172 if (resNew == NULL) { 173 resNew = next; 174 } else { 175 last->ai_next = next; 176 } 177 last = next; 178 i++; 179 if (iterator->ai_family == AF_INET) { 180 inetCount ++; 181 } else if (iterator->ai_family == AF_INET6) { 182 inet6Count ++; 183 } 184 } 185 iterator = iterator->ai_next; 186 } 187 retLen = i; 188 iterator = resNew; 189 i = 0; 190 ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL); 191 192 if (IS_NULL(ret)) { 193 /* we may have memory to free at the end of this */ 194 goto cleanupAndReturn; 195 } 196 197 if (preferIPv6Address) { 198 inetIndex = inet6Count; 199 inet6Index = 0; 200 } else { 201 inetIndex = 0; 202 inet6Index = inetCount; 203 } 204 205 while (iterator != NULL) { 206 if (iterator->ai_family == AF_INET) { 207 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 208 if (IS_NULL(iaObj)) { 209 ret = NULL; 210 goto cleanupAndReturn; 211 } 212 (*env)->SetIntField(env, iaObj, ia_addressID, 213 ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); 214 (*env)->SetObjectField(env, iaObj, ia_hostNameID, host); 215 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj); 216 inetIndex ++; 217 } else if (iterator->ai_family == AF_INET6) { 218 jint scope = 0; 219 jbyteArray ipaddress; 220 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 221 if (IS_NULL(iaObj)) { 222 ret = NULL; 223 goto cleanupAndReturn; 224 } 225 ipaddress = (*env)->NewByteArray(env, 16); 226 if (IS_NULL(ipaddress)) { 227 ret = NULL; 228 goto cleanupAndReturn; 229 } 230 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16, 231 (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr)); 232 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id; 233 if (scope != 0) { /* zero is default value, no need to set */ 234 (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope); 235 (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE); 236 } 237 (*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress); 238 (*env)->SetObjectField(env, iaObj, ia_hostNameID, host); 239 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj); 240 inet6Index ++; 241 } 242 iterator = iterator->ai_next; 243 } 244 } 245 } 246 247 cleanupAndReturn: 248 { 249 struct addrinfo *iterator, *tmp; 250 iterator = resNew; 251 while (iterator != NULL) { 252 tmp = iterator; 253 iterator = iterator->ai_next; 254 free(tmp); 255 } 256 JNU_ReleaseStringPlatformChars(env, host, hostname); 257 } 258 259 if (NET_addrtransAvailable()) 260 (*freeaddrinfo_ptr)(res); 261 262 return ret; 263 } 264 265 /* 266 * Class: java_net_Inet6AddressImpl 267 * Method: getHostByAddr 268 * Signature: (I)Ljava/lang/String; 269 */ 270 JNIEXPORT jstring JNICALL 271 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 272 jbyteArray addrArray) { 273 jstring ret = NULL; 274 275 char host[NI_MAXHOST+1]; 276 int error = 0; 277 int len = 0; 278 jbyte caddr[16]; 279 280 if (NET_addrtransAvailable()) { 281 struct sockaddr_in him4; 282 struct sockaddr_in6 him6; 283 struct sockaddr *sa; 284 285 /* 286 * For IPv4 addresses construct a sockaddr_in structure. 287 */ 288 if ((*env)->GetArrayLength(env, addrArray) == 4) { 289 jint addr; 290 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 291 addr = ((caddr[0]<<24) & 0xff000000); 292 addr |= ((caddr[1] <<16) & 0xff0000); 293 addr |= ((caddr[2] <<8) & 0xff00); 294 addr |= (caddr[3] & 0xff); 295 memset((char *) &him4, 0, sizeof(him4)); 296 him4.sin_addr.s_addr = (uint32_t) htonl(addr); 297 him4.sin_family = AF_INET; 298 sa = (struct sockaddr *) &him4; 299 len = sizeof(him4); 300 } else { 301 /* 302 * For IPv6 address construct a sockaddr_in6 structure. 303 */ 304 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 305 memset((char *) &him6, 0, sizeof(him6)); 306 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); 307 him6.sin6_family = AF_INET6; 308 sa = (struct sockaddr *) &him6 ; 309 len = sizeof(him6) ; 310 } 311 312 error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0, 313 NI_NAMEREQD); 314 315 if (!error) { 316 ret = (*env)->NewStringUTF(env, host); 317 } 318 } 319 320 if (ret == NULL) { 321 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); 322 } 323 324 return ret; 325 } 326 327 #ifdef AF_INET6 328 329 330 /** 331 * ping implementation. 332 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout 333 * expires or a answer is received. 334 * Returns true is an ECHO_REPLY is received, otherwise, false. 335 */ 336 static jboolean 337 ping6(JNIEnv *env, jint fd, struct SOCKADDR_IN6* him, jint timeout, 338 struct SOCKADDR_IN6* netif, jint ttl) { 339 jint size; 340 jint n, len, i; 341 char sendbuf[1500]; 342 char auxbuf[1500]; 343 unsigned char recvbuf[1500]; 344 struct icmp6_hdr *icmp6; 345 struct SOCKADDR_IN6 sa_recv; 346 unsigned short pid, seq; 347 int read_rv = 0; 348 WSAEVENT hEvent; 349 struct ip6_pseudo_hdr *pseudo_ip6; 350 int timestamp; 351 int tmout2; 352 353 /* Initialize the sequence number to a suitable random number and 354 shift right one place to allow sufficient room for increamenting. */ 355 seq = ((unsigned short)rand()) >> 1; 356 357 /* icmp_id is a 16 bit data type, therefore down cast the pid */ 358 pid = (unsigned short) _getpid(); 359 360 size = 60*1024; 361 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&size, sizeof(size)); 362 /** 363 * A TTL was specified, let's set the socket option. 364 */ 365 if (ttl > 0) { 366 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *) &ttl, sizeof(ttl)); 367 } 368 369 /** 370 * A network interface was specified, let's bind to it. 371 */ 372 if (netif != NULL) { 373 if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0){ 374 NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface"); 375 closesocket(fd); 376 return JNI_FALSE; 377 } 378 } 379 380 /* 381 * Make the socket non blocking 382 */ 383 hEvent = WSACreateEvent(); 384 WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); 385 386 /** 387 * send 1 ICMP REQUEST every second until either we get a valid reply 388 * or the timeout expired. 389 */ 390 do { 391 /* let's tag the ECHO packet with our pid so we can identify it */ 392 timestamp = GetCurrentTime(); 393 memset(sendbuf, 0, 1500); 394 icmp6 = (struct icmp6_hdr *) sendbuf; 395 icmp6->icmp6_type = ICMP6_ECHO_REQUEST; 396 icmp6->icmp6_code = 0; 397 icmp6->icmp6_id = htons(pid); 398 icmp6->icmp6_seq = htons(seq); 399 icmp6->icmp6_cksum = 0; 400 memcpy((icmp6 + 1), ×tamp, sizeof(int)); 401 if (netif != NULL) { 402 memset(auxbuf, 0, 1500); 403 pseudo_ip6 = (struct ip6_pseudo_hdr*) auxbuf; 404 memcpy(&pseudo_ip6->ip6_src, &netif->sin6_addr, sizeof(struct in6_addr)); 405 memcpy(&pseudo_ip6->ip6_dst, &him->sin6_addr, sizeof(struct in6_addr)); 406 pseudo_ip6->ip6_plen= htonl( 64 ); 407 pseudo_ip6->ip6_nxt = htonl( IPPROTO_ICMPV6 ); 408 memcpy(auxbuf + sizeof(struct ip6_pseudo_hdr), icmp6, 64); 409 /** 410 * We shouldn't have to do that as computing the checksum is supposed 411 * to be done by the IPv6 stack. Unfortunately windows, here too, is 412 * uterly broken, or non compliant, so let's do it. 413 * Problem is to compute the checksum I need to know the source address 414 * which happens only if I know the interface to be used... 415 */ 416 icmp6->icmp6_cksum = in_cksum((u_short *)pseudo_ip6, sizeof(struct ip6_pseudo_hdr) + 64); 417 } 418 419 /** 420 * Ping! 421 */ 422 n = sendto(fd, sendbuf, 64, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6)); 423 if (n < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEADDRNOTAVAIL)) { 424 // Happens when using a "tunnel interface" for instance. 425 // Or trying to send a packet on a different scope. 426 closesocket(fd); 427 WSACloseEvent(hEvent); 428 return JNI_FALSE; 429 } 430 if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) { 431 NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet"); 432 closesocket(fd); 433 WSACloseEvent(hEvent); 434 return JNI_FALSE; 435 } 436 437 tmout2 = timeout > 1000 ? 1000 : timeout; 438 do { 439 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); 440 441 if (tmout2 >= 0) { 442 len = sizeof(sa_recv); 443 memset(recvbuf, 0, 1500); 444 /** 445 * For some unknown reason, besides plain stupidity, windows 446 * truncates the first 4 bytes of the icmpv6 header some we can't 447 * check for the ICMP_ECHOREPLY value. 448 * we'll check the other values, though 449 */ 450 n = recvfrom(fd, recvbuf + 4, sizeof(recvbuf) - 4, 0, (struct sockaddr*) &sa_recv, &len); 451 icmp6 = (struct icmp6_hdr *) (recvbuf); 452 memcpy(&i, (icmp6 + 1), sizeof(int)); 453 /** 454 * Is that the reply we were expecting? 455 */ 456 if (n >= 8 && ntohs(icmp6->icmp6_seq) == seq && 457 ntohs(icmp6->icmp6_id) == pid && i == timestamp) { 458 closesocket(fd); 459 WSACloseEvent(hEvent); 460 return JNI_TRUE; 461 } 462 } 463 } while (tmout2 > 0); 464 timeout -= 1000; 465 seq++; 466 } while (timeout > 0); 467 closesocket(fd); 468 WSACloseEvent(hEvent); 469 return JNI_FALSE; 470 } 471 #endif /* AF_INET6 */ 472 473 /* 474 * Class: java_net_Inet6AddressImpl 475 * Method: isReachable0 476 * Signature: ([bII[bI)Z 477 */ 478 JNIEXPORT jboolean JNICALL 479 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, 480 jbyteArray addrArray, 481 jint scope, 482 jint timeout, 483 jbyteArray ifArray, 484 jint ttl, jint if_scope) { 485 #ifdef AF_INET6 486 jbyte caddr[16]; 487 jint fd, sz; 488 struct sockaddr_in6 him6; 489 struct sockaddr_in6* netif = NULL; 490 struct sockaddr_in6 inf6; 491 WSAEVENT hEvent; 492 int len = 0; 493 int connect_rv = -1; 494 495 /* 496 * If IPv6 is not enable, then we can't reach an IPv6 address, can we? 497 * Actually, we probably shouldn't even get here. 498 */ 499 if (!ipv6_available()) { 500 return JNI_FALSE; 501 } 502 /* 503 * If it's an IPv4 address, ICMP won't work with IPv4 mapped address, 504 * therefore, let's delegate to the Inet4Address method. 505 */ 506 sz = (*env)->GetArrayLength(env, addrArray); 507 if (sz == 4) { 508 return Java_java_net_Inet4AddressImpl_isReachable0(env, this, 509 addrArray, 510 timeout, 511 ifArray, ttl); 512 } 513 514 memset((char *) caddr, 0, 16); 515 memset((char *) &him6, 0, sizeof(him6)); 516 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 517 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); 518 him6.sin6_family = AF_INET6; 519 if (scope > 0) { 520 him6.sin6_scope_id = scope; 521 } 522 len = sizeof(struct sockaddr_in6); 523 /** 524 * A network interface was specified, let's convert the address 525 */ 526 if (!(IS_NULL(ifArray))) { 527 memset((char *) caddr, 0, 16); 528 memset((char *) &inf6, 0, sizeof(inf6)); 529 (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr); 530 memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) ); 531 inf6.sin6_family = AF_INET6; 532 inf6.sin6_port = 0; 533 inf6.sin6_scope_id = if_scope; 534 netif = &inf6; 535 } 536 537 #if 0 538 /* 539 * Windows implementation of ICMP & RAW sockets is too unreliable for now. 540 * Therefore it's best not to try it at all and rely only on TCP 541 * We may revisit and enable this code in the future. 542 */ 543 544 /* 545 * Right now, windows doesn't generate the ICMP checksum automatically 546 * so we have to compute it, but we can do it only if we know which 547 * interface will be used. Therefore, don't try to use ICMP if no 548 * interface was specified. 549 * When ICMPv6 support improves in windows, we may change this. 550 */ 551 if (!(IS_NULL(ifArray))) { 552 /* 553 * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST 554 * otherwise we'll try a tcp socket to the Echo port (7). 555 * Note that this is empiric, and not connecting could mean it's blocked 556 * or the echo servioe has been disabled. 557 */ 558 fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 559 560 if (fd != -1) { /* Good to go, let's do a ping */ 561 return ping6(env, fd, &him6, timeout, netif, ttl); 562 } 563 } 564 #endif 565 566 /* No good, let's fall back on TCP */ 567 fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); 568 if (fd == JVM_IO_ERR) { 569 /* note: if you run out of fds, you may not be able to load 570 * the exception class, and get a NoClassDefFoundError 571 * instead. 572 */ 573 NET_ThrowNew(env, errno, "Can't create socket"); 574 return JNI_FALSE; 575 } 576 577 /** 578 * A TTL was specified, let's set the socket option. 579 */ 580 if (ttl > 0) { 581 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl)); 582 } 583 584 /** 585 * A network interface was specified, let's bind to it. 586 */ 587 if (netif != NULL) { 588 if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0) { 589 NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface"); 590 closesocket(fd); 591 return JNI_FALSE; 592 } 593 } 594 595 /** 596 * Make the socket non blocking. 597 */ 598 hEvent = WSACreateEvent(); 599 WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); 600 601 /* no need to use NET_Connect as non-blocking */ 602 him6.sin6_port = htons((short) 7); /* Echo port */ 603 connect_rv = connect(fd, (struct sockaddr *)&him6, len); 604 605 /** 606 * connection established or refused immediately, either way it means 607 * we were able to reach the host! 608 */ 609 if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) { 610 WSACloseEvent(hEvent); 611 closesocket(fd); 612 return JNI_TRUE; 613 } else { 614 int optlen; 615 616 switch (WSAGetLastError()) { 617 case WSAEHOSTUNREACH: /* Host Unreachable */ 618 case WSAENETUNREACH: /* Network Unreachable */ 619 case WSAENETDOWN: /* Network is down */ 620 case WSAEPFNOSUPPORT: /* Protocol Family unsupported */ 621 WSACloseEvent(hEvent); 622 closesocket(fd); 623 return JNI_FALSE; 624 } 625 626 if (WSAGetLastError() != WSAEWOULDBLOCK) { 627 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 628 "connect failed"); 629 WSACloseEvent(hEvent); 630 closesocket(fd); 631 return JNI_FALSE; 632 } 633 634 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 635 636 if (timeout >= 0) { 637 /* has connection been established? */ 638 optlen = sizeof(connect_rv); 639 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 640 &optlen) <0) { 641 connect_rv = WSAGetLastError(); 642 } 643 644 if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) { 645 WSACloseEvent(hEvent); 646 closesocket(fd); 647 return JNI_TRUE; 648 } 649 } 650 } 651 WSACloseEvent(hEvent); 652 closesocket(fd); 653 #endif /* AF_INET6 */ 654 return JNI_FALSE; 655 } --- EOF ---