File: | jdk/src/java.base/unix/native/libnet/net_util_md.c |
Warning: | line 147, column 29 The left operand of '==' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 1997, 2020, 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(*__errno_location ()).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__1) | |||
35 | #include <arpa/inet.h> | |||
36 | #include <net/route.h> | |||
37 | #include <sys/utsname.h> | |||
38 | #endif | |||
39 | ||||
40 | #if defined(MACOSX) | |||
41 | #include <sys/sysctl.h> | |||
42 | #endif | |||
43 | ||||
44 | #include "jvm.h" | |||
45 | #include "net_util.h" | |||
46 | ||||
47 | #include "java_net_SocketOptions.h" | |||
48 | #include "java_net_InetAddress.h" | |||
49 | ||||
50 | #if defined(__linux__1) && !defined(IPV6_FLOWINFO_SEND33) | |||
51 | #define IPV6_FLOWINFO_SEND33 33 | |||
52 | #endif | |||
53 | ||||
54 | #define RESTARTABLE(_cmd, _result)do { do { _result = _cmd; } while((_result == -1) && ( (*__errno_location ()) == 4)); } while(0) do { \ | |||
55 | do { \ | |||
56 | _result = _cmd; \ | |||
57 | } while((_result == -1) && (errno(*__errno_location ()) == EINTR4)); \ | |||
58 | } while(0) | |||
59 | ||||
60 | int NET_SocketAvailable(int s, int *pbytes) { | |||
61 | int result; | |||
62 | RESTARTABLE(ioctl(s, FIONREAD, pbytes), result)do { do { result = ioctl(s, 0x541B, pbytes); } while((result == -1) && ((*__errno_location ()) == 4)); } while(0); | |||
63 | return result; | |||
64 | } | |||
65 | ||||
66 | void | |||
67 | NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, | |||
68 | const char *defaultDetail) { | |||
69 | JNU_ThrowByNameWithMessageAndLastError(env, name, defaultDetail); | |||
70 | } | |||
71 | ||||
72 | void | |||
73 | NET_ThrowCurrent(JNIEnv *env, char *msg) { | |||
74 | NET_ThrowNew(env, errno(*__errno_location ()), msg); | |||
75 | } | |||
76 | ||||
77 | void | |||
78 | NET_ThrowNew(JNIEnv *env, int errorNumber, char *msg) { | |||
79 | char fullMsg[512]; | |||
80 | if (!msg) { | |||
81 | msg = "no further information"; | |||
82 | } | |||
83 | switch(errorNumber) { | |||
84 | case EBADF9: | |||
85 | jio_snprintf(fullMsg, sizeof(fullMsg), "socket closed: %s", msg); | |||
86 | JNU_ThrowByName(env, JNU_JAVANETPKG"java/net/" "SocketException", fullMsg); | |||
87 | break; | |||
88 | case EINTR4: | |||
89 | JNU_ThrowByName(env, JNU_JAVAIOPKG"java/io/" "InterruptedIOException", msg); | |||
90 | break; | |||
91 | default: | |||
92 | errno(*__errno_location ()) = errorNumber; | |||
93 | JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG"java/net/" "SocketException", msg); | |||
94 | break; | |||
95 | } | |||
96 | } | |||
97 | ||||
98 | ||||
99 | jfieldID | |||
100 | NET_GetFileDescriptorID(JNIEnv *env) | |||
101 | { | |||
102 | jclass cls = (*env)->FindClass(env, "java/io/FileDescriptor"); | |||
103 | CHECK_NULL_RETURN(cls, NULL)do { if ((cls) == ((void*)0)) { return (((void*)0)); } } while (0); | |||
104 | return (*env)->GetFieldID(env, cls, "fd", "I"); | |||
105 | } | |||
106 | ||||
107 | jint IPv4_supported() | |||
108 | { | |||
109 | int fd = socket(AF_INET2, SOCK_STREAMSOCK_STREAM, 0) ; | |||
110 | if (fd < 0) { | |||
111 | return JNI_FALSE0; | |||
112 | } | |||
113 | close(fd); | |||
114 | return JNI_TRUE1; | |||
115 | } | |||
116 | ||||
117 | #if defined(DONT_ENABLE_IPV6) | |||
118 | jint IPv6_supported() | |||
119 | { | |||
120 | return JNI_FALSE0; | |||
121 | } | |||
122 | ||||
123 | #else /* !DONT_ENABLE_IPV6 */ | |||
124 | ||||
125 | jint IPv6_supported() | |||
126 | { | |||
127 | int fd; | |||
128 | void *ipv6_fn; | |||
129 | SOCKETADDRESS sa; | |||
130 | socklen_t sa_len = sizeof(SOCKETADDRESS); | |||
131 | ||||
132 | fd = socket(AF_INET610, SOCK_STREAMSOCK_STREAM, 0) ; | |||
133 | if (fd < 0) { | |||
| ||||
134 | /* | |||
135 | * TODO: We really cant tell since it may be an unrelated error | |||
136 | * for now we will assume that AF_INET6 is not available | |||
137 | */ | |||
138 | return JNI_FALSE0; | |||
139 | } | |||
140 | ||||
141 | /* | |||
142 | * If fd 0 is a socket it means we may have been launched from inetd or | |||
143 | * xinetd. If it's a socket then check the family - if it's an | |||
144 | * IPv4 socket then we need to disable IPv6. | |||
145 | */ | |||
146 | if (getsockname(0, &sa.sa, &sa_len) == 0) { | |||
147 | if (sa.sa.sa_family == AF_INET2) { | |||
| ||||
148 | close(fd); | |||
149 | return JNI_FALSE0; | |||
150 | } | |||
151 | } | |||
152 | ||||
153 | /** | |||
154 | * Linux - check if any interface has an IPv6 address. | |||
155 | * Don't need to parse the line - we just need an indication. | |||
156 | */ | |||
157 | #ifdef __linux__1 | |||
158 | { | |||
159 | FILE *fP = fopen("/proc/net/if_inet6", "r"); | |||
160 | char buf[255]; | |||
161 | char *bufP; | |||
162 | ||||
163 | if (fP == NULL((void*)0)) { | |||
164 | close(fd); | |||
165 | return JNI_FALSE0; | |||
166 | } | |||
167 | bufP = fgets(buf, sizeof(buf), fP); | |||
168 | fclose(fP); | |||
169 | if (bufP == NULL((void*)0)) { | |||
170 | close(fd); | |||
171 | return JNI_FALSE0; | |||
172 | } | |||
173 | } | |||
174 | #endif | |||
175 | ||||
176 | /* | |||
177 | * OK we may have the stack available in the kernel, | |||
178 | * we should also check if the APIs are available. | |||
179 | */ | |||
180 | ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT((void *) 0), "inet_pton"); | |||
181 | close(fd); | |||
182 | if (ipv6_fn == NULL((void*)0) ) { | |||
183 | return JNI_FALSE0; | |||
184 | } else { | |||
185 | return JNI_TRUE1; | |||
186 | } | |||
187 | } | |||
188 | #endif /* DONT_ENABLE_IPV6 */ | |||
189 | ||||
190 | jint reuseport_supported() | |||
191 | { | |||
192 | /* Do a simple dummy call, and try to figure out from that */ | |||
193 | int one = 1; | |||
194 | int rv, s; | |||
195 | s = socket(PF_INET2, SOCK_STREAMSOCK_STREAM, 0); | |||
196 | if (s < 0) { | |||
197 | return JNI_FALSE0; | |||
198 | } | |||
199 | rv = setsockopt(s, SOL_SOCKET1, SO_REUSEPORT15, (void *)&one, sizeof(one)); | |||
200 | if (rv != 0) { | |||
201 | rv = JNI_FALSE0; | |||
202 | } else { | |||
203 | rv = JNI_TRUE1; | |||
204 | } | |||
205 | close(s); | |||
206 | return rv; | |||
207 | } | |||
208 | ||||
209 | void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, | |||
210 | const char* hostname, | |||
211 | int gai_error) | |||
212 | { | |||
213 | int size; | |||
214 | char *buf; | |||
215 | const char *format = "%s: %s"; | |||
216 | const char *error_string = gai_strerror(gai_error); | |||
217 | if (error_string == NULL((void*)0)) | |||
218 | error_string = "unknown error"; | |||
219 | ||||
220 | size = strlen(format) + strlen(hostname) + strlen(error_string) + 2; | |||
221 | buf = (char *) malloc(size); | |||
222 | if (buf) { | |||
223 | jstring s; | |||
224 | sprintf(buf, format, hostname, error_string)__builtin___sprintf_chk (buf, 2 - 1, __builtin_object_size (buf , 2 > 1), format, hostname, error_string); | |||
225 | s = JNU_NewStringPlatform(env, buf); | |||
226 | if (s != NULL((void*)0)) { | |||
227 | jobject x = JNU_NewObjectByName(env, | |||
228 | "java/net/UnknownHostException", | |||
229 | "(Ljava/lang/String;)V", s); | |||
230 | if (x != NULL((void*)0)) | |||
231 | (*env)->Throw(env, x); | |||
232 | } | |||
233 | free(buf); | |||
234 | } | |||
235 | } | |||
236 | ||||
237 | #if defined(_AIX) | |||
238 | ||||
239 | /* Initialize stubs for blocking I/O workarounds (see src/solaris/native/java/net/linux_close.c) */ | |||
240 | extern void aix_close_init(); | |||
241 | ||||
242 | void platformInit () { | |||
243 | aix_close_init(); | |||
244 | } | |||
245 | ||||
246 | #else | |||
247 | ||||
248 | void platformInit () {} | |||
249 | ||||
250 | #endif | |||
251 | ||||
252 | JNIEXPORT__attribute__((visibility("default"))) jint JNICALL | |||
253 | NET_EnableFastTcpLoopback(int fd) { | |||
254 | return 0; | |||
255 | } | |||
256 | ||||
257 | /** | |||
258 | * See net_util.h for documentation | |||
259 | */ | |||
260 | JNIEXPORT__attribute__((visibility("default"))) int JNICALL | |||
261 | NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, | |||
262 | SOCKETADDRESS *sa, int *len, | |||
263 | jboolean v4MappedAddress) | |||
264 | { | |||
265 | jint family = getInetAddress_family(env, iaObj); | |||
266 | JNU_CHECK_EXCEPTION_RETURN(env, -1)do { if ((*env)->ExceptionCheck(env)) { return (-1); } } while (0); | |||
267 | memset((char *)sa, 0, sizeof(SOCKETADDRESS)); | |||
268 | ||||
269 | if (ipv6_available() && | |||
270 | !(family == java_net_InetAddress_IPv41L && | |||
271 | v4MappedAddress == JNI_FALSE0)) | |||
272 | { | |||
273 | jbyte caddr[16]; | |||
274 | jint address; | |||
275 | ||||
276 | if (family == java_net_InetAddress_IPv41L) { | |||
277 | // convert to IPv4-mapped address | |||
278 | memset((char *)caddr, 0, 16); | |||
279 | address = getInetAddress_addr(env, iaObj); | |||
280 | JNU_CHECK_EXCEPTION_RETURN(env, -1)do { if ((*env)->ExceptionCheck(env)) { return (-1); } } while (0); | |||
281 | if (address == INADDR_ANY((in_addr_t) 0x00000000)) { | |||
282 | /* we would always prefer IPv6 wildcard address | |||
283 | * caddr[10] = 0xff; | |||
284 | * caddr[11] = 0xff; */ | |||
285 | } else { | |||
286 | caddr[10] = 0xff; | |||
287 | caddr[11] = 0xff; | |||
288 | caddr[12] = ((address >> 24) & 0xff); | |||
289 | caddr[13] = ((address >> 16) & 0xff); | |||
290 | caddr[14] = ((address >> 8) & 0xff); | |||
291 | caddr[15] = (address & 0xff); | |||
292 | } | |||
293 | } else { | |||
294 | getInet6Address_ipaddress(env, iaObj, (char *)caddr); | |||
295 | } | |||
296 | sa->sa6.sin6_port = htons(port)(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (port); if (__builtin_constant_p (__x)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff ) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
297 | memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr)); | |||
298 | sa->sa6.sin6_family = AF_INET610; | |||
299 | if (len != NULL((void*)0)) { | |||
300 | *len = sizeof(struct sockaddr_in6); | |||
301 | } | |||
302 | ||||
303 | /* handle scope_id */ | |||
304 | if (family != java_net_InetAddress_IPv41L) { | |||
305 | if (ia6_scopeidID) { | |||
306 | sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj); | |||
307 | } | |||
308 | } | |||
309 | } else { | |||
310 | jint address; | |||
311 | if (family != java_net_InetAddress_IPv41L) { | |||
312 | JNU_ThrowByName(env, JNU_JAVANETPKG"java/net/" "SocketException", "Protocol family unavailable"); | |||
313 | return -1; | |||
314 | } | |||
315 | address = getInetAddress_addr(env, iaObj); | |||
316 | JNU_CHECK_EXCEPTION_RETURN(env, -1)do { if ((*env)->ExceptionCheck(env)) { return (-1); } } while (0); | |||
317 | sa->sa4.sin_port = htons(port)(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (port); if (__builtin_constant_p (__x)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff ) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
318 | sa->sa4.sin_addr.s_addr = htonl(address)(__extension__ ({ unsigned int __v, __x = (address); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x ) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ( "bswap %0" : "=r" (__v) : "0" (__x)); __v; })); | |||
319 | sa->sa4.sin_family = AF_INET2; | |||
320 | if (len != NULL((void*)0)) { | |||
321 | *len = sizeof(struct sockaddr_in); | |||
322 | } | |||
323 | } | |||
324 | return 0; | |||
325 | } | |||
326 | ||||
327 | void | |||
328 | NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) { | |||
329 | if (sa->sa.sa_family == AF_INET610) { | |||
330 | sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20)(__extension__ ({ unsigned int __v, __x = ((trafficClass & 0xff) << 20); if (__builtin_constant_p (__x)) __v = (( ((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000 ) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x ) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v; })); | |||
331 | } | |||
332 | } | |||
333 | ||||
334 | int | |||
335 | NET_IsIPv4Mapped(jbyte* caddr) { | |||
336 | int i; | |||
337 | for (i = 0; i < 10; i++) { | |||
338 | if (caddr[i] != 0x00) { | |||
339 | return 0; /* false */ | |||
340 | } | |||
341 | } | |||
342 | ||||
343 | if (((caddr[10] & 0xff) == 0xff) && ((caddr[11] & 0xff) == 0xff)) { | |||
344 | return 1; /* true */ | |||
345 | } | |||
346 | return 0; /* false */ | |||
347 | } | |||
348 | ||||
349 | int | |||
350 | NET_IPv4MappedToIPv4(jbyte* caddr) { | |||
351 | return ((caddr[12] & 0xff) << 24) | ((caddr[13] & 0xff) << 16) | ((caddr[14] & 0xff) << 8) | |||
352 | | (caddr[15] & 0xff); | |||
353 | } | |||
354 | ||||
355 | int | |||
356 | NET_IsEqual(jbyte* caddr1, jbyte* caddr2) { | |||
357 | int i; | |||
358 | for (i = 0; i < 16; i++) { | |||
359 | if (caddr1[i] != caddr2[i]) { | |||
360 | return 0; /* false */ | |||
361 | } | |||
362 | } | |||
363 | return 1; | |||
364 | } | |||
365 | ||||
366 | int NET_IsZeroAddr(jbyte* caddr) { | |||
367 | int i; | |||
368 | for (i = 0; i < 16; i++) { | |||
369 | if (caddr[i] != 0) { | |||
370 | return 0; | |||
371 | } | |||
372 | } | |||
373 | return 1; | |||
374 | } | |||
375 | ||||
376 | /* | |||
377 | * Map the Java level socket option to the platform specific | |||
378 | * level and option name. | |||
379 | */ | |||
380 | int | |||
381 | NET_MapSocketOption(jint cmd, int *level, int *optname) { | |||
382 | static struct { | |||
383 | jint cmd; | |||
384 | int level; | |||
385 | int optname; | |||
386 | } const opts[] = { | |||
387 | { java_net_SocketOptions_TCP_NODELAY1L, IPPROTO_TCPIPPROTO_TCP, TCP_NODELAY1 }, | |||
388 | { java_net_SocketOptions_SO_OOBINLINE4099L, SOL_SOCKET1, SO_OOBINLINE10 }, | |||
389 | { java_net_SocketOptions_SO_LINGER128L, SOL_SOCKET1, SO_LINGER13 }, | |||
390 | { java_net_SocketOptions_SO_SNDBUF4097L, SOL_SOCKET1, SO_SNDBUF7 }, | |||
391 | { java_net_SocketOptions_SO_RCVBUF4098L, SOL_SOCKET1, SO_RCVBUF8 }, | |||
392 | { java_net_SocketOptions_SO_KEEPALIVE8L, SOL_SOCKET1, SO_KEEPALIVE9 }, | |||
393 | { java_net_SocketOptions_SO_REUSEADDR4L, SOL_SOCKET1, SO_REUSEADDR2 }, | |||
394 | { java_net_SocketOptions_SO_REUSEPORT14L, SOL_SOCKET1, SO_REUSEPORT15 }, | |||
395 | { java_net_SocketOptions_SO_BROADCAST32L, SOL_SOCKET1, SO_BROADCAST6 }, | |||
396 | { java_net_SocketOptions_IP_TOS3L, IPPROTO_IPIPPROTO_IP, IP_TOS1 }, | |||
397 | { java_net_SocketOptions_IP_MULTICAST_IF16L, IPPROTO_IPIPPROTO_IP, IP_MULTICAST_IF32 }, | |||
398 | { java_net_SocketOptions_IP_MULTICAST_IF231L, IPPROTO_IPIPPROTO_IP, IP_MULTICAST_IF32 }, | |||
399 | { java_net_SocketOptions_IP_MULTICAST_LOOP18L, IPPROTO_IPIPPROTO_IP, IP_MULTICAST_LOOP34 }, | |||
400 | }; | |||
401 | ||||
402 | int i; | |||
403 | ||||
404 | if (ipv6_available()) { | |||
405 | switch (cmd) { | |||
406 | // Different multicast options if IPv6 is enabled | |||
407 | case java_net_SocketOptions_IP_MULTICAST_IF16L: | |||
408 | case java_net_SocketOptions_IP_MULTICAST_IF231L: | |||
409 | *level = IPPROTO_IPV6IPPROTO_IPV6; | |||
410 | *optname = IPV6_MULTICAST_IF17; | |||
411 | return 0; | |||
412 | ||||
413 | case java_net_SocketOptions_IP_MULTICAST_LOOP18L: | |||
414 | *level = IPPROTO_IPV6IPPROTO_IPV6; | |||
415 | *optname = IPV6_MULTICAST_LOOP19; | |||
416 | return 0; | |||
417 | #if defined(MACOSX) | |||
418 | // Map IP_TOS request to IPV6_TCLASS | |||
419 | case java_net_SocketOptions_IP_TOS3L: | |||
420 | *level = IPPROTO_IPV6IPPROTO_IPV6; | |||
421 | *optname = IPV6_TCLASS67; | |||
422 | return 0; | |||
423 | #endif | |||
424 | } | |||
425 | } | |||
426 | ||||
427 | /* | |||
428 | * Map the Java level option to the native level | |||
429 | */ | |||
430 | for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) { | |||
431 | if (cmd == opts[i].cmd) { | |||
432 | *level = opts[i].level; | |||
433 | *optname = opts[i].optname; | |||
434 | return 0; | |||
435 | } | |||
436 | } | |||
437 | ||||
438 | /* not found */ | |||
439 | return -1; | |||
440 | } | |||
441 | ||||
442 | /* | |||
443 | * Wrapper for getsockopt system routine - does any necessary | |||
444 | * pre/post processing to deal with OS specific oddities :- | |||
445 | * | |||
446 | * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed | |||
447 | * to compensate for an incorrect value returned by the kernel. | |||
448 | */ | |||
449 | int | |||
450 | NET_GetSockOpt(int fd, int level, int opt, void *result, | |||
451 | int *len) | |||
452 | { | |||
453 | int rv; | |||
454 | socklen_t socklen = *len; | |||
455 | ||||
456 | rv = getsockopt(fd, level, opt, result, &socklen); | |||
457 | *len = socklen; | |||
458 | ||||
459 | if (rv < 0) { | |||
460 | return rv; | |||
461 | } | |||
462 | ||||
463 | #ifdef __linux__1 | |||
464 | /* | |||
465 | * On Linux SO_SNDBUF/SO_RCVBUF aren't symmetric. This | |||
466 | * stems from additional socket structures in the send | |||
467 | * and receive buffers. | |||
468 | */ | |||
469 | if ((level == SOL_SOCKET1) && ((opt == SO_SNDBUF7) | |||
470 | || (opt == SO_RCVBUF8))) { | |||
471 | int n = *((int *)result); | |||
472 | n /= 2; | |||
473 | *((int *)result) = n; | |||
474 | } | |||
475 | #endif | |||
476 | ||||
477 | /* Workaround for Mac OS treating linger value as | |||
478 | * signed integer | |||
479 | */ | |||
480 | #ifdef MACOSX | |||
481 | if (level == SOL_SOCKET1 && opt == SO_LINGER13) { | |||
482 | struct linger* to_cast = (struct linger*)result; | |||
483 | to_cast->l_linger = (unsigned short)to_cast->l_linger; | |||
484 | } | |||
485 | #endif | |||
486 | return rv; | |||
487 | } | |||
488 | ||||
489 | /* | |||
490 | * Wrapper for setsockopt system routine - performs any | |||
491 | * necessary pre/post processing to deal with OS specific | |||
492 | * issue :- | |||
493 | * | |||
494 | * On Solaris need to limit the suggested value for SO_SNDBUF | |||
495 | * and SO_RCVBUF to the kernel configured limit | |||
496 | * | |||
497 | * For IP_TOS socket option need to mask off bits as this | |||
498 | * aren't automatically masked by the kernel and results in | |||
499 | * an error. | |||
500 | */ | |||
501 | int | |||
502 | NET_SetSockOpt(int fd, int level, int opt, const void *arg, | |||
503 | int len) | |||
504 | { | |||
505 | ||||
506 | #ifndef IPTOS_TOS_MASK0x1e | |||
507 | #define IPTOS_TOS_MASK0x1e 0x1e | |||
508 | #endif | |||
509 | #ifndef IPTOS_PREC_MASK0xe0 | |||
510 | #define IPTOS_PREC_MASK0xe0 0xe0 | |||
511 | #endif | |||
512 | ||||
513 | #if defined(_ALLBSD_SOURCE) | |||
514 | #if defined(KIPC_MAXSOCKBUF) | |||
515 | int mib[3]; | |||
516 | size_t rlen; | |||
517 | #endif | |||
518 | ||||
519 | int *bufsize; | |||
520 | ||||
521 | #ifdef __APPLE__ | |||
522 | static int maxsockbuf = -1; | |||
523 | #else | |||
524 | static long maxsockbuf = -1; | |||
525 | #endif | |||
526 | #endif | |||
527 | ||||
528 | /* | |||
529 | * IPPROTO/IP_TOS :- | |||
530 | * 1. IPv6 on Solaris/Mac OS: | |||
531 | * Set the TOS OR Traffic Class value to cater for | |||
532 | * IPv6 and IPv4 scenarios. | |||
533 | * 2. IPv6 on Linux: By default Linux ignores flowinfo | |||
534 | * field so enable IPV6_FLOWINFO_SEND so that flowinfo | |||
535 | * will be examined. We also set the IPv4 TOS option in this case. | |||
536 | * 3. IPv4: set socket option based on ToS and Precedence | |||
537 | * fields (otherwise get invalid argument) | |||
538 | */ | |||
539 | if (level == IPPROTO_IPIPPROTO_IP && opt == IP_TOS1) { | |||
540 | int *iptos; | |||
541 | ||||
542 | #if defined(__linux__1) | |||
543 | if (ipv6_available()) { | |||
544 | int optval = 1; | |||
545 | if (setsockopt(fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_FLOWINFO_SEND33, | |||
546 | (void *)&optval, sizeof(optval)) < 0) { | |||
547 | return -1; | |||
548 | } | |||
549 | /* | |||
550 | * Let's also set the IPV6_TCLASS flag. | |||
551 | * Linux appears to allow both IP_TOS and IPV6_TCLASS to be set | |||
552 | * This helps in mixed environments where IPv4 and IPv6 sockets | |||
553 | * are connecting. | |||
554 | */ | |||
555 | if (setsockopt(fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_TCLASS67, | |||
556 | arg, len) < 0) { | |||
557 | return -1; | |||
558 | } | |||
559 | } | |||
560 | #endif | |||
561 | ||||
562 | iptos = (int *)arg; | |||
563 | *iptos &= (IPTOS_TOS_MASK0x1e | IPTOS_PREC_MASK0xe0); | |||
564 | } | |||
565 | ||||
566 | #ifdef _AIX | |||
567 | if (level == SOL_SOCKET1) { | |||
568 | if (opt == SO_SNDBUF7 || opt == SO_RCVBUF8) { | |||
569 | /* | |||
570 | * Just try to set the requested size. If it fails we will leave the | |||
571 | * socket option as is. Setting the buffer size means only a hint in | |||
572 | * the jse2/java software layer, see javadoc. In the previous | |||
573 | * solution the buffer has always been truncated to a length of | |||
574 | * 0x100000 Byte, even if the technical limit has not been reached. | |||
575 | * This kind of absolute truncation was unexpected in the jck tests. | |||
576 | */ | |||
577 | int ret = setsockopt(fd, level, opt, arg, len); | |||
578 | if ((ret == 0) || (ret == -1 && errno(*__errno_location ()) == ENOBUFS105)) { | |||
579 | // Accept failure because of insufficient buffer memory resources. | |||
580 | return 0; | |||
581 | } else { | |||
582 | // Deliver all other kinds of errors. | |||
583 | return ret; | |||
584 | } | |||
585 | } | |||
586 | } | |||
587 | #endif | |||
588 | ||||
589 | /* | |||
590 | * On Linux the receive buffer is used for both socket | |||
591 | * structures and the packet payload. The implication | |||
592 | * is that if SO_RCVBUF is too small then small packets | |||
593 | * must be discarded. | |||
594 | */ | |||
595 | #ifdef __linux__1 | |||
596 | if (level == SOL_SOCKET1 && opt == SO_RCVBUF8) { | |||
597 | int *bufsize = (int *)arg; | |||
598 | if (*bufsize < 1024) { | |||
599 | *bufsize = 1024; | |||
600 | } | |||
601 | } | |||
602 | #endif | |||
603 | ||||
604 | #if defined(_ALLBSD_SOURCE) | |||
605 | /* | |||
606 | * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On FreeBSD need to | |||
607 | * ensure that value is <= kern.ipc.maxsockbuf as otherwise we get | |||
608 | * an ENOBUFS error. | |||
609 | */ | |||
610 | if (level == SOL_SOCKET1) { | |||
611 | if (opt == SO_SNDBUF7 || opt == SO_RCVBUF8) { | |||
612 | #ifdef KIPC_MAXSOCKBUF | |||
613 | if (maxsockbuf == -1) { | |||
614 | mib[0] = CTL_KERN; | |||
615 | mib[1] = KERN_IPC; | |||
616 | mib[2] = KIPC_MAXSOCKBUF; | |||
617 | rlen = sizeof(maxsockbuf); | |||
618 | if (sysctl(mib, 3, &maxsockbuf, &rlen, NULL((void*)0), 0) == -1) | |||
619 | maxsockbuf = 1024; | |||
620 | ||||
621 | #if 1 | |||
622 | /* XXXBSD: This is a hack to workaround mb_max/mb_max_adj | |||
623 | problem. It should be removed when kern.ipc.maxsockbuf | |||
624 | will be real value. */ | |||
625 | maxsockbuf = (maxsockbuf/5)*4; | |||
626 | #endif | |||
627 | } | |||
628 | #elif defined(__OpenBSD__) | |||
629 | maxsockbuf = SB_MAX; | |||
630 | #else | |||
631 | maxsockbuf = 64 * 1024; /* XXX: NetBSD */ | |||
632 | #endif | |||
633 | ||||
634 | bufsize = (int *)arg; | |||
635 | if (*bufsize > maxsockbuf) { | |||
636 | *bufsize = maxsockbuf; | |||
637 | } | |||
638 | ||||
639 | if (opt == SO_RCVBUF8 && *bufsize < 1024) { | |||
640 | *bufsize = 1024; | |||
641 | } | |||
642 | ||||
643 | } | |||
644 | } | |||
645 | #endif | |||
646 | ||||
647 | #if defined(_ALLBSD_SOURCE) || defined(_AIX) | |||
648 | /* | |||
649 | * On Solaris, SO_REUSEADDR will allow multiple datagram | |||
650 | * sockets to bind to the same port. The network jck tests check | |||
651 | * for this "feature", so we need to emulate it by turning on | |||
652 | * SO_REUSEPORT as well for that combination. | |||
653 | */ | |||
654 | if (level == SOL_SOCKET1 && opt == SO_REUSEADDR2) { | |||
655 | int sotype; | |||
656 | socklen_t arglen; | |||
657 | ||||
658 | arglen = sizeof(sotype); | |||
659 | if (getsockopt(fd, SOL_SOCKET1, SO_TYPE3, (void *)&sotype, &arglen) < 0) { | |||
660 | return -1; | |||
661 | } | |||
662 | ||||
663 | if (sotype == SOCK_DGRAMSOCK_DGRAM) { | |||
664 | setsockopt(fd, level, SO_REUSEPORT15, arg, len); | |||
665 | } | |||
666 | } | |||
667 | #endif | |||
668 | ||||
669 | return setsockopt(fd, level, opt, arg, len); | |||
670 | } | |||
671 | ||||
672 | /* | |||
673 | * Wrapper for bind system call - performs any necessary pre/post | |||
674 | * processing to deal with OS specific issues :- | |||
675 | * | |||
676 | * Linux allows a socket to bind to 127.0.0.255 which must be | |||
677 | * caught. | |||
678 | */ | |||
679 | int | |||
680 | NET_Bind(int fd, SOCKETADDRESS *sa, int len) | |||
681 | { | |||
682 | int rv; | |||
683 | int arg, alen; | |||
684 | ||||
685 | #ifdef __linux__1 | |||
686 | /* | |||
687 | * ## get bugId for this issue - goes back to 1.2.2 port ## | |||
688 | * ## When IPv6 is enabled this will be an IPv4-mapped | |||
689 | * ## with family set to AF_INET6 | |||
690 | */ | |||
691 | if (sa->sa.sa_family == AF_INET2) { | |||
692 | if ((ntohl(sa->sa4.sin_addr.s_addr)(__extension__ ({ unsigned int __v, __x = (sa->sa4.sin_addr .s_addr); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff ) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" ( __x)); __v; })) & 0x7f0000ff) == 0x7f0000ff) { | |||
693 | errno(*__errno_location ()) = EADDRNOTAVAIL99; | |||
694 | return -1; | |||
695 | } | |||
696 | } | |||
697 | #endif | |||
698 | ||||
699 | rv = bind(fd, &sa->sa, len); | |||
700 | ||||
701 | return rv; | |||
702 | } | |||
703 | ||||
704 | /** | |||
705 | * Wrapper for poll with timeout on a single file descriptor. | |||
706 | * | |||
707 | * flags (defined in net_util_md.h can be any combination of | |||
708 | * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT. | |||
709 | * | |||
710 | * The function will return when either the socket is ready for one | |||
711 | * of the specified operations or the timeout expired. | |||
712 | * | |||
713 | * It returns the time left from the timeout (possibly 0), or -1 if it expired. | |||
714 | */ | |||
715 | ||||
716 | jint | |||
717 | NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout) | |||
718 | { | |||
719 | jlong prevNanoTime = JVM_NanoTime(env, 0); | |||
720 | jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC1000000; | |||
721 | jint read_rv; | |||
722 | ||||
723 | while (1) { | |||
724 | jlong newNanoTime; | |||
725 | struct pollfd pfd; | |||
726 | pfd.fd = fd; | |||
727 | pfd.events = 0; | |||
728 | if (flags & NET_WAIT_READ0x01) | |||
729 | pfd.events |= POLLIN0x001; | |||
730 | if (flags & NET_WAIT_WRITE0x02) | |||
731 | pfd.events |= POLLOUT0x004; | |||
732 | if (flags & NET_WAIT_CONNECT0x04) | |||
733 | pfd.events |= POLLOUT0x004; | |||
734 | ||||
735 | errno(*__errno_location ()) = 0; | |||
736 | read_rv = NET_Poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC1000000); | |||
737 | ||||
738 | newNanoTime = JVM_NanoTime(env, 0); | |||
739 | nanoTimeout -= (newNanoTime - prevNanoTime); | |||
740 | if (nanoTimeout < NET_NSEC_PER_MSEC1000000) { | |||
741 | return read_rv > 0 ? 0 : -1; | |||
742 | } | |||
743 | prevNanoTime = newNanoTime; | |||
744 | ||||
745 | if (read_rv > 0) { | |||
746 | break; | |||
747 | } | |||
748 | } /* while */ | |||
749 | return (nanoTimeout / NET_NSEC_PER_MSEC1000000); | |||
750 | } |