1 /* 2 * Copyright (c) 1997, 2020, 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 #include <dlfcn.h> 26 #include <errno.h> 27 #include <net/if.h> 28 #include <netinet/tcp.h> // defines TCP_NODELAY 29 #include <stdlib.h> 30 #include <string.h> 31 #include <sys/ioctl.h> 32 #include <sys/time.h> 33 34 #if defined(__linux__) 35 #include <arpa/inet.h> 36 #include <net/route.h> 37 #include <sys/utsname.h> 38 #endif 39 40 #if defined(MACOSX) 41 #include <sys/sysctl.h> 42 #endif 43 44 #include "jvm.h" 45 #include "net_util.h" 46 47 #include "java_net_SocketOptions.h" 48 #include "java_net_InetAddress.h" 49 50 #if defined(__linux__) && !defined(IPV6_FLOWINFO_SEND) 51 #define IPV6_FLOWINFO_SEND 33 52 #endif 53 54 #define RESTARTABLE(_cmd, _result) do { \ 55 do { \ 56 _result = _cmd; \ 57 } while((_result == -1) && (errno == EINTR)); \ 58 } while(0) 59 60 int NET_SocketAvailable(int s, int *pbytes) { 61 int result; 62 RESTARTABLE(ioctl(s, FIONREAD, pbytes), result); 63 return result; 64 } 65 66 void 67 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, 68 const char *defaultDetail) { 69 JNU_ThrowByNameWithMessageAndLastError(env, name, defaultDetail); 70 } 71 72 void 73 NET_ThrowCurrent(JNIEnv *env, char *msg) { 74 NET_ThrowNew(env, errno, msg); 75 } 76 77 void 78 NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) { 79 char fullMsg[512]; 80 if (!msg) { 81 msg = "no further information"; 82 } 83 switch(errorNumber) { 84 case EBADF: 85 jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg); 86 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg); 87 break; 88 case EINTR: 89 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg); 90 break; 91 default: 92 errno = errorNumber; 93 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg); 94 break; 95 } 96 } 97 98 99 jfieldID 100 NET_GetFileDescriptorID(JNIEnv *env) 101 { 102 jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor"); 103 CHECK_NULL_RETURN(cls, NULL); 104 return (*env)->GetFieldID(env, cls, "fd", "I"); 105 } 106 107 jint IPv4_supported() 108 { 109 int fd = socket(AF_INET, SOCK_STREAM, 0) ; 110 if (fd < 0) { 111 return JNI_FALSE; 112 } 113 close(fd); 114 return JNI_TRUE; 115 } 116 117 #if defined(DONT_ENABLE_IPV6) 118 jint IPv6_supported() 119 { 120 return JNI_FALSE; 121 } 122 123 #else /* !DONT_ENABLE_IPV6 */ 124 125 jint IPv6_supported() 126 { 127 int fd; 128 void *ipv6_fn; 129 SOCKETADDRESS sa; 130 socklen_t sa_len = sizeof(SOCKETADDRESS); 131 132 fd = socket(AF_INET6, SOCK_STREAM, 0) ; 133 if (fd < 0) { 134 /* 135 * TODO: We really cant tell since it may be an unrelated error 136 * for now we will assume that AF_INET6 is not available 137 */ 138 return JNI_FALSE; 139 } 140 141 /* 142 * If fd 0 is a socket it means we may have been launched from inetd or 143 * xinetd. If it's a socket then check the family - if it's an 144 * IPv4 socket then we need to disable IPv6. 145 */ 146 if (getsockname(0, &sa.sa, &sa_len) == 0) { 147 if (sa.sa.sa_family == AF_INET) { 148 close(fd); 149 return JNI_FALSE; 150 } 151 } 152 153 /** 154 * Linux - check if any interface has an IPv6 address. 155 * Don't need to parse the line - we just need an indication. 156 */ 157 #ifdef __linux__ 158 { 159 FILE *fP = fopen("/proc/net/if_inet6", "r"); 160 char buf[255]; 161 char *bufP; 162 163 if (fP == NULL) { 164 close(fd); 165 return JNI_FALSE; 166 } 167 bufP = fgets(buf, sizeof(buf), fP); 168 fclose(fP); 169 if (bufP == NULL) { 170 close(fd); 171 return JNI_FALSE; 172 } 173 } 174 #endif 175 176 /* 177 * OK we may have the stack available in the kernel, 178 * we should also check if the APIs are available. 179 */ 180 ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton"); 181 close(fd); 182 if (ipv6_fn == NULL ) { 183 return JNI_FALSE; 184 } else { 185 return JNI_TRUE; 186 } 187 } 188 #endif /* DONT_ENABLE_IPV6 */ 189 190 jint reuseport_supported() 191 { 192 /* Do a simple dummy call, and try to figure out from that */ 193 int one = 1; 194 int rv, s; 195 s = socket(PF_INET, SOCK_STREAM, 0); 196 if (s < 0) { 197 return JNI_FALSE; 198 } 199 rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one)); 200 if (rv != 0) { 201 rv = JNI_FALSE; 202 } else { 203 rv = JNI_TRUE; 204 } 205 close(s); 206 return rv; 207 } 208 209 void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, 210 const char* hostname, 211 int gai_error) 212 { 213 int size; 214 char *buf; 215 const char *format = "%s: %s"; 216 const char *error_string = gai_strerror(gai_error); 217 if (error_string == NULL) 218 error_string = "unknown error"; 219 220 size = strlen(format) + strlen(hostname) + strlen(error_string) + 2; 221 buf = (char *) malloc(size); 222 if (buf) { 223 jstring s; 224 sprintf(buf, format, hostname, error_string); 225 s = JNU_NewStringPlatform(env, buf); 226 if (s != NULL) { 227 jobject x = JNU_NewObjectByName(env, 228 "java/net/UnknownHostException", 229 "(Ljava/lang/String;)V", s); 230 if (x != NULL) 231 (*env)->Throw(env, x); 232 } 233 free(buf); 234 } 235 } 236 237 #if defined(_AIX) 238 239 /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ 240 extern void aix_close_init(); 241 242 void platformInit () { 243 aix_close_init(); 244 } 245 246 #else 247 248 void platformInit () {} 249 250 #endif 251 252 JNIEXPORT jint JNICALL 253 NET_EnableFastTcpLoopback(int fd) { 254 return 0; 255 } 256 257 /** 258 * See net_util.h for documentation 259 */ 260 JNIEXPORT int JNICALL 261 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, 262 SOCKETADDRESS *sa, int *len, 263 jboolean v4MappedAddress) 264 { 265 jint family = getInetAddress_family(env, iaObj); 266 JNU_CHECK_EXCEPTION_RETURN(env, -1); 267 memset((char *)sa, 0, sizeof(SOCKETADDRESS)); 268 269 if (ipv6_available() && 270 !(family == java_net_InetAddress_IPv4 && 271 v4MappedAddress == JNI_FALSE)) 272 { 273 jbyte caddr[16]; 274 jint address; 275 276 if (family == java_net_InetAddress_IPv4) { 277 // convert to IPv4-mapped address 278 memset((char *)caddr, 0, 16); 279 address = getInetAddress_addr(env, iaObj); 280 JNU_CHECK_EXCEPTION_RETURN(env, -1); 281 if (address == INADDR_ANY) { 282 /* we would always prefer IPv6 wildcard address 283 * caddr[10] = 0xff; 284 * caddr[11] = 0xff; */ 285 } else { 286 caddr[10] = 0xff; 287 caddr[11] = 0xff; 288 caddr[12] = ((address >> 24) & 0xff); 289 caddr[13] = ((address >> 16) & 0xff); 290 caddr[14] = ((address >> 8) & 0xff); 291 caddr[15] = (address & 0xff); 292 } 293 } else { 294 getInet6Address_ipaddress(env, iaObj, (char *)caddr); 295 } 296 sa->sa6.sin6_port = htons(port); 297 memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr)); 298 sa->sa6.sin6_family = AF_INET6; 299 if (len != NULL) { 300 *len = sizeof(struct sockaddr_in6); 301 } 302 303 /* handle scope_id */ 304 if (family != java_net_InetAddress_IPv4) { 305 if (ia6_scopeidID) { 306 sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj); 307 } 308 } 309 } else { 310 jint address; 311 if (family != java_net_InetAddress_IPv4) { 312 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable"); 313 return -1; 314 } 315 address = getInetAddress_addr(env, iaObj); 316 JNU_CHECK_EXCEPTION_RETURN(env, -1); 317 sa->sa4.sin_port = htons(port); 318 sa->sa4.sin_addr.s_addr = htonl(address); 319 sa->sa4.sin_family = AF_INET; 320 if (len != NULL) { 321 *len = sizeof(struct sockaddr_in); 322 } 323 } 324 return 0; 325 } 326 327 void 328 NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) { 329 if (sa->sa.sa_family == AF_INET6) { 330 sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20); 331 } 332 } 333 334 int 335 NET_IsIPv4Mapped(jbyte* caddr) { 336 int i; 337 for (i = 0; i < 10; i++) { 338 if (caddr[i] != 0x00) { 339 return 0; /* false */ 340 } 341 } 342 343 if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) { 344 return 1; /* true */ 345 } 346 return 0; /* false */ 347 } 348 349 int 350 NET_IPv4MappedToIPv4(jbyte* caddr) { 351 return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8) 352 | (caddr[15] & 0xff); 353 } 354 355 int 356 NET_IsEqual(jbyte* caddr1, jbyte* caddr2) { 357 int i; 358 for (i = 0; i < 16; i++) { 359 if (caddr1[i] != caddr2[i]) { 360 return 0; /* false */ 361 } 362 } 363 return 1; 364 } 365 366 int NET_IsZeroAddr(jbyte* caddr) { 367 int i; 368 for (i = 0; i < 16; i++) { 369 if (caddr[i] != 0) { 370 return 0; 371 } 372 } 373 return 1; 374 } 375 376 /* 377 * Map the Java level socket option to the platform specific 378 * level and option name. 379 */ 380 int 381 NET_MapSocketOption(jint cmd, int *level, int *optname) { 382 static struct { 383 jint cmd; 384 int level; 385 int optname; 386 } const opts[] = { 387 { java_net_SocketOptions_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY }, 388 { java_net_SocketOptions_SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE }, 389 { java_net_SocketOptions_SO_LINGER, SOL_SOCKET, SO_LINGER }, 390 { java_net_SocketOptions_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF }, 391 { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF }, 392 { java_net_SocketOptions_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE }, 393 { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR }, 394 { java_net_SocketOptions_SO_REUSEPORT, SOL_SOCKET, SO_REUSEPORT }, 395 { java_net_SocketOptions_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST }, 396 { java_net_SocketOptions_IP_TOS, IPPROTO_IP, IP_TOS }, 397 { java_net_SocketOptions_IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF }, 398 { java_net_SocketOptions_IP_MULTICAST_IF2, IPPROTO_IP, IP_MULTICAST_IF }, 399 { java_net_SocketOptions_IP_MULTICAST_LOOP, IPPROTO_IP, IP_MULTICAST_LOOP }, 400 }; 401 402 int i; 403 404 if (ipv6_available()) { 405 switch (cmd) { 406 // Different multicast options if IPv6 is enabled 407 case java_net_SocketOptions_IP_MULTICAST_IF: 408 case java_net_SocketOptions_IP_MULTICAST_IF2: 409 *level = IPPROTO_IPV6; 410 *optname = IPV6_MULTICAST_IF; 411 return 0; 412 413 case java_net_SocketOptions_IP_MULTICAST_LOOP: 414 *level = IPPROTO_IPV6; 415 *optname = IPV6_MULTICAST_LOOP; 416 return 0; 417 #if defined(MACOSX) 418 // Map IP_TOS request to IPV6_TCLASS 419 case java_net_SocketOptions_IP_TOS: 420 *level = IPPROTO_IPV6; 421 *optname = IPV6_TCLASS; 422 return 0; 423 #endif 424 } 425 } 426 427 /* 428 * Map the Java level option to the native level 429 */ 430 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) { 431 if (cmd == opts[i].cmd) { 432 *level = opts[i].level; 433 *optname = opts[i].optname; 434 return 0; 435 } 436 } 437 438 /* not found */ 439 return -1; 440 } 441 442 /* 443 * Wrapper for getsockopt system routine - does any necessary 444 * pre/post processing to deal with OS specific oddities :- 445 * 446 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed 447 * to compensate for an incorrect value returned by the kernel. 448 */ 449 int 450 NET_GetSockOpt(int fd, int level, int opt, void *result, 451 int *len) 452 { 453 int rv; 454 socklen_t socklen = *len; 455 456 rv = getsockopt(fd, level, opt, result, &socklen); 457 *len = socklen; 458 459 if (rv < 0) { 460 return rv; 461 } 462 463 #ifdef __linux__ 464 /* 465 * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This 466 * stems from additional socket structures in the send 467 * and receive buffers. 468 */ 469 if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF) 470 || (opt == SO_RCVBUF))) { 471 int n = *((int *)result); 472 n /= 2; 473 *((int *)result) = n; 474 } 475 #endif 476 477 /* Workaround for Mac OS treating linger value as 478 * signed integer 479 */ 480 #ifdef MACOSX 481 if (level == SOL_SOCKET && opt == SO_LINGER) { 482 struct linger* to_cast = (struct linger*)result; 483 to_cast->l_linger = (unsigned short)to_cast->l_linger; 484 } 485 #endif 486 return rv; 487 } 488 489 /* 490 * Wrapper for setsockopt system routine - performs any 491 * necessary pre/post processing to deal with OS specific 492 * issue :- 493 * 494 * On Solaris need to limit the suggested value for SO_SNDBUF 495 * and SO_RCVBUF to the kernel configured limit 496 * 497 * For IP_TOS socket option need to mask off bits as this 498 * aren't automatically masked by the kernel and results in 499 * an error. 500 */ 501 int 502 NET_SetSockOpt(int fd, int level, int opt, const void *arg, 503 int len) 504 { 505 506 #ifndef IPTOS_TOS_MASK 507 #define IPTOS_TOS_MASK 0x1e 508 #endif 509 #ifndef IPTOS_PREC_MASK 510 #define IPTOS_PREC_MASK 0xe0 511 #endif 512 513 #if defined(_ALLBSD_SOURCE) 514 #if defined(KIPC_MAXSOCKBUF) 515 int mib[3]; 516 size_t rlen; 517 #endif 518 519 int *bufsize; 520 521 #ifdef __APPLE__ 522 static int maxsockbuf = -1; 523 #else 524 static long maxsockbuf = -1; 525 #endif 526 #endif 527 528 /* 529 * IPPROTO/IP_TOS :- 530 * 1. IPv6 on Solaris/Mac OS: 531 * Set the TOS OR Traffic Class value to cater for 532 * IPv6 and IPv4 scenarios. 533 * 2. IPv6 on Linux: By default Linux ignores flowinfo 534 * field so enable IPV6_FLOWINFO_SEND so that flowinfo 535 * will be examined. We also set the IPv4 TOS option in this case. 536 * 3. IPv4: set socket option based on ToS and Precedence 537 * fields (otherwise get invalid argument) 538 */ 539 if (level == IPPROTO_IP && opt == IP_TOS) { 540 int *iptos; 541 542 #if defined(__linux__) 543 if (ipv6_available()) { 544 int optval = 1; 545 if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, 546 (void *)&optval, sizeof(optval)) < 0) { 547 return -1; 548 } 549 /* 550 * Let's also set the IPV6_TCLASS flag. 551 * Linux appears to allow both IP_TOS and IPV6_TCLASS to be set 552 * This helps in mixed environments where IPv4 and IPv6 sockets 553 * are connecting. 554 */ 555 if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, 556 arg, len) < 0) { 557 return -1; 558 } 559 } 560 #endif 561 562 iptos = (int *)arg; 563 *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK); 564 } 565 566 #ifdef _AIX 567 if (level == SOL_SOCKET) { 568 if (opt == SO_SNDBUF || opt == SO_RCVBUF) { 569 /* 570 * Just try to set the requested size. If it fails we will leave the 571 * socket option as is. Setting the buffer size means only a hint in 572 * the jse2/java software layer, see javadoc. In the previous 573 * solution the buffer has always been truncated to a length of 574 * 0x100000 Byte, even if the technical limit has not been reached. 575 * This kind of absolute truncation was unexpected in the jck tests. 576 */ 577 int ret = setsockopt(fd, level, opt, arg, len); 578 if ((ret == 0) || (ret == -1 && errno == ENOBUFS)) { 579 // Accept failure because of insufficient buffer memory resources. 580 return 0; 581 } else { 582 // Deliver all other kinds of errors. 583 return ret; 584 } 585 } 586 } 587 #endif 588 589 /* 590 * On Linux the receive buffer is used for both socket 591 * structures and the packet payload. The implication 592 * is that if SO_RCVBUF is too small then small packets 593 * must be discarded. 594 */ 595 #ifdef __linux__ 596 if (level == SOL_SOCKET && opt == SO_RCVBUF) { 597 int *bufsize = (int *)arg; 598 if (*bufsize < 1024) { 599 *bufsize = 1024; 600 } 601 } 602 #endif 603 604 #if defined(_ALLBSD_SOURCE) 605 /* 606 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On FreeBSD need to 607 * ensure that value is <= kern.ipc.maxsockbuf as otherwise we get 608 * an ENOBUFS error. 609 */ 610 if (level == SOL_SOCKET) { 611 if (opt == SO_SNDBUF || opt == SO_RCVBUF) { 612 #ifdef KIPC_MAXSOCKBUF 613 if (maxsockbuf == -1) { 614 mib[0] = CTL_KERN; 615 mib[1] = KERN_IPC; 616 mib[2] = KIPC_MAXSOCKBUF; 617 rlen = sizeof(maxsockbuf); 618 if (sysctl(mib, 3, &maxsockbuf, &rlen, NULL, 0) == -1) 619 maxsockbuf = 1024; 620 621 #if 1 622 /* XXXBSD: This is a hack to workaround mb_max/mb_max_adj 623 problem. It should be removed when kern.ipc.maxsockbuf 624 will be real value. */ 625 maxsockbuf = (maxsockbuf/5)*4; 626 #endif 627 } 628 #elif defined(__OpenBSD__) 629 maxsockbuf = SB_MAX; 630 #else 631 maxsockbuf = 64 * 1024; /* XXX: NetBSD */ 632 #endif 633 634 bufsize = (int *)arg; 635 if (*bufsize > maxsockbuf) { 636 *bufsize = maxsockbuf; 637 } 638 639 if (opt == SO_RCVBUF && *bufsize < 1024) { 640 *bufsize = 1024; 641 } 642 643 } 644 } 645 #endif 646 647 #if defined(_ALLBSD_SOURCE) || defined(_AIX) 648 /* 649 * On Solaris, SO_REUSEADDR will allow multiple datagram 650 * sockets to bind to the same port. The network jck tests check 651 * for this "feature", so we need to emulate it by turning on 652 * SO_REUSEPORT as well for that combination. 653 */ 654 if (level == SOL_SOCKET && opt == SO_REUSEADDR) { 655 int sotype; 656 socklen_t arglen; 657 658 arglen = sizeof(sotype); 659 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen) < 0) { 660 return -1; 661 } 662 663 if (sotype == SOCK_DGRAM) { 664 setsockopt(fd, level, SO_REUSEPORT, arg, len); 665 } 666 } 667 #endif 668 669 return setsockopt(fd, level, opt, arg, len); 670 } 671 672 /* 673 * Wrapper for bind system call - performs any necessary pre/post 674 * processing to deal with OS specific issues :- 675 * 676 * Linux allows a socket to bind to 127.0.0.255 which must be 677 * caught. 678 */ 679 int 680 NET_Bind(int fd, SOCKETADDRESS *sa, int len) 681 { 682 int rv; 683 int arg, alen; 684 685 #ifdef __linux__ 686 /* 687 * ## get bugId for this issue - goes back to 1.2.2 port ## 688 * ## When IPv6 is enabled this will be an IPv4-mapped 689 * ## with family set to AF_INET6 690 */ 691 if (sa->sa.sa_family == AF_INET) { 692 if ((ntohl(sa->sa4.sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) { 693 errno = EADDRNOTAVAIL; 694 return -1; 695 } 696 } 697 #endif 698 699 rv = bind(fd, &sa->sa, len); 700 701 return rv; 702 } 703 704 /** 705 * Wrapper for poll with timeout on a single file descriptor. 706 * 707 * flags (defined in net_util_md.h can be any combination of 708 * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT. 709 * 710 * The function will return when either the socket is ready for one 711 * of the specified operations or the timeout expired. 712 * 713 * It returns the time left from the timeout (possibly 0), or -1 if it expired. 714 */ 715 716 jint 717 NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout) 718 { 719 jlong prevNanoTime = JVM_NanoTime(env, 0); 720 jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; 721 jint read_rv; 722 723 while (1) { 724 jlong newNanoTime; 725 struct pollfd pfd; 726 pfd.fd = fd; 727 pfd.events = 0; 728 if (flags & NET_WAIT_READ) 729 pfd.events |= POLLIN; 730 if (flags & NET_WAIT_WRITE) 731 pfd.events |= POLLOUT; 732 if (flags & NET_WAIT_CONNECT) 733 pfd.events |= POLLOUT; 734 735 errno = 0; 736 read_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); 737 738 newNanoTime = JVM_NanoTime(env, 0); 739 nanoTimeout -= (newNanoTime - prevNanoTime); 740 if (nanoTimeout < NET_NSEC_PER_MSEC) { 741 return read_rv > 0 ? 0 : -1; 742 } 743 prevNanoTime = newNanoTime; 744 745 if (read_rv > 0) { 746 break; 747 } 748 } /* while */ 749 return (nanoTimeout / NET_NSEC_PER_MSEC); 750 }