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 }