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