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