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 #ifndef _ALLBSD_SOURCE
38 #include <values.h>
39 #else
40 #include <limits.h>
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
43 #ifndef MAXINT
44 #define MAXINT INT_MAX
45 #endif
46 #endif
47
48 #ifdef __solaris__
49 #include <sys/sockio.h>
50 #include <stropts.h>
51 #include <inet/nd.h>
52 #endif
53
54 #ifdef __linux__
55 #include <arpa/inet.h>
56 #include <net/route.h>
57 #include <sys/utsname.h>
58
59 #ifndef IPV6_FLOWINFO_SEND
60 #define IPV6_FLOWINFO_SEND 33
61 #endif
62
63 #endif
64
65 #include "jni_util.h"
66 #include "jvm.h"
67 #include "net_util.h"
68
69 #include "java_net_SocketOptions.h"
70
71 /* needed from libsocket on Solaris 8 */
72
73 getaddrinfo_f getaddrinfo_ptr = NULL;
74 freeaddrinfo_f freeaddrinfo_ptr = NULL;
93 if (ni_class == NULL) {
94 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
95 CHECK_NULL(c);
96 c = (*env)->NewGlobalRef(env, c);
97 CHECK_NULL(c);
98 ni_defaultIndexID = (*env)->GetStaticFieldID(
99 env, c, "defaultIndex", "I");
100 ni_class = c;
101 }
102 int defaultIndex;
103 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)him;
104 if (sin6->sin6_family == AF_INET6 && (sin6->sin6_scope_id == 0)) {
105 defaultIndex = (*env)->GetStaticIntField(env, ni_class,
106 ni_defaultIndexID);
107 sin6->sin6_scope_id = defaultIndex;
108 }
109 #endif
110 }
111
112 int getDefaultScopeID(JNIEnv *env) {
113 static jclass ni_class = NULL;
114 static jfieldID ni_defaultIndexID;
115 if (ni_class == NULL) {
116 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
117 CHECK_NULL_RETURN(c, 0);
118 c = (*env)->NewGlobalRef(env, c);
119 CHECK_NULL_RETURN(c, 0);
120 ni_defaultIndexID = (*env)->GetStaticFieldID(env, c,
121 "defaultIndex", "I");
122 ni_class = c;
123 }
124 int defaultIndex = 0;
125 defaultIndex = (*env)->GetStaticIntField(env, ni_class,
126 ni_defaultIndexID);
127 return defaultIndex;
128 }
129
130 #ifdef __solaris__
131 static int init_tcp_max_buf, init_udp_max_buf;
132 static int tcp_max_buf;
133 static int udp_max_buf;
134 static int useExclBind = 0;
135
136 /*
137 * Get the specified parameter from the specified driver. The value
138 * of the parameter is assumed to be an 'int'. If the parameter
139 * cannot be obtained return -1
140 */
141 int net_getParam(char *driver, char *param)
142 {
143 struct strioctl stri;
144 char buf [64];
145 int s;
146 int value;
147
148 s = open (driver, O_RDWR);
149 if (s < 0) {
305 #if defined(DONT_ENABLE_IPV6)
306 jint IPv6_supported()
307 {
308 return JNI_FALSE;
309 }
310
311 #else /* !DONT_ENABLE_IPV6 */
312
313 jint IPv6_supported()
314 {
315 #ifndef AF_INET6
316 return JNI_FALSE;
317 #endif
318
319 #ifdef AF_INET6
320 int fd;
321 void *ipv6_fn;
322 SOCKADDR sa;
323 socklen_t sa_len = sizeof(sa);
324
325 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0) ;
326 if (fd < 0) {
327 /*
328 * TODO: We really cant tell since it may be an unrelated error
329 * for now we will assume that AF_INET6 is not available
330 */
331 return JNI_FALSE;
332 }
333
334 /*
335 * If fd 0 is a socket it means we've been launched from inetd or
336 * xinetd. If it's a socket then check the family - if it's an
337 * IPv4 socket then we need to disable IPv6.
338 */
339 if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
340 struct sockaddr *saP = (struct sockaddr *)&sa;
341 if (saP->sa_family != AF_INET6) {
342 return JNI_FALSE;
343 }
344 }
345
1190 return 0;
1191 }
1192 #endif
1193
1194
1195 /*
1196 * Wrapper for getsockopt system routine - does any necessary
1197 * pre/post processing to deal with OS specific oddities :-
1198 *
1199 * IP_TOS is a no-op with IPv6 sockets as it's setup when
1200 * the connection is established.
1201 *
1202 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
1203 * to compensate for an incorrect value returned by the kernel.
1204 */
1205 int
1206 NET_GetSockOpt(int fd, int level, int opt, void *result,
1207 int *len)
1208 {
1209 int rv;
1210
1211 #ifdef AF_INET6
1212 if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
1213 if (ipv6_available()) {
1214
1215 /*
1216 * For IPv6 socket option implemented at Java-level
1217 * so return -1.
1218 */
1219 int *tc = (int *)result;
1220 *tc = -1;
1221 return 0;
1222 }
1223 }
1224 #endif
1225
1226 #ifdef __solaris__
1227 rv = getsockopt(fd, level, opt, result, len);
1228 #else
1229 {
1230 socklen_t socklen = *len;
1231 rv = getsockopt(fd, level, opt, result, &socklen);
1232 *len = socklen;
1233 }
1234 #endif
1235
1236 if (rv < 0) {
1237 return rv;
1238 }
1239
1240 #ifdef __linux__
1241 /*
1242 * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
1243 * stems from additional socket structures in the send
1244 * and receive buffers.
1245 */
1246 if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
1247 || (opt == SO_RCVBUF))) {
1248 int n = *((int *)result);
1249 n /= 2;
1250 *((int *)result) = n;
1251 }
1252 #endif
1253
1254 /* Workaround for Mac OS treating linger value as
1325
1326 #if defined(AF_INET6) && defined(__linux__)
1327 if (ipv6_available()) {
1328 int optval = 1;
1329 return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
1330 (void *)&optval, sizeof(optval));
1331 }
1332 #endif
1333
1334 iptos = (int *)arg;
1335 *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
1336 }
1337
1338 /*
1339 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
1340 * the value when it exceeds the system limit.
1341 */
1342 #ifdef __solaris__
1343 if (level == SOL_SOCKET) {
1344 if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
1345 int sotype=0, arglen;
1346 int *bufsize, maxbuf;
1347 int ret;
1348
1349 /* Attempt with the original size */
1350 ret = setsockopt(fd, level, opt, arg, len);
1351 if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
1352 return ret;
1353
1354 /* Exceeded system limit so clamp and retry */
1355
1356 arglen = sizeof(sotype);
1357 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
1358 &arglen) < 0) {
1359 return -1;
1360 }
1361
1362 /*
1363 * We try to get tcp_maxbuf (and udp_max_buf) using
1364 * an ioctl() that isn't available on all versions of Solaris.
1365 * If that fails, we use the search algorithm in findMaxBuf()
1529 if (him->sa_family == AF_INET) {
1530 struct sockaddr_in *sa = (struct sockaddr_in *)him;
1531 if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
1532 errno = EADDRNOTAVAIL;
1533 return -1;
1534 }
1535 }
1536 #endif
1537
1538 #if defined(__solaris__) && defined(AF_INET6)
1539 /*
1540 * Solaris has separate IPv4 and IPv6 port spaces so we
1541 * use an exclusive bind when SO_REUSEADDR is not used to
1542 * give the illusion of a unified port space.
1543 * This also avoids problems with IPv6 sockets connecting
1544 * to IPv4 mapped addresses whereby the socket conversion
1545 * results in a late bind that fails because the
1546 * corresponding IPv4 port is in use.
1547 */
1548 if (ipv6_available()) {
1549 int arg, len;
1550
1551 len = sizeof(arg);
1552 if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1553 (char *)&arg, &len) == 0) {
1554 if (useExclBind || arg == 0) {
1555 /*
1556 * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
1557 * property is true so enable TCP_EXCLBIND or
1558 * UDP_EXCLBIND
1559 */
1560 len = sizeof(arg);
1561 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
1562 &len) == 0) {
1563 if (arg == SOCK_STREAM) {
1564 level = IPPROTO_TCP;
1565 exclbind = TCP_EXCLBIND;
1566 } else {
1567 level = IPPROTO_UDP;
1568 exclbind = UDP_EXCLBIND;
1569 }
|
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 #ifndef _ALLBSD_SOURCE
38 #include <values.h>
39 #else
40 #include <limits.h>
41 #include <sys/param.h>
42 #include <sys/sysctl.h>
43 #include <sys/ioctl.h>
44 #ifndef MAXINT
45 #define MAXINT INT_MAX
46 #endif
47 #endif
48
49 #ifdef __solaris__
50 #include <sys/filio.h>
51 #include <sys/sockio.h>
52 #include <stropts.h>
53 #include <inet/nd.h>
54 #endif
55
56 #ifdef __linux__
57 #include <sys/ioctl.h>
58 #include <arpa/inet.h>
59 #include <net/route.h>
60 #include <sys/utsname.h>
61
62 #ifndef IPV6_FLOWINFO_SEND
63 #define IPV6_FLOWINFO_SEND 33
64 #endif
65
66 #endif
67
68 #include "jni_util.h"
69 #include "jvm.h"
70 #include "net_util.h"
71
72 #include "java_net_SocketOptions.h"
73
74 /* needed from libsocket on Solaris 8 */
75
76 getaddrinfo_f getaddrinfo_ptr = NULL;
77 freeaddrinfo_f freeaddrinfo_ptr = NULL;
96 if (ni_class == NULL) {
97 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
98 CHECK_NULL(c);
99 c = (*env)->NewGlobalRef(env, c);
100 CHECK_NULL(c);
101 ni_defaultIndexID = (*env)->GetStaticFieldID(
102 env, c, "defaultIndex", "I");
103 ni_class = c;
104 }
105 int defaultIndex;
106 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)him;
107 if (sin6->sin6_family == AF_INET6 && (sin6->sin6_scope_id == 0)) {
108 defaultIndex = (*env)->GetStaticIntField(env, ni_class,
109 ni_defaultIndexID);
110 sin6->sin6_scope_id = defaultIndex;
111 }
112 #endif
113 }
114
115 int getDefaultScopeID(JNIEnv *env) {
116 int defaultIndex = 0;
117 static jclass ni_class = NULL;
118 static jfieldID ni_defaultIndexID;
119 if (ni_class == NULL) {
120 jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");
121 CHECK_NULL_RETURN(c, 0);
122 c = (*env)->NewGlobalRef(env, c);
123 CHECK_NULL_RETURN(c, 0);
124 ni_defaultIndexID = (*env)->GetStaticFieldID(env, c,
125 "defaultIndex", "I");
126 ni_class = c;
127 }
128 defaultIndex = (*env)->GetStaticIntField(env, ni_class,
129 ni_defaultIndexID);
130 return defaultIndex;
131 }
132
133 #define RESTARTABLE(_cmd, _result) do { \
134 do { \
135 _result = _cmd; \
136 } while((_result == -1) && (errno == EINTR)); \
137 } while(0)
138
139 int NET_SocketAvailable(int s, jint *pbytes) {
140 int result;
141 RESTARTABLE(ioctl(s, FIONREAD, pbytes), result);
142 // note: ioctl can return 0 when successful, NET_SocketAvailable
143 // is expected to return 0 on failure and 1 on success.
144 return (result == -1) ? 0 : 1;
145 }
146
147 #ifdef __solaris__
148 static int init_tcp_max_buf, init_udp_max_buf;
149 static int tcp_max_buf;
150 static int udp_max_buf;
151 static int useExclBind = 0;
152
153 /*
154 * Get the specified parameter from the specified driver. The value
155 * of the parameter is assumed to be an 'int'. If the parameter
156 * cannot be obtained return -1
157 */
158 int net_getParam(char *driver, char *param)
159 {
160 struct strioctl stri;
161 char buf [64];
162 int s;
163 int value;
164
165 s = open (driver, O_RDWR);
166 if (s < 0) {
322 #if defined(DONT_ENABLE_IPV6)
323 jint IPv6_supported()
324 {
325 return JNI_FALSE;
326 }
327
328 #else /* !DONT_ENABLE_IPV6 */
329
330 jint IPv6_supported()
331 {
332 #ifndef AF_INET6
333 return JNI_FALSE;
334 #endif
335
336 #ifdef AF_INET6
337 int fd;
338 void *ipv6_fn;
339 SOCKADDR sa;
340 socklen_t sa_len = sizeof(sa);
341
342 fd = socket(AF_INET6, SOCK_STREAM, 0) ;
343 if (fd < 0) {
344 /*
345 * TODO: We really cant tell since it may be an unrelated error
346 * for now we will assume that AF_INET6 is not available
347 */
348 return JNI_FALSE;
349 }
350
351 /*
352 * If fd 0 is a socket it means we've been launched from inetd or
353 * xinetd. If it's a socket then check the family - if it's an
354 * IPv4 socket then we need to disable IPv6.
355 */
356 if (getsockname(0, (struct sockaddr *)&sa, &sa_len) == 0) {
357 struct sockaddr *saP = (struct sockaddr *)&sa;
358 if (saP->sa_family != AF_INET6) {
359 return JNI_FALSE;
360 }
361 }
362
1207 return 0;
1208 }
1209 #endif
1210
1211
1212 /*
1213 * Wrapper for getsockopt system routine - does any necessary
1214 * pre/post processing to deal with OS specific oddities :-
1215 *
1216 * IP_TOS is a no-op with IPv6 sockets as it's setup when
1217 * the connection is established.
1218 *
1219 * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
1220 * to compensate for an incorrect value returned by the kernel.
1221 */
1222 int
1223 NET_GetSockOpt(int fd, int level, int opt, void *result,
1224 int *len)
1225 {
1226 int rv;
1227 socklen_t socklen = *len;
1228
1229 #ifdef AF_INET6
1230 if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
1231 if (ipv6_available()) {
1232
1233 /*
1234 * For IPv6 socket option implemented at Java-level
1235 * so return -1.
1236 */
1237 int *tc = (int *)result;
1238 *tc = -1;
1239 return 0;
1240 }
1241 }
1242 #endif
1243
1244 rv = getsockopt(fd, level, opt, result, &socklen);
1245 *len = socklen;
1246
1247 if (rv < 0) {
1248 return rv;
1249 }
1250
1251 #ifdef __linux__
1252 /*
1253 * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This
1254 * stems from additional socket structures in the send
1255 * and receive buffers.
1256 */
1257 if ((level == SOL_SOCKET) && ((opt == SO_SNDBUF)
1258 || (opt == SO_RCVBUF))) {
1259 int n = *((int *)result);
1260 n /= 2;
1261 *((int *)result) = n;
1262 }
1263 #endif
1264
1265 /* Workaround for Mac OS treating linger value as
1336
1337 #if defined(AF_INET6) && defined(__linux__)
1338 if (ipv6_available()) {
1339 int optval = 1;
1340 return setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,
1341 (void *)&optval, sizeof(optval));
1342 }
1343 #endif
1344
1345 iptos = (int *)arg;
1346 *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
1347 }
1348
1349 /*
1350 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
1351 * the value when it exceeds the system limit.
1352 */
1353 #ifdef __solaris__
1354 if (level == SOL_SOCKET) {
1355 if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
1356 int sotype=0;
1357 socklen_t arglen;
1358 int *bufsize, maxbuf;
1359 int ret;
1360
1361 /* Attempt with the original size */
1362 ret = setsockopt(fd, level, opt, arg, len);
1363 if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
1364 return ret;
1365
1366 /* Exceeded system limit so clamp and retry */
1367
1368 arglen = sizeof(sotype);
1369 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
1370 &arglen) < 0) {
1371 return -1;
1372 }
1373
1374 /*
1375 * We try to get tcp_maxbuf (and udp_max_buf) using
1376 * an ioctl() that isn't available on all versions of Solaris.
1377 * If that fails, we use the search algorithm in findMaxBuf()
1541 if (him->sa_family == AF_INET) {
1542 struct sockaddr_in *sa = (struct sockaddr_in *)him;
1543 if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
1544 errno = EADDRNOTAVAIL;
1545 return -1;
1546 }
1547 }
1548 #endif
1549
1550 #if defined(__solaris__) && defined(AF_INET6)
1551 /*
1552 * Solaris has separate IPv4 and IPv6 port spaces so we
1553 * use an exclusive bind when SO_REUSEADDR is not used to
1554 * give the illusion of a unified port space.
1555 * This also avoids problems with IPv6 sockets connecting
1556 * to IPv4 mapped addresses whereby the socket conversion
1557 * results in a late bind that fails because the
1558 * corresponding IPv4 port is in use.
1559 */
1560 if (ipv6_available()) {
1561 int arg;
1562 socklen_t len;
1563
1564 len = sizeof(arg);
1565 if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
1566 (char *)&arg, &len) == 0) {
1567 if (useExclBind || arg == 0) {
1568 /*
1569 * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
1570 * property is true so enable TCP_EXCLBIND or
1571 * UDP_EXCLBIND
1572 */
1573 len = sizeof(arg);
1574 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
1575 &len) == 0) {
1576 if (arg == SOCK_STREAM) {
1577 level = IPPROTO_TCP;
1578 exclbind = TCP_EXCLBIND;
1579 } else {
1580 level = IPPROTO_UDP;
1581 exclbind = UDP_EXCLBIND;
1582 }
|