1 /*
   2  * Copyright (c) 1997, 2019, 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(__solaris__)
  41 #include <inet/nd.h>
  42 #include <limits.h>
  43 #include <stropts.h>
  44 #include <sys/filio.h>
  45 #include <sys/sockio.h>
  46 #endif
  47 
  48 #if defined(MACOSX)
  49 #include <sys/sysctl.h>
  50 #endif
  51 
  52 #include "jvm.h"
  53 #include "net_util.h"
  54 
  55 #include "java_net_SocketOptions.h"
  56 #include "java_net_InetAddress.h"
  57 
  58 #if defined(__linux__) && !defined(IPV6_FLOWINFO_SEND)
  59 #define IPV6_FLOWINFO_SEND      33
  60 #endif
  61 
  62 #if defined(__solaris__) && !defined(MAXINT)
  63 #define MAXINT INT_MAX
  64 #endif
  65 
  66 /*
  67  * EXCLBIND socket options only on Solaris
  68  */
  69 #if defined(__solaris__) && !defined(TCP_EXCLBIND)
  70 #define TCP_EXCLBIND            0x21
  71 #endif
  72 #if defined(__solaris__) && !defined(UDP_EXCLBIND)
  73 #define UDP_EXCLBIND            0x0101
  74 #endif
  75 
  76 #define RESTARTABLE(_cmd, _result) do { \
  77     do { \
  78         _result = _cmd; \
  79     } while((_result == -1) && (errno == EINTR)); \
  80 } while(0)
  81 
  82 int NET_SocketAvailable(int s, int *pbytes) {
  83     int result;
  84     RESTARTABLE(ioctl(s, FIONREAD, pbytes), result);
  85     return result;
  86 }
  87 
  88 #ifdef __solaris__
  89 static int init_tcp_max_buf, init_udp_max_buf;
  90 static int tcp_max_buf;
  91 static int udp_max_buf;
  92 static int useExclBind = 0;
  93 
  94 /*
  95  * Get the specified parameter from the specified driver. The value
  96  * of the parameter is assumed to be an 'int'. If the parameter
  97  * cannot be obtained return -1
  98  */
  99 int net_getParam(char *driver, char *param)
 100 {
 101     struct strioctl stri;
 102     char buf [64];
 103     int s;
 104     int value;
 105 
 106     s = open (driver, O_RDWR);
 107     if (s < 0) {
 108         return -1;
 109     }
 110     strncpy (buf, param, sizeof(buf));
 111     stri.ic_cmd = ND_GET;
 112     stri.ic_timout = 0;
 113     stri.ic_dp = buf;
 114     stri.ic_len = sizeof(buf);
 115     if (ioctl (s, I_STR, &stri) < 0) {
 116         value = -1;
 117     } else {
 118         value = atoi(buf);
 119     }
 120     close (s);
 121     return value;
 122 }
 123 
 124 /*
 125  * Iterative way to find the max value that SO_SNDBUF or SO_RCVBUF
 126  * for Solaris versions that do not support the ioctl() in net_getParam().
 127  * Ugly, but only called once (for each sotype).
 128  *
 129  * As an optimization, we make a guess using the default values for Solaris
 130  * assuming they haven't been modified with ndd.
 131  */
 132 
 133 #define MAX_TCP_GUESS 1024 * 1024
 134 #define MAX_UDP_GUESS 2 * 1024 * 1024
 135 
 136 #define FAIL_IF_NOT_ENOBUFS if (errno != ENOBUFS) return -1
 137 
 138 static int findMaxBuf(int fd, int opt, int sotype) {
 139     int a = 0;
 140     int b = MAXINT;
 141     int initial_guess;
 142     int limit = -1;
 143 
 144     if (sotype == SOCK_DGRAM) {
 145         initial_guess = MAX_UDP_GUESS;
 146     } else {
 147         initial_guess = MAX_TCP_GUESS;
 148     }
 149 
 150     if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess, sizeof(int)) == 0) {
 151         initial_guess++;
 152         if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess,sizeof(int)) < 0) {
 153             FAIL_IF_NOT_ENOBUFS;
 154             return initial_guess - 1;
 155         }
 156         a = initial_guess;
 157     } else {
 158         FAIL_IF_NOT_ENOBUFS;
 159         b = initial_guess - 1;
 160     }
 161     do {
 162         int mid = a + (b-a)/2;
 163         if (setsockopt(fd, SOL_SOCKET, opt, &mid, sizeof(int)) == 0) {
 164             limit = mid;
 165             a = mid + 1;
 166         } else {
 167             FAIL_IF_NOT_ENOBUFS;
 168             b = mid - 1;
 169         }
 170     } while (b >= a);
 171 
 172     return limit;
 173 }
 174 #endif
 175 
 176 void
 177 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
 178                    const char *defaultDetail) {
 179     JNU_ThrowByNameWithMessageAndLastError(env, name, defaultDetail);
 180 }
 181 
 182 void
 183 NET_ThrowCurrent(JNIEnv *env, char *msg) {
 184     NET_ThrowNew(env, errno, msg);
 185 }
 186 
 187 void
 188 NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) {
 189     char fullMsg[512];
 190     if (!msg) {
 191         msg = "no further information";
 192     }
 193     switch(errorNumber) {
 194     case EBADF:
 195         jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg);
 196         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
 197         break;
 198     case EINTR:
 199         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg);
 200         break;
 201     default:
 202         errno = errorNumber;
 203         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg);
 204         break;
 205     }
 206 }
 207 
 208 
 209 jfieldID
 210 NET_GetFileDescriptorID(JNIEnv *env)
 211 {
 212     jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor");
 213     CHECK_NULL_RETURN(cls, NULL);
 214     return (*env)->GetFieldID(env, cls, "fd", "I");
 215 }
 216 
 217 jint  IPv4_supported()
 218 {
 219     int fd = socket(AF_INET, SOCK_STREAM, 0) ;
 220     if (fd < 0) {
 221         return JNI_FALSE;
 222     }
 223     close(fd);
 224     return JNI_TRUE;
 225 }
 226 
 227 #if defined(DONT_ENABLE_IPV6)
 228 jint  IPv6_supported()
 229 {
 230     return JNI_FALSE;
 231 }
 232 
 233 #else /* !DONT_ENABLE_IPV6 */
 234 
 235 jint  IPv6_supported()
 236 {
 237     int fd;
 238     void *ipv6_fn;
 239     SOCKETADDRESS sa;
 240     socklen_t sa_len = sizeof(SOCKETADDRESS);
 241 
 242     fd = socket(AF_INET6, SOCK_STREAM, 0) ;
 243     if (fd < 0) {
 244         /*
 245          *  TODO: We really cant tell since it may be an unrelated error
 246          *  for now we will assume that AF_INET6 is not available
 247          */
 248         return JNI_FALSE;
 249     }
 250 
 251     /*
 252      * If fd 0 is a socket it means we may have been launched from inetd or
 253      * xinetd. If it's a socket then check the family - if it's an
 254      * IPv4 socket then we need to disable IPv6.
 255      */
 256     if (getsockname(0, &sa.sa, &sa_len) == 0) {
 257         if (sa.sa.sa_family == AF_INET) {
 258             close(fd);
 259             return JNI_FALSE;
 260         }
 261     }
 262 
 263     /**
 264      * Linux - check if any interface has an IPv6 address.
 265      * Don't need to parse the line - we just need an indication.
 266      */
 267 #ifdef __linux__
 268     {
 269         FILE *fP = fopen("/proc/net/if_inet6", "r");
 270         char buf[255];
 271         char *bufP;
 272 
 273         if (fP == NULL) {
 274             close(fd);
 275             return JNI_FALSE;
 276         }
 277         bufP = fgets(buf, sizeof(buf), fP);
 278         fclose(fP);
 279         if (bufP == NULL) {
 280             close(fd);
 281             return JNI_FALSE;
 282         }
 283     }
 284 #endif
 285 
 286     /**
 287      * On Solaris 8 it's possible to create INET6 sockets even
 288      * though IPv6 is not enabled on all interfaces. Thus we
 289      * query the number of IPv6 addresses to verify that IPv6
 290      * has been configured on at least one interface.
 291      *
 292      * On Linux it doesn't matter - if IPv6 is built-in the
 293      * kernel then IPv6 addresses will be bound automatically
 294      * to all interfaces.
 295      */
 296 #ifdef __solaris__
 297 
 298 #ifdef SIOCGLIFNUM
 299     {
 300         struct lifnum numifs;
 301 
 302         numifs.lifn_family = AF_INET6;
 303         numifs.lifn_flags = 0;
 304         if (ioctl(fd, SIOCGLIFNUM, (char *)&numifs) < 0) {
 305             /**
 306              * SIOCGLIFNUM failed - assume IPv6 not configured
 307              */
 308             close(fd);
 309             return JNI_FALSE;
 310         }
 311         /**
 312          * If no IPv6 addresses then return false. If count > 0
 313          * it's possible that all IPv6 addresses are "down" but
 314          * that's okay as they may be brought "up" while the
 315          * VM is running.
 316          */
 317         if (numifs.lifn_count == 0) {
 318             close(fd);
 319             return JNI_FALSE;
 320         }
 321     }
 322 #else
 323     /* SIOCGLIFNUM not defined in build environment ??? */
 324     close(fd);
 325     return JNI_FALSE;
 326 #endif
 327 
 328 #endif /* __solaris */
 329 
 330     /*
 331      *  OK we may have the stack available in the kernel,
 332      *  we should also check if the APIs are available.
 333      */
 334     ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
 335     close(fd);
 336     if (ipv6_fn == NULL ) {
 337         return JNI_FALSE;
 338     } else {
 339         return JNI_TRUE;
 340     }
 341 }
 342 #endif /* DONT_ENABLE_IPV6 */
 343 
 344 jint reuseport_supported()
 345 {
 346     /* Do a simple dummy call, and try to figure out from that */
 347     int one = 1;
 348     int rv, s;
 349     s = socket(PF_INET, SOCK_STREAM, 0);
 350     if (s < 0) {
 351         return JNI_FALSE;
 352     }
 353     rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one));
 354     if (rv != 0) {
 355         rv = JNI_FALSE;
 356     } else {
 357         rv = JNI_TRUE;
 358     }
 359     close(s);
 360     return rv;
 361 }
 362 
 363 void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
 364                                                const char* hostname,
 365                                                int gai_error)
 366 {
 367     int size;
 368     char *buf;
 369     const char *format = "%s: %s";
 370     const char *error_string = gai_strerror(gai_error);
 371     if (error_string == NULL)
 372         error_string = "unknown error";
 373 
 374     size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
 375     buf = (char *) malloc(size);
 376     if (buf) {
 377         jstring s;
 378         sprintf(buf, format, hostname, error_string);
 379         s = JNU_NewStringPlatform(env, buf);
 380         if (s != NULL) {
 381             jobject x = JNU_NewObjectByName(env,
 382                                             "java/net/UnknownHostException",
 383                                             "(Ljava/lang/String;)V", s);
 384             if (x != NULL)
 385                 (*env)->Throw(env, x);
 386         }
 387         free(buf);
 388     }
 389 }
 390 
 391 #if defined(_AIX)
 392 
 393 /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */
 394 extern void aix_close_init();
 395 
 396 void platformInit () {
 397     aix_close_init();
 398 }
 399 
 400 #else
 401 
 402 void platformInit () {}
 403 
 404 #endif
 405 
 406 void parseExclusiveBindProperty(JNIEnv *env) {
 407 #ifdef __solaris__
 408     jstring s, flagSet;
 409     jclass iCls;
 410     jmethodID mid;
 411 
 412     s = (*env)->NewStringUTF(env, "sun.net.useExclusiveBind");
 413     CHECK_NULL(s);
 414     iCls = (*env)->FindClass(env, "java/lang/System");
 415     CHECK_NULL(iCls);
 416     mid = (*env)->GetStaticMethodID(env, iCls, "getProperty",
 417                 "(Ljava/lang/String;)Ljava/lang/String;");
 418     CHECK_NULL(mid);
 419     flagSet = (*env)->CallStaticObjectMethod(env, iCls, mid, s);
 420     if (flagSet != NULL) {
 421         useExclBind = 1;
 422     }
 423 #endif
 424 }
 425 
 426 JNIEXPORT jint JNICALL
 427 NET_EnableFastTcpLoopback(int fd) {
 428     return 0;
 429 }
 430 
 431 /**
 432  * See net_util.h for documentation
 433  */
 434 JNIEXPORT int JNICALL
 435 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port,
 436                           SOCKETADDRESS *sa, int *len,
 437                           jboolean v4MappedAddress)
 438 {
 439     jint family = getInetAddress_family(env, iaObj);
 440     JNU_CHECK_EXCEPTION_RETURN(env, -1);
 441     memset((char *)sa, 0, sizeof(SOCKETADDRESS));
 442 
 443     if (ipv6_available() &&
 444         !(family == java_net_InetAddress_IPv4 &&
 445           v4MappedAddress == JNI_FALSE))
 446     {
 447         jbyte caddr[16];
 448         jint address;
 449 
 450         if (family == java_net_InetAddress_IPv4) {
 451             // convert to IPv4-mapped address
 452             memset((char *)caddr, 0, 16);
 453             address = getInetAddress_addr(env, iaObj);
 454             JNU_CHECK_EXCEPTION_RETURN(env, -1);
 455             if (address == INADDR_ANY) {
 456                 /* we would always prefer IPv6 wildcard address
 457                  * caddr[10] = 0xff;
 458                  * caddr[11] = 0xff; */
 459             } else {
 460                 caddr[10] = 0xff;
 461                 caddr[11] = 0xff;
 462                 caddr[12] = ((address >> 24) & 0xff);
 463                 caddr[13] = ((address >> 16) & 0xff);
 464                 caddr[14] = ((address >> 8) & 0xff);
 465                 caddr[15] = (address & 0xff);
 466             }
 467         } else {
 468             getInet6Address_ipaddress(env, iaObj, (char *)caddr);
 469         }
 470         sa->sa6.sin6_port = htons(port);
 471         memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr));
 472         sa->sa6.sin6_family = AF_INET6;
 473         if (len != NULL) {
 474             *len = sizeof(struct sockaddr_in6);
 475         }
 476 
 477         /* handle scope_id */
 478         if (family != java_net_InetAddress_IPv4) {
 479             if (ia6_scopeidID) {
 480                 sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj);
 481             }
 482         }
 483     } else {
 484         jint address;
 485         if (family != java_net_InetAddress_IPv4) {
 486             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
 487             return -1;
 488         }
 489         address = getInetAddress_addr(env, iaObj);
 490         JNU_CHECK_EXCEPTION_RETURN(env, -1);
 491         sa->sa4.sin_port = htons(port);
 492         sa->sa4.sin_addr.s_addr = htonl(address);
 493         sa->sa4.sin_family = AF_INET;
 494         if (len != NULL) {
 495             *len = sizeof(struct sockaddr_in);
 496         }
 497     }
 498     return 0;
 499 }
 500 
 501 void
 502 NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) {
 503     if (sa->sa.sa_family == AF_INET6) {
 504         sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
 505     }
 506 }
 507 
 508 int
 509 NET_IsIPv4Mapped(jbyte* caddr) {
 510     int i;
 511     for (i = 0; i < 10; i++) {
 512         if (caddr[i] != 0x00) {
 513             return 0; /* false */
 514         }
 515     }
 516 
 517     if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) {
 518         return 1; /* true */
 519     }
 520     return 0; /* false */
 521 }
 522 
 523 int
 524 NET_IPv4MappedToIPv4(jbyte* caddr) {
 525     return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8)
 526         | (caddr[15] & 0xff);
 527 }
 528 
 529 int
 530 NET_IsEqual(jbyte* caddr1, jbyte* caddr2) {
 531     int i;
 532     for (i = 0; i < 16; i++) {
 533         if (caddr1[i] != caddr2[i]) {
 534             return 0; /* false */
 535         }
 536     }
 537     return 1;
 538 }
 539 
 540 int NET_IsZeroAddr(jbyte* caddr) {
 541     int i;
 542     for (i = 0; i < 16; i++) {
 543         if (caddr[i] != 0) {
 544             return 0;
 545         }
 546     }
 547     return 1;
 548 }
 549 
 550 /*
 551  * Map the Java level socket option to the platform specific
 552  * level and option name.
 553  */
 554 int
 555 NET_MapSocketOption(jint cmd, int *level, int *optname) {
 556     static struct {
 557         jint cmd;
 558         int level;
 559         int optname;
 560     } const opts[] = {
 561         { java_net_SocketOptions_TCP_NODELAY,           IPPROTO_TCP,    TCP_NODELAY },
 562         { java_net_SocketOptions_SO_OOBINLINE,          SOL_SOCKET,     SO_OOBINLINE },
 563         { java_net_SocketOptions_SO_LINGER,             SOL_SOCKET,     SO_LINGER },
 564         { java_net_SocketOptions_SO_SNDBUF,             SOL_SOCKET,     SO_SNDBUF },
 565         { java_net_SocketOptions_SO_RCVBUF,             SOL_SOCKET,     SO_RCVBUF },
 566         { java_net_SocketOptions_SO_KEEPALIVE,          SOL_SOCKET,     SO_KEEPALIVE },
 567         { java_net_SocketOptions_SO_REUSEADDR,          SOL_SOCKET,     SO_REUSEADDR },
 568         { java_net_SocketOptions_SO_REUSEPORT,          SOL_SOCKET,     SO_REUSEPORT },
 569         { java_net_SocketOptions_SO_BROADCAST,          SOL_SOCKET,     SO_BROADCAST },
 570         { java_net_SocketOptions_IP_TOS,                IPPROTO_IP,     IP_TOS },
 571         { java_net_SocketOptions_IP_MULTICAST_IF,       IPPROTO_IP,     IP_MULTICAST_IF },
 572         { java_net_SocketOptions_IP_MULTICAST_IF2,      IPPROTO_IP,     IP_MULTICAST_IF },
 573         { java_net_SocketOptions_IP_MULTICAST_LOOP,     IPPROTO_IP,     IP_MULTICAST_LOOP },
 574     };
 575 
 576     int i;
 577 
 578     if (ipv6_available()) {
 579         switch (cmd) {
 580             // Different multicast options if IPv6 is enabled
 581             case java_net_SocketOptions_IP_MULTICAST_IF:
 582             case java_net_SocketOptions_IP_MULTICAST_IF2:
 583                 *level = IPPROTO_IPV6;
 584                 *optname = IPV6_MULTICAST_IF;
 585                 return 0;
 586 
 587             case java_net_SocketOptions_IP_MULTICAST_LOOP:
 588                 *level = IPPROTO_IPV6;
 589                 *optname = IPV6_MULTICAST_LOOP;
 590                 return 0;
 591 #if (defined(__solaris__) || defined(MACOSX))
 592             // Map IP_TOS request to IPV6_TCLASS
 593             case java_net_SocketOptions_IP_TOS:
 594                 *level = IPPROTO_IPV6;
 595                 *optname = IPV6_TCLASS;
 596                 return 0;
 597 #endif
 598         }
 599     }
 600 
 601     /*
 602      * Map the Java level option to the native level
 603      */
 604     for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
 605         if (cmd == opts[i].cmd) {
 606             *level = opts[i].level;
 607             *optname = opts[i].optname;
 608             return 0;
 609         }
 610     }
 611 
 612     /* not found */
 613     return -1;
 614 }
 615 
 616 /*
 617  * Wrapper for getsockopt system routine - does any necessary
 618  * pre/post processing to deal with OS specific oddities :-
 619  *
 620  * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
 621  * to compensate for an incorrect value returned by the kernel.
 622  */
 623 int
 624 NET_GetSockOpt(int fd, int level, int opt, void *result,
 625                int *len)
 626 {
 627     int rv;
 628     socklen_t socklen = *len;
 629 
 630     rv = getsockopt(fd, level, opt, result, &socklen);
 631     *len = socklen;
 632 
 633     if (rv < 0) {
 634         return rv;
 635     }
 636 
 637 #ifdef __linux__
 638     /*
 639      * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
 640      * stems from additional socket structures in the send
 641      * and receive buffers.
 642      */
 643     if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
 644                                   || (opt == SO_RCVBUF))) {
 645         int n = *((int *)result);
 646         n /= 2;
 647         *((int *)result) = n;
 648     }
 649 #endif
 650 
 651 /* Workaround for Mac OS treating linger value as
 652  *  signed integer
 653  */
 654 #ifdef MACOSX
 655     if (level == SOL_SOCKET && opt == SO_LINGER) {
 656         struct linger* to_cast = (struct linger*)result;
 657         to_cast->l_linger = (unsigned short)to_cast->l_linger;
 658     }
 659 #endif
 660     return rv;
 661 }
 662 
 663 /*
 664  * Wrapper for setsockopt system routine - performs any
 665  * necessary pre/post processing to deal with OS specific
 666  * issue :-
 667  *
 668  * On Solaris need to limit the suggested value for SO_SNDBUF
 669  * and SO_RCVBUF to the kernel configured limit
 670  *
 671  * For IP_TOS socket option need to mask off bits as this
 672  * aren't automatically masked by the kernel and results in
 673  * an error.
 674  */
 675 int
 676 NET_SetSockOpt(int fd, int level, int  opt, const void *arg,
 677                int len)
 678 {
 679 
 680 #ifndef IPTOS_TOS_MASK
 681 #define IPTOS_TOS_MASK 0x1e
 682 #endif
 683 #ifndef IPTOS_PREC_MASK
 684 #define IPTOS_PREC_MASK 0xe0
 685 #endif
 686 
 687 #if defined(_ALLBSD_SOURCE)
 688 #if defined(KIPC_MAXSOCKBUF)
 689     int mib[3];
 690     size_t rlen;
 691 #endif
 692 
 693     int *bufsize;
 694 
 695 #ifdef __APPLE__
 696     static int maxsockbuf = -1;
 697 #else
 698     static long maxsockbuf = -1;
 699 #endif
 700 #endif
 701 
 702     /*
 703      * IPPROTO/IP_TOS :-
 704      * 1. IPv6 on Solaris/Mac OS:
 705      *    Set the TOS OR Traffic Class value to cater for
 706      *    IPv6 and IPv4 scenarios.
 707      * 2. IPv6 on Linux: By default Linux ignores flowinfo
 708      *    field so enable IPV6_FLOWINFO_SEND so that flowinfo
 709      *    will be examined. We also set the IPv4 TOS option in this case.
 710      * 3. IPv4: set socket option based on ToS and Precedence
 711      *    fields (otherwise get invalid argument)
 712      */
 713     if (level == IPPROTO_IP && opt == IP_TOS) {
 714         int *iptos;
 715 
 716 #if defined(__linux__)
 717         if (ipv6_available()) {
 718             int optval = 1;
 719             if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
 720                            (void *)&optval, sizeof(optval)) < 0) {
 721                 return -1;
 722             }
 723            /*
 724             * Let's also set the IPV6_TCLASS flag.
 725             * Linux appears to allow both IP_TOS and IPV6_TCLASS to be set
 726             * This helps in mixed environments where IPv4 and IPv6 sockets
 727             * are connecting.
 728             */
 729            if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS,
 730                            arg, len) < 0) {
 731                 return -1;
 732             }
 733         }
 734 #endif
 735 
 736         iptos = (int *)arg;
 737         *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
 738     }
 739 
 740     /*
 741      * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
 742      * the value when it exceeds the system limit.
 743      */
 744 #ifdef __solaris__
 745     if (level == SOL_SOCKET) {
 746         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
 747             int sotype=0;
 748             socklen_t arglen;
 749             int *bufsize, maxbuf;
 750             int ret;
 751 
 752             /* Attempt with the original size */
 753             ret = setsockopt(fd, level, opt, arg, len);
 754             if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
 755                 return ret;
 756 
 757             /* Exceeded system limit so clamp and retry */
 758 
 759             arglen = sizeof(sotype);
 760             if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
 761                            &arglen) < 0) {
 762                 return -1;
 763             }
 764 
 765             /*
 766              * We try to get tcp_maxbuf (and udp_max_buf) using
 767              * an ioctl() that isn't available on all versions of Solaris.
 768              * If that fails, we use the search algorithm in findMaxBuf()
 769              */
 770             if (!init_tcp_max_buf && sotype == SOCK_STREAM) {
 771                 tcp_max_buf = net_getParam("/dev/tcp", "tcp_max_buf");
 772                 if (tcp_max_buf == -1) {
 773                     tcp_max_buf = findMaxBuf(fd, opt, SOCK_STREAM);
 774                     if (tcp_max_buf == -1) {
 775                         return -1;
 776                     }
 777                 }
 778                 init_tcp_max_buf = 1;
 779             } else if (!init_udp_max_buf && sotype == SOCK_DGRAM) {
 780                 udp_max_buf = net_getParam("/dev/udp", "udp_max_buf");
 781                 if (udp_max_buf == -1) {
 782                     udp_max_buf = findMaxBuf(fd, opt, SOCK_DGRAM);
 783                     if (udp_max_buf == -1) {
 784                         return -1;
 785                     }
 786                 }
 787                 init_udp_max_buf = 1;
 788             }
 789 
 790             maxbuf = (sotype == SOCK_STREAM) ? tcp_max_buf : udp_max_buf;
 791             bufsize = (int *)arg;
 792             if (*bufsize > maxbuf) {
 793                 *bufsize = maxbuf;
 794             }
 795         }
 796     }
 797 #endif
 798 
 799 #ifdef _AIX
 800     if (level == SOL_SOCKET) {
 801         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
 802             /*
 803              * Just try to set the requested size. If it fails we will leave the
 804              * socket option as is. Setting the buffer size means only a hint in
 805              * the jse2/java software layer, see javadoc. In the previous
 806              * solution the buffer has always been truncated to a length of
 807              * 0x100000 Byte, even if the technical limit has not been reached.
 808              * This kind of absolute truncation was unexpected in the jck tests.
 809              */
 810             int ret = setsockopt(fd, level, opt, arg, len);
 811             if ((ret == 0) || (ret == -1 && errno == ENOBUFS)) {
 812                 // Accept failure because of insufficient buffer memory resources.
 813                 return 0;
 814             } else {
 815                 // Deliver all other kinds of errors.
 816                 return ret;
 817             }
 818         }
 819     }
 820 #endif
 821 
 822     /*
 823      * On Linux the receive buffer is used for both socket
 824      * structures and the packet payload. The implication
 825      * is that if SO_RCVBUF is too small then small packets
 826      * must be discarded.
 827      */
 828 #ifdef __linux__
 829     if (level == SOL_SOCKET && opt == SO_RCVBUF) {
 830         int *bufsize = (int *)arg;
 831         if (*bufsize < 1024) {
 832             *bufsize = 1024;
 833         }
 834     }
 835 #endif
 836 
 837 #if defined(_ALLBSD_SOURCE)
 838     /*
 839      * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On FreeBSD need to
 840      * ensure that value is <= kern.ipc.maxsockbuf as otherwise we get
 841      * an ENOBUFS error.
 842      */
 843     if (level == SOL_SOCKET) {
 844         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
 845 #ifdef KIPC_MAXSOCKBUF
 846             if (maxsockbuf == -1) {
 847                mib[0] = CTL_KERN;
 848                mib[1] = KERN_IPC;
 849                mib[2] = KIPC_MAXSOCKBUF;
 850                rlen = sizeof(maxsockbuf);
 851                if (sysctl(mib, 3, &maxsockbuf, &rlen, NULL, 0) == -1)
 852                    maxsockbuf = 1024;
 853 
 854 #if 1
 855                /* XXXBSD: This is a hack to workaround mb_max/mb_max_adj
 856                   problem.  It should be removed when kern.ipc.maxsockbuf
 857                   will be real value. */
 858                maxsockbuf = (maxsockbuf/5)*4;
 859 #endif
 860            }
 861 #elif defined(__OpenBSD__)
 862            maxsockbuf = SB_MAX;
 863 #else
 864            maxsockbuf = 64 * 1024;      /* XXX: NetBSD */
 865 #endif
 866 
 867            bufsize = (int *)arg;
 868            if (*bufsize > maxsockbuf) {
 869                *bufsize = maxsockbuf;
 870            }
 871 
 872            if (opt == SO_RCVBUF && *bufsize < 1024) {
 873                 *bufsize = 1024;
 874            }
 875 
 876         }
 877     }
 878 #endif
 879 
 880 #if defined(_ALLBSD_SOURCE) || defined(_AIX)
 881     /*
 882      * On Solaris, SO_REUSEADDR will allow multiple datagram
 883      * sockets to bind to the same port. The network jck tests check
 884      * for this "feature", so we need to emulate it by turning on
 885      * SO_REUSEPORT as well for that combination.
 886      */
 887     if (level == SOL_SOCKET && opt == SO_REUSEADDR) {
 888         int sotype;
 889         socklen_t arglen;
 890 
 891         arglen = sizeof(sotype);
 892         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen) < 0) {
 893             return -1;
 894         }
 895 
 896         if (sotype == SOCK_DGRAM) {
 897             setsockopt(fd, level, SO_REUSEPORT, arg, len);
 898         }
 899     }
 900 #endif
 901 
 902     return setsockopt(fd, level, opt, arg, len);
 903 }
 904 
 905 /*
 906  * Wrapper for bind system call - performs any necessary pre/post
 907  * processing to deal with OS specific issues :-
 908  *
 909  * Linux allows a socket to bind to 127.0.0.255 which must be
 910  * caught.
 911  *
 912  * On Solaris with IPv6 enabled we must use an exclusive
 913  * bind to guarantee a unique port number across the IPv4 and
 914  * IPv6 port spaces.
 915  *
 916  */
 917 int
 918 NET_Bind(int fd, SOCKETADDRESS *sa, int len)
 919 {
 920 #if defined(__solaris__)
 921     int level = -1;
 922     int exclbind = -1;
 923 #endif
 924     int rv;
 925     int arg, alen;
 926 
 927 #ifdef __linux__
 928     /*
 929      * ## get bugId for this issue - goes back to 1.2.2 port ##
 930      * ## When IPv6 is enabled this will be an IPv4-mapped
 931      * ## with family set to AF_INET6
 932      */
 933     if (sa->sa.sa_family == AF_INET) {
 934         if ((ntohl(sa->sa4.sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
 935             errno = EADDRNOTAVAIL;
 936             return -1;
 937         }
 938     }
 939 #endif
 940 
 941 #if defined(__solaris__)
 942     /*
 943      * Solaris has separate IPv4 and IPv6 port spaces so we
 944      * use an exclusive bind when SO_REUSEADDR is not used to
 945      * give the illusion of a unified port space.
 946      * This also avoids problems with IPv6 sockets connecting
 947      * to IPv4 mapped addresses whereby the socket conversion
 948      * results in a late bind that fails because the
 949      * corresponding IPv4 port is in use.
 950      */
 951     alen = sizeof(arg);
 952 
 953     if (useExclBind ||
 954         getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg, &alen) == 0)
 955     {
 956         if (useExclBind || arg == 0) {
 957             /*
 958              * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
 959              * property is true so enable TCP_EXCLBIND or
 960              * UDP_EXCLBIND
 961              */
 962             alen = sizeof(arg);
 963             if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg, &alen) == 0)
 964             {
 965                 if (arg == SOCK_STREAM) {
 966                     level = IPPROTO_TCP;
 967                     exclbind = TCP_EXCLBIND;
 968                 } else {
 969                     level = IPPROTO_UDP;
 970                     exclbind = UDP_EXCLBIND;
 971                 }
 972             }
 973 
 974             arg = 1;
 975             setsockopt(fd, level, exclbind, (char *)&arg, sizeof(arg));
 976         }
 977     }
 978 
 979 #endif
 980 
 981     rv = bind(fd, &sa->sa, len);
 982 
 983 #if defined(__solaris__)
 984     if (rv < 0) {
 985         int en = errno;
 986         /* Restore *_EXCLBIND if the bind fails */
 987         if (exclbind != -1) {
 988             int arg = 0;
 989             setsockopt(fd, level, exclbind, (char *)&arg,
 990                        sizeof(arg));
 991         }
 992         errno = en;
 993     }
 994 #endif
 995 
 996     return rv;
 997 }
 998 
 999 /**
1000  * Wrapper for poll with timeout on a single file descriptor.
1001  *
1002  * flags (defined in net_util_md.h can be any combination of
1003  * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
1004  *
1005  * The function will return when either the socket is ready for one
1006  * of the specified operations or the timeout expired.
1007  *
1008  * It returns the time left from the timeout (possibly 0), or -1 if it expired.
1009  */
1010 
1011 jint
1012 NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout)
1013 {
1014     jlong prevNanoTime = JVM_NanoTime(env, 0);
1015     jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
1016     jint read_rv;
1017 
1018     while (1) {
1019         jlong newNanoTime;
1020         struct pollfd pfd;
1021         pfd.fd = fd;
1022         pfd.events = 0;
1023         if (flags & NET_WAIT_READ)
1024           pfd.events |= POLLIN;
1025         if (flags & NET_WAIT_WRITE)
1026           pfd.events |= POLLOUT;
1027         if (flags & NET_WAIT_CONNECT)
1028           pfd.events |= POLLOUT;
1029 
1030         errno = 0;
1031         read_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
1032 
1033         newNanoTime = JVM_NanoTime(env, 0);
1034         nanoTimeout -= (newNanoTime - prevNanoTime);
1035         if (nanoTimeout < NET_NSEC_PER_MSEC) {
1036           return read_rv > 0 ? 0 : -1;
1037         }
1038         prevNanoTime = newNanoTime;
1039 
1040         if (read_rv > 0) {
1041           break;
1042         }
1043       } /* while */
1044     return (nanoTimeout / NET_NSEC_PER_MSEC);
1045 }