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 
setDefaultScopeID(JNIEnv * env,struct sockaddr * him)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 
getDefaultScopeID(JNIEnv * env)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
getParam(char * driver,char * param)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 
findMaxBuf(int fd,int opt,int sotype)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 
kernelIsV24()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 
getScopeID(struct sockaddr * him)237 int getScopeID (struct sockaddr *him) {
238     struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
239     return hext->sin6_scope_id;
240 }
241 
cmpScopeID(unsigned int scope,struct sockaddr * him)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 
getScopeID(struct sockaddr * him)249 int getScopeID (struct sockaddr *him) {
250     struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
251     return him6->sin6_scope_id;
252 }
253 
cmpScopeID(unsigned int scope,struct sockaddr * him)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
NET_ThrowByNameWithLastError(JNIEnv * env,const char * name,const char * defaultDetail)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
NET_ThrowCurrent(JNIEnv * env,char * msg)272 NET_ThrowCurrent(JNIEnv *env, char *msg) {
273     NET_ThrowNew(env, errno, msg);
274 }
275 
276 void
NET_ThrowNew(JNIEnv * env,int errorNumber,char * msg)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
NET_GetFileDescriptorID(JNIEnv * env)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)
IPv6_supported()307 jint  IPv6_supported()
308 {
309     return JNI_FALSE;
310 }
311 
312 #else /* !DONT_ENABLE_IPV6 */
313 
IPv6_supported()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 
ThrowUnknownHostExceptionWithGaiError(JNIEnv * env,const char * hostname,int gai_error)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
NET_AllocSockaddr(struct sockaddr ** him,int * len)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 
initLocalAddrTable()720 void initLocalAddrTable () {}
721 
722 #endif
723 
parseExclusiveBindProperty(JNIEnv * env)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
NET_InetAddressToSockaddr(JNIEnv * env,jobject iaObj,int port,struct sockaddr * him,int * len,jboolean v4MappedAddress)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
NET_SetTrafficClass(struct sockaddr * him,int trafficClass)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
NET_GetPortFromSockaddr(struct sockaddr * him)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
NET_IsIPv4Mapped(jbyte * caddr)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
NET_IPv4MappedToIPv4(jbyte * caddr)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
NET_IsEqual(jbyte * caddr1,jbyte * caddr2)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 
NET_addrtransAvailable()875 jboolean NET_addrtransAvailable() {
876     return (jboolean)(getaddrinfo_ptr != NULL);
877 }
878 
NET_IsZeroAddr(jbyte * caddr)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
NET_MapSocketOption(jint cmd,int * level,int * optname)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
NET_GetSockOpt(int fd,int level,int opt,void * result,int * len)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
NET_SetSockOpt(int fd,int level,int opt,const void * arg,int len)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
NET_Bind(int fd,struct sockaddr * him,int len)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
NET_Wait(JNIEnv * env,jint fd,jint flags,jint timeout)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