Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1997, 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 <errno.h>
     27 #include <string.h>
     28 #include <sys/types.h>
     29 #include <sys/socket.h>
     30 #include <netinet/tcp.h>        /* Defines TCP_NODELAY, needed for 2.6 */
     31 #include <netinet/in.h>
     32 #include <net/if.h>
     33 #include <netdb.h>
     34 #include <stdlib.h>
     35 #include <dlfcn.h>
     36 
     37 #include <limits.h>
     38 #include <sys/param.h>
     39 #ifndef MAXINT
     40 #define MAXINT INT_MAX
     41 #endif
     42 #ifdef __BIONIC__
     43 #include <linux/ipv6_route.h>
     44 #endif
     45 
     46 #ifdef __solaris__
     47 #include <sys/sockio.h>
     48 #include <stropts.h>
     49 #include <inet/nd.h>
     50 #endif
     51 
     52 #ifdef __linux__
     53 #include <arpa/inet.h>
     54 #include <net/route.h>
     55 #include <sys/utsname.h>
     56 
     57 #ifndef IPV6_FLOWINFO_SEND
     58 #define IPV6_FLOWINFO_SEND      33
     59 #endif
     60 
     61 #endif
     62 
     63 #include "jni_util.h"
     64 #include "jvm.h"
     65 #include "net_util.h"
     66 
     67 #include "java_net_SocketOptions.h"
     68 
     69 /* needed from libsocket on Solaris 8 */
     70 
     71 getaddrinfo_f getaddrinfo_ptr = NULL;
     72 freeaddrinfo_f freeaddrinfo_ptr = NULL;
     73 gai_strerror_f gai_strerror_ptr = NULL;
     74 getnameinfo_f getnameinfo_ptr = NULL;
     75 
     76 /*
     77  * EXCLBIND socket options only on Solaris
     78  */
     79 #if defined(__solaris__) && !defined(TCP_EXCLBIND)
     80 #define TCP_EXCLBIND            0x21
     81 #endif
     82 #if defined(__solaris__) && !defined(UDP_EXCLBIND)
     83 #define UDP_EXCLBIND            0x0101
     84 #endif
     85 
     86 void setDefaultScopeID(JNIEnv *env, struct sockaddr *him)
     87 {
     88 #ifdef MACOSX
     89     static jclass ni_class = NULL;
     90     static jfieldID ni_defaultIndexID;
     91     if (ni_class == NULL) {
     92         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
     93         CHECK_NULL(c);
     94         c = (*env)->NewGlobalRef(env, c);
     95         CHECK_NULL(c);
     96         ni_defaultIndexID = (*env)->GetStaticFieldID(
     97             env, c, "defaultIndex", "I");
     98         ni_class = c;
     99     }
    100     int defaultIndex;
    101     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)him;
    102     if (sin6->sin6_family == AF_INET6 && (sin6->sin6_scope_id == 0)) {
    103         defaultIndex = (*env)->GetStaticIntField(env, ni_class,
    104                                                  ni_defaultIndexID);
    105         sin6->sin6_scope_id = defaultIndex;
    106     }
    107 #endif
    108 }
    109 
    110 int getDefaultScopeID(JNIEnv *env) {
    111     static jclass ni_class = NULL;
    112     static jfieldID ni_defaultIndexID;
    113     if (ni_class == NULL) {
    114         jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
    115         if (c == NULL) return 0;
    116         c = (*env)->NewGlobalRef(env, c);
    117         if (c == NULL) return 0;
    118         ni_defaultIndexID = (*env)->GetStaticFieldID(
    119             env, c, "defaultIndex", "I");
    120         ni_class = c;
    121     }
    122     int defaultIndex = 0;
    123     defaultIndex = (*env)->GetStaticIntField(env, ni_class,
    124                                                  ni_defaultIndexID);
    125     return defaultIndex;
    126 }
    127 
    128 #ifdef __solaris__
    129 static int init_tcp_max_buf, init_udp_max_buf;
    130 static int tcp_max_buf;
    131 static int udp_max_buf;
    132 static int useExclBind = 0;
    133 
    134 /*
    135  * Get the specified parameter from the specified driver. The value
    136  * of the parameter is assumed to be an 'int'. If the parameter
    137  * cannot be obtained return -1
    138  */
    139 static int
    140 getParam(char *driver, char *param)
    141 {
    142     struct strioctl stri;
    143     char buf [64];
    144     int s;
    145     int value;
    146 
    147     s = open (driver, O_RDWR);
    148     if (s < 0) {
    149         return -1;
    150     }
    151     strncpy (buf, param, sizeof(buf));
    152     stri.ic_cmd = ND_GET;
    153     stri.ic_timout = 0;
    154     stri.ic_dp = buf;
    155     stri.ic_len = sizeof(buf);
    156     if (ioctl (s, I_STR, &stri) < 0) {
    157         value = -1;
    158     } else {
    159         value = atoi(buf);
    160     }
    161     close (s);
    162     return value;
    163 }
    164 
    165 /*
    166  * Iterative way to find the max value that SO_SNDBUF or SO_RCVBUF
    167  * for Solaris versions that do not support the ioctl() in getParam().
    168  * Ugly, but only called once (for each sotype).
    169  *
    170  * As an optimization, we make a guess using the default values for Solaris
    171  * assuming they haven't been modified with ndd.
    172  */
    173 
    174 #define MAX_TCP_GUESS 1024 * 1024
    175 #define MAX_UDP_GUESS 2 * 1024 * 1024
    176 
    177 #define FAIL_IF_NOT_ENOBUFS if (errno != ENOBUFS) return -1
    178 
    179 static int findMaxBuf(int fd, int opt, int sotype) {
    180     int a = 0;
    181     int b = MAXINT;
    182     int initial_guess;
    183     int limit = -1;
    184 
    185     if (sotype == SOCK_DGRAM) {
    186         initial_guess = MAX_UDP_GUESS;
    187     } else {
    188         initial_guess = MAX_TCP_GUESS;
    189     }
    190 
    191     if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess, sizeof(int)) == 0) {
    192         initial_guess++;
    193         if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess,sizeof(int)) < 0) {
    194             FAIL_IF_NOT_ENOBUFS;
    195             return initial_guess - 1;
    196         }
    197         a = initial_guess;
    198     } else {
    199         FAIL_IF_NOT_ENOBUFS;
    200         b = initial_guess - 1;
    201     }
    202     do {
    203         int mid = a + (b-a)/2;
    204         if (setsockopt(fd, SOL_SOCKET, opt, &mid, sizeof(int)) == 0) {
    205             limit = mid;
    206             a = mid + 1;
    207         } else {
    208             FAIL_IF_NOT_ENOBUFS;
    209             b = mid - 1;
    210         }
    211     } while (b >= a);
    212 
    213     return limit;
    214 }
    215 #endif
    216 
    217 #ifdef __linux__
    218 static int vinit = 0;
    219 
    220 static int kernelV24 = 0;
    221 static int vinit24 = 0;
    222 
    223 int kernelIsV24 () {
    224     if (!vinit24) {
    225         struct utsname sysinfo;
    226         if (uname(&sysinfo) == 0) {
    227             sysinfo.release[3] = '\0';
    228             if (strcmp(sysinfo.release, "2.4") == 0) {
    229                 kernelV24 = JNI_TRUE;
    230             }
    231         }
    232         vinit24 = 1;
    233     }
    234     return kernelV24;
    235 }
    236 
    237 int getScopeID (struct sockaddr *him) {
    238     struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
    239     return hext->sin6_scope_id;
    240 }
    241 
    242 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
    243     struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
    244     return hext->sin6_scope_id == scope;
    245 }
    246 
    247 #else
    248 
    249 int getScopeID (struct sockaddr *him) {
    250     struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    251     return him6->sin6_scope_id;
    252 }
    253 
    254 int cmpScopeID (unsigned int scope, struct sockaddr *him) {
    255     struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    256     return him6->sin6_scope_id == scope;
    257 }
    258 
    259 #endif
    260 
    261 
    262 void
    263 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
    264                    const char *defaultDetail) {
    265     char errmsg[255];
    266     snprintf(errmsg, sizeof(errmsg), "errno: %d, error: %s\n", errno,
    267              defaultDetail);
    268     JNU_ThrowByNameWithLastError(env, name, errmsg);
    269 }
    270 
    271 void
    272 NET_ThrowCurrent(JNIEnv *env, char *msg) {
    273     NET_ThrowNew(env, errno, msg);
    274 }
    275 
    276 void
    277 NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) {
    278     char fullMsg[512];
    279     if (!msg) {
    280         msg = "no further information";
    281     }
    282     switch(errorNumber) {
    283     case EBADF:
    284         jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg);
    285         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
    286         break;
    287     case EINTR:
    288         JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", msg);
    289         break;
    290     default:
    291         errno = errorNumber;
    292         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", msg);
    293         break;
    294     }
    295 }
    296 
    297 
    298 jfieldID
    299 NET_GetFileDescriptorID(JNIEnv *env)
    300 {
    301     jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor");
    302     CHECK_NULL_RETURN(cls, NULL);
    303     return (*env)->GetFieldID(env, cls, "descriptor", "I");
    304 }
    305 
    306 #if defined(DONT_ENABLE_IPV6)
    307 jint  IPv6_supported()
    308 {
    309     return JNI_FALSE;
    310 }
    311 
    312 #else /* !DONT_ENABLE_IPV6 */
    313 
    314 jint  IPv6_supported()
    315 {
    316 #ifndef AF_INET6
    317     return JNI_FALSE;
    318 #endif
    319 
    320 #ifdef AF_INET6
    321     int fd;
    322     void *ipv6_fn;
    323     SOCKADDR sa;
    324     socklen_t sa_len = sizeof(sa);
    325 
    326     // This one below is problematic, will fail without proper permissions
    327     // and report no ipv6 for some and ipv6 for others.
    328     //fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ;
    329     //if (fd < 0) {
    330         /*
    331          *  TODO: We really cant tell since it may be an unrelated error
    332          *  for now we will assume that AF_INET6 is not available
    333          */
    334     //    return JNI_FALSE;
    335     //}
    336 
    337     /*
    338      * If fd 0 is a socket it means we've been launched from inetd or
    339      * xinetd. If it's a socket then check the family - if it's an
    340      * IPv4 socket then we need to disable IPv6.
    341      */
    342     /*if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
    343         struct sockaddr *saP = (struct sockaddr *)&sa;
    344         if (saP->sa_family != AF_INET6) {
    345             return JNI_FALSE;
    346         }
    347       }*/
    348 
    349     /**
    350      * Linux - check if any interface has an IPv6 address.
    351      * Don't need to parse the line - we just need an indication.
    352      */
    353 #ifdef __linux__
    354     /*    {
    355         FILE *fP = fopen("/proc/net/if_inet6", "r");
    356         char buf[255];
    357         char *bufP;
    358 
    359         if (fP == NULL) {
    360             close(fd);
    361             return JNI_FALSE;
    362         }
    363         bufP = fgets(buf, sizeof(buf), fP);
    364         fclose(fP);
    365         if (bufP == NULL) {
    366             close(fd);
    367             return JNI_FALSE;
    368         }
    369         }*/
    370 #endif
    371 
    372     /**
    373      * On Solaris 8 it's possible to create INET6 sockets even
    374      * though IPv6 is not enabled on all interfaces. Thus we
    375      * query the number of IPv6 addresses to verify that IPv6
    376      * has been configured on at least one interface.
    377      *
    378      * On Linux it doesn't matter - if IPv6 is built-in the
    379      * kernel then IPv6 addresses will be bound automatically
    380      * to all interfaces.
    381      */
    382 #ifdef __solaris__
    383 
    384 #ifdef SIOCGLIFNUM
    385     {
    386         struct lifnum numifs;
    387 
    388         numifs.lifn_family = AF_INET6;
    389         numifs.lifn_flags = 0;
    390         if (ioctl(fd, SIOCGLIFNUM, (char *)&numifs) < 0) {
    391             /**
    392              * SIOCGLIFNUM failed - assume IPv6 not configured
    393              */
    394             untagSocket(env, fd);
    395             close(fd);
    396             return JNI_FALSE;
    397         }
    398         /**
    399          * If no IPv6 addresses then return false. If count > 0
    400          * it's possible that all IPv6 addresses are "down" but
    401          * that's okay as they may be brought "up" while the
    402          * VM is running.
    403          */
    404         if (numifs.lifn_count == 0) {
    405             close(fd);
    406             return JNI_FALSE;
    407         }
    408     }
    409 #else
    410     /* SIOCGLIFNUM not defined in build environment ??? */
    411     close(fd);
    412     return JNI_FALSE;
    413 #endif
    414 
    415 #endif /* __solaris */
    416 
    417     /*
    418      *  OK we may have the stack available in the kernel,
    419      *  we should also check if the APIs are available.
    420      */
    421 
    422     ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
    423     if (ipv6_fn == NULL ) {
    424         // close(fd);
    425         return JNI_FALSE;
    426     }
    427 
    428     /*
    429      * We've got the library, let's get the pointers to some
    430      * IPV6 specific functions. We have to do that because, at least
    431      * on Solaris we may build on a system without IPV6 networking
    432      * libraries, therefore we can't have a hard link to these
    433      * functions.
    434      */
    435     getaddrinfo_ptr = (getaddrinfo_f)
    436         JVM_FindLibraryEntry(RTLD_DEFAULT, "getaddrinfo");
    437 
    438     freeaddrinfo_ptr = (freeaddrinfo_f)
    439         JVM_FindLibraryEntry(RTLD_DEFAULT, "freeaddrinfo");
    440 
    441     gai_strerror_ptr = (gai_strerror_f)
    442         JVM_FindLibraryEntry(RTLD_DEFAULT, "gai_strerror");
    443 
    444     getnameinfo_ptr = (getnameinfo_f)
    445         JVM_FindLibraryEntry(RTLD_DEFAULT, "getnameinfo");
    446 
    447     if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) {
    448         /* We need all 3 of them */
    449         getaddrinfo_ptr = NULL;
    450     }
    451 
    452     //close(fd);
    453     return JNI_TRUE;
    454 #endif /* AF_INET6 */
    455 }
    456 #endif /* DONT_ENABLE_IPV6 */
    457 
    458 void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
    459                                            const char* hostname,
    460                                            int gai_error)
    461 {
    462     int size;
    463     char *buf;
    464     const char *format = "%s: %s";
    465     const char *error_string =
    466         (gai_strerror_ptr == NULL) ? NULL : (*gai_strerror_ptr)(gai_error);
    467     if (error_string == NULL)
    468         error_string = "unknown error";
    469 
    470     size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
    471     buf = (char *) malloc(size);
    472     if (buf) {
    473         jstring s;
    474         snprintf(buf, size, format, hostname, error_string);
    475         s = JNU_NewStringPlatform(env, buf);
    476         if (s != NULL) {
    477             jobject x = JNU_NewObjectByName(env,
    478                                             "java/net/UnknownHostException",
    479                                             "(Ljava/lang/String;)V", s);
    480             if (x != NULL)
    481                 (*env)->Throw(env, x);
    482         }
    483         free(buf);
    484     }
    485 }
    486 
    487 void
    488 NET_AllocSockaddr(struct sockaddr **him, int *len) {
    489 #ifdef AF_INET6
    490     if (ipv6_available()) {
    491         struct sockaddr_in6 *him6 = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6));
    492         *him = (struct sockaddr*)him6;
    493         *len = sizeof(struct sockaddr_in6);
    494     } else
    495 #endif /* AF_INET6 */
    496         {
    497             struct sockaddr_in *him4 = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
    498             *him = (struct sockaddr*)him4;
    499             *len = sizeof(struct sockaddr_in);
    500         }
    501 }
    502 
    503 #if 0
    504 // Android-changed: Stripped out unused code. http://b/33250070
    505 // #if defined(__linux__) && defined(AF_INET6)
    506 
    507 
    508 /* following code creates a list of addresses from the kernel
    509  * routing table that are routed via the loopback address.
    510  * We check all destination addresses against this table
    511  * and override the scope_id field to use the relevant value for "lo"
    512  * in order to work-around the Linux bug that prevents packets destined
    513  * for certain local addresses from being sent via a physical interface.
    514  */
    515 
    516 struct loopback_route {
    517     struct in6_addr addr; /* destination address */
    518     int plen; /* prefix length */
    519 };
    520 
    521 static struct loopback_route *loRoutes = 0;
    522 static int nRoutes = 0; /* number of routes */
    523 static int loRoutes_size = 16; /* initial size */
    524 static int lo_scope_id = 0;
    525 
    526 static void initLoopbackRoutes();
    527 
    528 void printAddr (struct in6_addr *addr) {
    529     int i;
    530     for (i=0; i<16; i++) {
    531         printf ("%02x", addr->s6_addr[i]);
    532     }
    533     printf ("\n");
    534 }
    535 
    536 static void initLoopbackRoutes() {
    537     FILE *f;
    538     char srcp[8][5];
    539     char hopp[8][5];
    540     int dest_plen, src_plen, use, refcnt, metric;
    541     unsigned long flags;
    542     char dest_str[40];
    543     struct in6_addr dest_addr;
    544     char device[16];
    545 
    546     if (loRoutes != 0) {
    547         free (loRoutes);
    548     }
    549     loRoutes = calloc (loRoutes_size, sizeof(struct loopback_route));
    550     if (loRoutes == 0) {
    551         return;
    552     }
    553     /*
    554      * Scan /proc/net/ipv6_route looking for a matching
    555      * route.
    556      */
    557     if ((f = fopen("/proc/net/ipv6_route", "r")) == NULL) {
    558         return ;
    559     }
    560     while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
    561                      "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
    562                      "%4s%4s%4s%4s%4s%4s%4s%4s "
    563                      "%08x %08x %08x %08lx %8s",
    564                      dest_str, &dest_str[5], &dest_str[10], &dest_str[15],
    565                      &dest_str[20], &dest_str[25], &dest_str[30], &dest_str[35],
    566                      &dest_plen,
    567                      srcp[0], srcp[1], srcp[2], srcp[3],
    568                      srcp[4], srcp[5], srcp[6], srcp[7],
    569                      &src_plen,
    570                      hopp[0], hopp[1], hopp[2], hopp[3],
    571                      hopp[4], hopp[5], hopp[6], hopp[7],
    572                      &metric, &use, &refcnt, &flags, device) == 31) {
    573 
    574         /*
    575          * Some routes should be ignored
    576          */
    577         if ( (dest_plen < 0 || dest_plen > 128)  ||
    578              (src_plen != 0) ||
    579              (flags & (RTF_POLICY | RTF_FLOW)) ||
    580              ((flags & RTF_REJECT) && dest_plen == 0) ) {
    581             continue;
    582         }
    583 
    584         /*
    585          * Convert the destination address
    586          */
    587         dest_str[4] = ':';
    588         dest_str[9] = ':';
    589         dest_str[14] = ':';
    590         dest_str[19] = ':';
    591         dest_str[24] = ':';
    592         dest_str[29] = ':';
    593         dest_str[34] = ':';
    594         dest_str[39] = '\0';
    595 
    596         if (inet_pton(AF_INET6, dest_str, &dest_addr) < 0) {
    597             /* not an Ipv6 address */
    598             continue;
    599         }
    600         if (strcmp(device, "lo") != 0) {
    601             /* Not a loopback route */
    602             continue;
    603         } else {
    604             if (nRoutes == loRoutes_size) {
    605                 loRoutes = realloc (loRoutes, loRoutes_size *
    606                                 sizeof (struct loopback_route) * 2);
    607                 if (loRoutes == 0) {
    608                     return ;
    609                 }
    610                 loRoutes_size *= 2;
    611             }
    612             memcpy (&loRoutes[nRoutes].addr,&dest_addr,sizeof(struct in6_addr));
    613             loRoutes[nRoutes].plen = dest_plen;
    614             nRoutes ++;
    615         }
    616     }
    617 
    618     fclose (f);
    619     {
    620         /* now find the scope_id for "lo" */
    621 
    622         char devname[21];
    623         char addr6p[8][5];
    624         int plen, scope, dad_status, if_idx;
    625 
    626         if ((f = fopen("/proc/net/if_inet6", "r")) != NULL) {
    627             while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
    628                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
    629                       addr6p[4], addr6p[5], addr6p[6], addr6p[7],
    630                   &if_idx, &plen, &scope, &dad_status, devname) == 13) {
    631 
    632                 if (strcmp(devname, "lo") == 0) {
    633                     /*
    634                      * Found - so just return the index
    635                      */
    636                     fclose(f);
    637                     lo_scope_id = if_idx;
    638                     return;
    639                 }
    640             }
    641             fclose(f);
    642         }
    643     }
    644 }
    645 
    646 /*
    647  * Following is used for binding to local addresses. Equivalent
    648  * to code above, for bind().
    649  */
    650 
    651 struct localinterface {
    652     int index;
    653     char localaddr [16];
    654 };
    655 
    656 static struct localinterface *localifs = 0;
    657 static int localifsSize = 0;    /* size of array */
    658 static int nifs = 0;            /* number of entries used in array */
    659 
    660 /* not thread safe: make sure called once from one thread */
    661 
    662 static void initLocalIfs () {
    663     FILE *f;
    664     unsigned char staddr [16];
    665     char ifname [33];
    666     struct localinterface *lif=0;
    667     int index, x1, x2, x3;
    668     unsigned int u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,ua,ub,uc,ud,ue,uf;
    669 
    670     if ((f = fopen("/proc/net/if_inet6", "r")) == NULL) {
    671         return ;
    672     }
    673     while (fscanf (f, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x "
    674                 "%d %x %x %x %32s",&u0,&u1,&u2,&u3,&u4,&u5,&u6,&u7,
    675                 &u8,&u9,&ua,&ub,&uc,&ud,&ue,&uf,
    676                 &index, &x1, &x2, &x3, ifname) == 21) {
    677         staddr[0] = (unsigned char)u0;
    678         staddr[1] = (unsigned char)u1;
    679         staddr[2] = (unsigned char)u2;
    680         staddr[3] = (unsigned char)u3;
    681         staddr[4] = (unsigned char)u4;
    682         staddr[5] = (unsigned char)u5;
    683         staddr[6] = (unsigned char)u6;
    684         staddr[7] = (unsigned char)u7;
    685         staddr[8] = (unsigned char)u8;
    686         staddr[9] = (unsigned char)u9;
    687         staddr[10] = (unsigned char)ua;
    688         staddr[11] = (unsigned char)ub;
    689         staddr[12] = (unsigned char)uc;
    690         staddr[13] = (unsigned char)ud;
    691         staddr[14] = (unsigned char)ue;
    692         staddr[15] = (unsigned char)uf;
    693         nifs ++;
    694         if (nifs > localifsSize) {
    695             localifs = (struct localinterface *) realloc (
    696                         localifs, sizeof (struct localinterface)* (localifsSize+5));
    697             if (localifs == 0) {
    698                 nifs = 0;
    699                 fclose (f);
    700                 return;
    701             }
    702             lif = localifs + localifsSize;
    703             localifsSize += 5;
    704         } else {
    705             lif ++;
    706         }
    707         memcpy (lif->localaddr, staddr, 16);
    708         lif->index = index;
    709     }
    710     fclose (f);
    711 }
    712 
    713 void initLocalAddrTable () {
    714     initLoopbackRoutes();
    715     initLocalIfs();
    716 }
    717 
    718 #else
    719 
    720 void initLocalAddrTable () {}
    721 
    722 #endif
    723 
    724 void parseExclusiveBindProperty(JNIEnv *env) {
    725 #ifdef __solaris__
    726     jstring s, flagSet;
    727     jclass iCls;
    728     jmethodID mid;
    729 
    730     s = (*env)->NewStringUTF(env, "sun.net.useExclusiveBind");
    731     CHECK_NULL(s);
    732     iCls = (*env)->FindClass(env, "java/lang/System");
    733     CHECK_NULL(iCls);
    734     mid = (*env)->GetStaticMethodID(env, iCls, "getProperty",
    735                 "(Ljava/lang/String;)Ljava/lang/String;");
    736     CHECK_NULL(mid);
    737     flagSet = (*env)->CallStaticObjectMethod(env, iCls, mid, s);
    738     if (flagSet != NULL) {
    739         useExclBind = 1;
    740     }
    741 #endif
    742 }
    743 /* In the case of an IPv4 Inetaddress this method will return an
    744  * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE.
    745  * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress.
    746 */
    747 JNIEXPORT int JNICALL
    748 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him,
    749                           int *len, jboolean v4MappedAddress) {
    750     jint family;
    751     family = getInetAddress_family(env, iaObj);
    752 #ifdef AF_INET6
    753     /* needs work. 1. family 2. clean up him6 etc deallocate memory */
    754     if (ipv6_available() && !(family == IPv4 && v4MappedAddress == JNI_FALSE)) {
    755         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    756         jbyteArray ipaddress;
    757         jbyte caddr[16];
    758         jint address;
    759 
    760 
    761         if (family == IPv4) { /* will convert to IPv4-mapped address */
    762             memset((char *) caddr, 0, 16);
    763             address = getInetAddress_addr(env, iaObj);
    764             if (address == INADDR_ANY) {
    765                 /* we would always prefer IPv6 wildcard address
    766                    caddr[10] = 0xff;
    767                    caddr[11] = 0xff; */
    768             } else {
    769                 caddr[10] = 0xff;
    770                 caddr[11] = 0xff;
    771                 caddr[12] = ((address >> 24) & 0xff);
    772                 caddr[13] = ((address >> 16) & 0xff);
    773                 caddr[14] = ((address >> 8) & 0xff);
    774                 caddr[15] = (address & 0xff);
    775             }
    776         } else {
    777             getInet6Address_ipaddress(env, iaObj, (char *)caddr);
    778         }
    779         memset((char *)him6, 0, sizeof(struct sockaddr_in6));
    780         him6->sin6_port = htons(port);
    781         memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );
    782         him6->sin6_family = AF_INET6;
    783         *len = sizeof(struct sockaddr_in6) ;
    784 
    785 #if defined(_ALLBSD_SOURCE) && defined(_AF_INET6)
    786 // XXXBSD: should we do something with scope id here ? see below linux comment
    787 /* MMM: Come back to this! */
    788 #endif
    789 
    790         // Android-changed: Don't try and figure out scope_ids for link local
    791         // addresses. Use them only if they're set in java (say, if the Inet6Address
    792         // was constructed with a specific scope_id or NetworkInterface).
    793         if (family != IPv4) {
    794             if (ia6_scopeidID) {
    795                 int scope_id = getInet6Address_scopeid(env, iaObj);
    796                 if (scope_id > 0) {
    797                     him6->sin6_scope_id = scope_id;
    798                 }
    799             }
    800         }
    801     } else
    802 #endif /* AF_INET6 */
    803         {
    804             struct sockaddr_in *him4 = (struct sockaddr_in*)him;
    805             jint address;
    806             if (family == IPv6) {
    807               JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
    808               return -1;
    809             }
    810             memset((char *) him4, 0, sizeof(struct sockaddr_in));
    811             address = getInetAddress_addr(env, iaObj);
    812             him4->sin_port = htons((short) port);
    813             him4->sin_addr.s_addr = (uint32_t) htonl(address);
    814             him4->sin_family = AF_INET;
    815             *len = sizeof(struct sockaddr_in);
    816         }
    817     return 0;
    818 }
    819 
    820 void
    821 NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
    822 #ifdef AF_INET6
    823     if (him->sa_family == AF_INET6) {
    824         struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
    825         him6->sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
    826     }
    827 #endif /* AF_INET6 */
    828 }
    829 
    830 JNIEXPORT jint JNICALL
    831 NET_GetPortFromSockaddr(struct sockaddr *him) {
    832 #ifdef AF_INET6
    833     if (him->sa_family == AF_INET6) {
    834         return ntohs(((struct sockaddr_in6*)him)->sin6_port);
    835 
    836         } else
    837 #endif /* AF_INET6 */
    838             {
    839                 return ntohs(((struct sockaddr_in*)him)->sin_port);
    840             }
    841 }
    842 
    843 int
    844 NET_IsIPv4Mapped(jbyte* caddr) {
    845     int i;
    846     for (i = 0; i < 10; i++) {
    847         if (caddr[i] != 0x00) {
    848             return 0; /* false */
    849         }
    850     }
    851 
    852     if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) {
    853         return 1; /* true */
    854     }
    855     return 0; /* false */
    856 }
    857 
    858 int
    859 NET_IPv4MappedToIPv4(jbyte* caddr) {
    860     return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8)
    861         | (caddr[15] & 0xff);
    862 }
    863 
    864 int
    865 NET_IsEqual(jbyte* caddr1, jbyte* caddr2) {
    866     int i;
    867     for (i = 0; i < 16; i++) {
    868         if (caddr1[i] != caddr2[i]) {
    869             return 0; /* false */
    870         }
    871     }
    872     return 1;
    873 }
    874 
    875 jboolean NET_addrtransAvailable() {
    876     return (jboolean)(getaddrinfo_ptr != NULL);
    877 }
    878 
    879 int NET_IsZeroAddr(jbyte* caddr) {
    880     int i;
    881     for (i = 0; i < 16; i++) {
    882         if (caddr[i] != 0) {
    883             return 0;
    884         }
    885     }
    886     return 1;
    887 }
    888 
    889 /*
    890  * Map the Java level socket option to the platform specific
    891  * level and option name.
    892  */
    893 int
    894 NET_MapSocketOption(jint cmd, int *level, int *optname) {
    895     static struct {
    896         jint cmd;
    897         int level;
    898         int optname;
    899     } const opts[] = {
    900         { java_net_SocketOptions_TCP_NODELAY,           IPPROTO_TCP,    TCP_NODELAY },
    901         { java_net_SocketOptions_SO_OOBINLINE,          SOL_SOCKET,     SO_OOBINLINE },
    902         { java_net_SocketOptions_SO_LINGER,             SOL_SOCKET,     SO_LINGER },
    903         { java_net_SocketOptions_SO_SNDBUF,             SOL_SOCKET,     SO_SNDBUF },
    904         { java_net_SocketOptions_SO_RCVBUF,             SOL_SOCKET,     SO_RCVBUF },
    905         { java_net_SocketOptions_SO_KEEPALIVE,          SOL_SOCKET,     SO_KEEPALIVE },
    906         { java_net_SocketOptions_SO_REUSEADDR,          SOL_SOCKET,     SO_REUSEADDR },
    907         { java_net_SocketOptions_SO_BROADCAST,          SOL_SOCKET,     SO_BROADCAST },
    908         { java_net_SocketOptions_IP_TOS,                IPPROTO_IP,     IP_TOS },
    909         { java_net_SocketOptions_IP_MULTICAST_IF,       IPPROTO_IP,     IP_MULTICAST_IF },
    910         { java_net_SocketOptions_IP_MULTICAST_IF2,      IPPROTO_IP,     IP_MULTICAST_IF },
    911         { java_net_SocketOptions_IP_MULTICAST_LOOP,     IPPROTO_IP,     IP_MULTICAST_LOOP },
    912     };
    913 
    914     int i;
    915 
    916 #ifdef AF_INET6
    917     if (ipv6_available()) {
    918         switch (cmd) {
    919             // Different multicast options if IPv6 is enabled
    920             case java_net_SocketOptions_IP_MULTICAST_IF:
    921             case java_net_SocketOptions_IP_MULTICAST_IF2:
    922                 *level = IPPROTO_IPV6;
    923                 *optname = IPV6_MULTICAST_IF;
    924                 return 0;
    925 
    926             case java_net_SocketOptions_IP_MULTICAST_LOOP:
    927                 *level = IPPROTO_IPV6;
    928                 *optname = IPV6_MULTICAST_LOOP;
    929                 return 0;
    930 #if (defined(__solaris__) || defined(MACOSX))
    931             // Map IP_TOS request to IPV6_TCLASS
    932             case java_net_SocketOptions_IP_TOS:
    933                 *level = IPPROTO_IPV6;
    934                 *optname = IPV6_TCLASS;
    935                 return 0;
    936 #endif
    937         }
    938     }
    939 #endif
    940 
    941     /*
    942      * Map the Java level option to the native level
    943      */
    944     for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
    945         if (cmd == opts[i].cmd) {
    946             *level = opts[i].level;
    947             *optname = opts[i].optname;
    948             return 0;
    949         }
    950     }
    951 
    952     /* not found */
    953     return -1;
    954 }
    955 
    956 /*
    957  * Wrapper for getsockopt system routine - does any necessary
    958  * pre/post processing to deal with OS specific oddities :-
    959  *
    960  * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
    961  * to compensate for an incorrect value returned by the kernel.
    962  */
    963 int
    964 NET_GetSockOpt(int fd, int level, int opt, void *result,
    965                int *len)
    966 {
    967     int rv;
    968 
    969 #ifdef __solaris__
    970     rv = getsockopt(fd, level, opt, result, len);
    971 #else
    972     {
    973         socklen_t socklen = *len;
    974         rv = getsockopt(fd, level, opt, result, &socklen);
    975         *len = socklen;
    976     }
    977 #endif
    978 
    979     if (rv < 0) {
    980         return rv;
    981     }
    982 
    983 #ifdef __linux__
    984     /*
    985      * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
    986      * stems from additional socket structures in the send
    987      * and receive buffers.
    988      */
    989     if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
    990                                   || (opt == SO_RCVBUF))) {
    991         int n = *((int *)result);
    992         n /= 2;
    993         *((int *)result) = n;
    994     }
    995 #endif
    996 
    997 /* Workaround for Mac OS treating linger value as
    998  *  signed integer
    999  */
   1000 #ifdef MACOSX
   1001     if (level == SOL_SOCKET && opt == SO_LINGER) {
   1002         struct linger* to_cast = (struct linger*)result;
   1003         to_cast->l_linger = (unsigned short)to_cast->l_linger;
   1004     }
   1005 #endif
   1006     return rv;
   1007 }
   1008 
   1009 /*
   1010  * Wrapper for setsockopt system routine - performs any
   1011  * necessary pre/post processing to deal with OS specific
   1012  * issue :-
   1013  *
   1014  * On Solaris need to limit the suggested value for SO_SNDBUF
   1015  * and SO_RCVBUF to the kernel configured limit
   1016  *
   1017  * For IP_TOS socket option need to mask off bits as this
   1018  * aren't automatically masked by the kernel and results in
   1019  * an error.
   1020  */
   1021 int
   1022 NET_SetSockOpt(int fd, int level, int  opt, const void *arg,
   1023                int len)
   1024 {
   1025 #ifndef IPTOS_TOS_MASK
   1026 #define IPTOS_TOS_MASK 0x1e
   1027 #endif
   1028 #ifndef IPTOS_PREC_MASK
   1029 #define IPTOS_PREC_MASK 0xe0
   1030 #endif
   1031 
   1032 #if defined(_ALLBSD_SOURCE)
   1033 #if defined(KIPC_MAXSOCKBUF)
   1034     int mib[3];
   1035     size_t rlen;
   1036 #endif
   1037 
   1038     int *bufsize;
   1039 
   1040 #ifdef __APPLE__
   1041     static int maxsockbuf = -1;
   1042 #else
   1043     static long maxsockbuf = -1;
   1044 #endif
   1045 #endif
   1046 
   1047     /*
   1048      * IPPROTO/IP_TOS :-
   1049      * 1. IPv6 on Solaris/Mac OS:
   1050      *    Set the TOS OR Traffic Class value to cater for
   1051      *    IPv6 and IPv4 scenarios.
   1052      * 2. IPv6 on Linux: By default Linux ignores flowinfo
   1053      *    field so enable IPV6_FLOWINFO_SEND so that flowinfo
   1054      *    will be examined. We also set the IPv4 TOS option in this case.
   1055      * 3. IPv4: set socket option based on ToS and Precedence
   1056      *    fields (otherwise get invalid argument)
   1057      */
   1058     if (level == IPPROTO_IP && opt == IP_TOS) {
   1059         int *iptos;
   1060 
   1061 #if defined(AF_INET6) && defined(__linux__)
   1062         if (ipv6_available()) {
   1063             int optval = 1;
   1064             if (setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
   1065                            (void *)&optval, sizeof(optval)) < 0) {
   1066                 return -1;
   1067             }
   1068            /*
   1069             * Let's also set the IPV6_TCLASS flag.
   1070             * Linux appears to allow both IP_TOS and IPV6_TCLASS to be set
   1071             * This helps in mixed environments where IPv4 and IPv6 sockets
   1072             * are connecting.
   1073             */
   1074            if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS,
   1075                            arg, len) < 0) {
   1076                 return -1;
   1077             }
   1078         }
   1079 #endif
   1080 
   1081         iptos = (int *)arg;
   1082         // Android-changed: This is out-dated RFC 1349 scheme. Modern Linux uses
   1083         // Diffsev/ECN, and this mask is no longer relavant.
   1084         // *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
   1085     }
   1086 
   1087     /*
   1088      * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
   1089      * the value when it exceeds the system limit.
   1090      */
   1091 #ifdef __solaris__
   1092     if (level == SOL_SOCKET) {
   1093         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
   1094             int sotype=0, arglen;
   1095             int *bufsize, maxbuf;
   1096             int ret;
   1097 
   1098             /* Attempt with the original size */
   1099             ret = setsockopt(fd, level, opt, arg, len);
   1100             if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
   1101                 return ret;
   1102 
   1103             /* Exceeded system limit so clamp and retry */
   1104 
   1105             arglen = sizeof(sotype);
   1106             if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
   1107                            &arglen) < 0) {
   1108                 return -1;
   1109             }
   1110 
   1111             /*
   1112              * We try to get tcp_maxbuf (and udp_max_buf) using
   1113              * an ioctl() that isn't available on all versions of Solaris.
   1114              * If that fails, we use the search algorithm in findMaxBuf()
   1115              */
   1116             if (!init_tcp_max_buf && sotype == SOCK_STREAM) {
   1117                 tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf");
   1118                 if (tcp_max_buf == -1) {
   1119                     tcp_max_buf = findMaxBuf(fd, opt, SOCK_STREAM);
   1120                     if (tcp_max_buf == -1) {
   1121                         return -1;
   1122                     }
   1123                 }
   1124                 init_tcp_max_buf = 1;
   1125             } else if (!init_udp_max_buf && sotype == SOCK_DGRAM) {
   1126                 udp_max_buf = getParam("/dev/udp", "udp_max_buf");
   1127                 if (udp_max_buf == -1) {
   1128                     udp_max_buf = findMaxBuf(fd, opt, SOCK_DGRAM);
   1129                     if (udp_max_buf == -1) {
   1130                         return -1;
   1131                     }
   1132                 }
   1133                 init_udp_max_buf = 1;
   1134             }
   1135 
   1136             maxbuf = (sotype == SOCK_STREAM) ? tcp_max_buf : udp_max_buf;
   1137             bufsize = (int *)arg;
   1138             if (*bufsize > maxbuf) {
   1139                 *bufsize = maxbuf;
   1140             }
   1141         }
   1142     }
   1143 #endif
   1144 
   1145     /*
   1146      * On Linux the receive buffer is used for both socket
   1147      * structures and the the packet payload. The implication
   1148      * is that if SO_RCVBUF is too small then small packets
   1149      * must be discarded.
   1150      */
   1151 #ifdef __linux__
   1152     if (level == SOL_SOCKET && opt == SO_RCVBUF) {
   1153         int *bufsize = (int *)arg;
   1154         if (*bufsize < 1024) {
   1155             *bufsize = 1024;
   1156         }
   1157     }
   1158 #endif
   1159 
   1160 #if defined(_ALLBSD_SOURCE)
   1161     /*
   1162      * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On FreeBSD need to
   1163      * ensure that value is <= kern.ipc.maxsockbuf as otherwise we get
   1164      * an ENOBUFS error.
   1165      */
   1166     if (level == SOL_SOCKET) {
   1167         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
   1168 #ifdef KIPC_MAXSOCKBUF
   1169             if (maxsockbuf == -1) {
   1170                mib[0] = CTL_KERN;
   1171                mib[1] = KERN_IPC;
   1172                mib[2] = KIPC_MAXSOCKBUF;
   1173                rlen = sizeof(maxsockbuf);
   1174                if (sysctl(mib, 3, &maxsockbuf, &rlen, NULL, 0) == -1)
   1175                    maxsockbuf = 1024;
   1176 
   1177 #if 1
   1178                /* XXXBSD: This is a hack to workaround mb_max/mb_max_adj
   1179                   problem.  It should be removed when kern.ipc.maxsockbuf
   1180                   will be real value. */
   1181                maxsockbuf = (maxsockbuf/5)*4;
   1182 #endif
   1183            }
   1184 #elif defined(__OpenBSD__)
   1185            maxsockbuf = SB_MAX;
   1186 #else
   1187            maxsockbuf = 64 * 1024;      /* XXX: NetBSD */
   1188 #endif
   1189 
   1190            bufsize = (int *)arg;
   1191            if (*bufsize > maxsockbuf) {
   1192                *bufsize = maxsockbuf;
   1193            }
   1194 
   1195            if (opt == SO_RCVBUF && *bufsize < 1024) {
   1196                 *bufsize = 1024;
   1197            }
   1198 
   1199         }
   1200     }
   1201 
   1202     /*
   1203      * On Solaris, SO_REUSEADDR will allow multiple datagram
   1204      * sockets to bind to the same port.  The network jck tests
   1205      * for this "feature", so we need to emulate it by turning on
   1206      * SO_REUSEPORT as well for that combination.
   1207      */
   1208     if (level == SOL_SOCKET && opt == SO_REUSEADDR) {
   1209         int sotype;
   1210         socklen_t arglen;
   1211 
   1212         arglen = sizeof(sotype);
   1213         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen) < 0) {
   1214             return -1;
   1215         }
   1216 
   1217         if (sotype == SOCK_DGRAM) {
   1218             setsockopt(fd, level, SO_REUSEPORT, arg, len);
   1219         }
   1220     }
   1221 
   1222 #endif
   1223 
   1224     return setsockopt(fd, level, opt, arg, len);
   1225 }
   1226 
   1227 /*
   1228  * Wrapper for bind system call - performs any necessary pre/post
   1229  * processing to deal with OS specific issues :-
   1230  *
   1231  * Linux allows a socket to bind to 127.0.0.255 which must be
   1232  * caught.
   1233  *
   1234  * On Solaris with IPv6 enabled we must use an exclusive
   1235  * bind to guaranteed a unique port number across the IPv4 and
   1236  * IPv6 port spaces.
   1237  *
   1238  */
   1239 int
   1240 NET_Bind(int fd, struct sockaddr *him, int len)
   1241 {
   1242 #if defined(__solaris__) && defined(AF_INET6)
   1243     int level = -1;
   1244     int exclbind = -1;
   1245 #endif
   1246     int rv;
   1247 
   1248 #ifdef __linux__
   1249     /*
   1250      * ## get bugId for this issue - goes back to 1.2.2 port ##
   1251      * ## When IPv6 is enabled this will be an IPv4-mapped
   1252      * ## with family set to AF_INET6
   1253      */
   1254     if (him->sa_family == AF_INET) {
   1255         struct sockaddr_in *sa = (struct sockaddr_in *)him;
   1256         if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
   1257             errno = EADDRNOTAVAIL;
   1258             return -1;
   1259         }
   1260     }
   1261 #endif
   1262 
   1263 #if defined(__solaris__) && defined(AF_INET6)
   1264     /*
   1265      * Solaris has seperate IPv4 and IPv6 port spaces so we
   1266      * use an exclusive bind when SO_REUSEADDR is not used to
   1267      * give the illusion of a unified port space.
   1268      * This also avoids problems with IPv6 sockets connecting
   1269      * to IPv4 mapped addresses whereby the socket conversion
   1270      * results in a late bind that fails because the
   1271      * corresponding IPv4 port is in use.
   1272      */
   1273     if (ipv6_available()) {
   1274         int arg, len;
   1275 
   1276         len = sizeof(arg);
   1277         if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
   1278                        (char *)&arg, &len) == 0) {
   1279             if (useExclBind || arg == 0) {
   1280                 /*
   1281                  * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
   1282                  * property is true so enable TCP_EXCLBIND or
   1283                  * UDP_EXCLBIND
   1284                  */
   1285                 len = sizeof(arg);
   1286                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
   1287                                &len) == 0) {
   1288                     if (arg == SOCK_STREAM) {
   1289                         level = IPPROTO_TCP;
   1290                         exclbind = TCP_EXCLBIND;
   1291                     } else {
   1292                         level = IPPROTO_UDP;
   1293                         exclbind = UDP_EXCLBIND;
   1294                     }
   1295                 }
   1296 
   1297                 arg = 1;
   1298                 setsockopt(fd, level, exclbind, (char *)&arg,
   1299                            sizeof(arg));
   1300             }
   1301         }
   1302     }
   1303 
   1304 #endif
   1305 
   1306     rv = bind(fd, him, len);
   1307 
   1308 #if defined(__solaris__) && defined(AF_INET6)
   1309     if (rv < 0) {
   1310         int en = errno;
   1311         /* Restore *_EXCLBIND if the bind fails */
   1312         if (exclbind != -1) {
   1313             int arg = 0;
   1314             setsockopt(fd, level, exclbind, (char *)&arg,
   1315                        sizeof(arg));
   1316         }
   1317         errno = en;
   1318     }
   1319 #endif
   1320 
   1321     return rv;
   1322 }
   1323 
   1324 /**
   1325  * Wrapper for select/poll with timeout on a single file descriptor.
   1326  *
   1327  * flags (defined in net_util_md.h can be any combination of
   1328  * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
   1329  *
   1330  * The function will return when either the socket is ready for one
   1331  * of the specified operations or the timeout expired.
   1332  *
   1333  * It returns the time left from the timeout (possibly 0), or -1 if it expired.
   1334  */
   1335 
   1336 jint
   1337 NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout)
   1338 {
   1339     jlong prevTime = JVM_CurrentTimeMillis(env, 0);
   1340     jint read_rv;
   1341 
   1342     while (1) {
   1343         jlong newTime;
   1344 #ifndef USE_SELECT
   1345         {
   1346           struct pollfd pfd;
   1347           pfd.fd = fd;
   1348           pfd.events = 0;
   1349           if (flags & NET_WAIT_READ)
   1350             pfd.events |= POLLIN;
   1351           if (flags & NET_WAIT_WRITE)
   1352             pfd.events |= POLLOUT;
   1353           if (flags & NET_WAIT_CONNECT)
   1354             pfd.events |= POLLOUT;
   1355 
   1356           errno = 0;
   1357           read_rv = NET_Poll(&pfd, 1, timeout);
   1358         }
   1359 #else
   1360         {
   1361           fd_set rd, wr, ex;
   1362           struct timeval t;
   1363 
   1364           t.tv_sec = timeout / 1000;
   1365           t.tv_usec = (timeout % 1000) * 1000;
   1366 
   1367           FD_ZERO(&rd);
   1368           FD_ZERO(&wr);
   1369           FD_ZERO(&ex);
   1370           if (flags & NET_WAIT_READ) {
   1371             FD_SET(fd, &rd);
   1372           }
   1373           if (flags & NET_WAIT_WRITE) {
   1374             FD_SET(fd, &wr);
   1375           }
   1376           if (flags & NET_WAIT_CONNECT) {
   1377             FD_SET(fd, &wr);
   1378             FD_SET(fd, &ex);
   1379           }
   1380 
   1381           errno = 0;
   1382           read_rv = NET_Select(fd+1, &rd, &wr, &ex, &t);
   1383         }
   1384 #endif
   1385 
   1386         newTime = JVM_CurrentTimeMillis(env, 0);
   1387         timeout -= (newTime - prevTime);
   1388         if (timeout <= 0) {
   1389           return read_rv > 0 ? 0 : -1;
   1390         }
   1391         prevTime = newTime;
   1392 
   1393         if (read_rv > 0) {
   1394           break;
   1395         }
   1396 
   1397 
   1398       } /* while */
   1399 
   1400     return timeout;
   1401 }
   1402 
   1403 #if 0
   1404 // Stripped out unused code.
   1405 // http://b/27301951
   1406 __attribute__((destructor))
   1407 static void netUtilCleanUp() {
   1408     if (loRoutes != 0) free(loRoutes);
   1409     if (localifs != 0) free(localifs);
   1410 }
   1411 #endif
   1412