1 /* |
1 /* |
2 * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
25 #include "net_util.h" |
25 #include "net_util.h" |
26 |
26 |
27 #include "java_net_DualStackPlainSocketImpl.h" |
27 #include "java_net_DualStackPlainSocketImpl.h" |
28 #include "java_net_SocketOptions.h" |
28 #include "java_net_SocketOptions.h" |
29 |
29 |
30 #define SET_BLOCKING 0 |
30 #define SET_BLOCKING 0 |
31 #define SET_NONBLOCKING 1 |
31 #define SET_NONBLOCKING 1 |
32 |
32 |
33 static jclass isa_class; /* java.net.InetSocketAddress */ |
33 static jclass isa_class; /* java.net.InetSocketAddress */ |
34 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ |
34 static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */ |
35 |
35 |
36 /* |
36 /* |
58 * Class: java_net_DualStackPlainSocketImpl |
58 * Class: java_net_DualStackPlainSocketImpl |
59 * Method: socket0 |
59 * Method: socket0 |
60 * Signature: (ZZ)I |
60 * Signature: (ZZ)I |
61 */ |
61 */ |
62 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0 |
62 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0 |
63 (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) { |
63 (JNIEnv *env, jclass clazz, jboolean stream) { |
64 int fd, rv, opt=0; |
64 int fd, rv, opt=0; |
65 |
65 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); |
66 fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); |
66 int domain = ipv6_available() ? AF_INET6 : AF_INET; |
|
67 |
|
68 fd = NET_Socket(domain, type, 0); |
|
69 |
67 if (fd == INVALID_SOCKET) { |
70 if (fd == INVALID_SOCKET) { |
68 NET_ThrowNew(env, WSAGetLastError(), "create"); |
71 NET_ThrowNew(env, WSAGetLastError(), "create"); |
69 return -1; |
72 return -1; |
70 } |
73 } |
71 |
74 |
72 rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt)); |
75 if (domain == AF_INET6) { |
73 if (rv == SOCKET_ERROR) { |
76 rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, |
74 NET_ThrowNew(env, WSAGetLastError(), "create"); |
77 sizeof(opt)); |
75 } |
78 if (rv == SOCKET_ERROR) { |
76 |
79 NET_ThrowNew(env, WSAGetLastError(), "create"); |
77 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); |
80 closesocket(fd); |
|
81 return -1; |
|
82 } |
|
83 } |
78 |
84 |
79 return fd; |
85 return fd; |
80 } |
86 } |
81 |
87 |
82 /* |
88 /* |
88 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, |
94 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, |
89 jboolean exclBind) |
95 jboolean exclBind) |
90 { |
96 { |
91 SOCKETADDRESS sa; |
97 SOCKETADDRESS sa; |
92 int rv, sa_len = 0; |
98 int rv, sa_len = 0; |
|
99 jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE; |
93 |
100 |
94 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, |
101 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, |
95 &sa_len, JNI_TRUE) != 0) { |
102 &sa_len, v4MappedAddress) != 0) { |
96 return; |
103 return; |
97 } |
104 } |
98 |
105 |
99 rv = NET_WinBind(fd, &sa, sa_len, exclBind); |
106 rv = NET_WinBind(fd, &sa, sa_len, exclBind); |
100 |
107 |
101 if (rv == SOCKET_ERROR) |
108 if (rv == SOCKET_ERROR) |
109 */ |
116 */ |
110 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 |
117 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0 |
111 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { |
118 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) { |
112 SOCKETADDRESS sa; |
119 SOCKETADDRESS sa; |
113 int rv, sa_len = 0; |
120 int rv, sa_len = 0; |
|
121 jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE; |
114 |
122 |
115 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, |
123 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, |
116 &sa_len, JNI_TRUE) != 0) { |
124 &sa_len, v4MappedAddress) != 0) { |
117 return -1; |
125 return -1; |
118 } |
126 } |
119 |
127 |
120 rv = connect(fd, &sa.sa, sa_len); |
128 rv = connect(fd, &sa.sa, sa_len); |
121 if (rv == SOCKET_ERROR) { |
129 if (rv == SOCKET_ERROR) { |
122 int err = WSAGetLastError(); |
130 int err = WSAGetLastError(); |
123 if (err == WSAEWOULDBLOCK) { |
131 if (err == WSAEWOULDBLOCK) { |
124 return java_net_DualStackPlainSocketImpl_WOULDBLOCK; |
132 return java_net_DualStackPlainSocketImpl_WOULDBLOCK; |
125 } else if (err == WSAEADDRNOTAVAIL) { |
133 } else if (err == WSAEADDRNOTAVAIL) { |
126 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", |
134 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", |
127 "connect: Address is invalid on local machine, or port is not valid on remote machine"); |
135 "connect: Address is invalid on local machine," |
|
136 " or port is not valid on remote machine"); |
128 } else { |
137 } else { |
129 NET_ThrowNew(env, err, "connect"); |
138 NET_ThrowNew(env, err, "connect"); |
130 } |
139 } |
131 return -1; // return value not important. |
140 return -1; // return value not important. |
132 } |
141 } |
198 } |
207 } |
199 |
208 |
200 if (rv == 0) { |
209 if (rv == 0) { |
201 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", |
210 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", |
202 "Unable to establish connection"); |
211 "Unable to establish connection"); |
|
212 } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) { |
|
213 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException", |
|
214 "connect: Address is invalid on local machine," |
|
215 " or port is not valid on remote machine"); |
203 } else { |
216 } else { |
204 NET_ThrowNew(env, rv, "connect"); |
217 NET_ThrowNew(env, rv, "connect"); |
205 } |
218 } |
206 } |
219 } |
207 |
220 |
282 |
295 |
283 memset((char *)&sa, 0, len); |
296 memset((char *)&sa, 0, len); |
284 newfd = accept(fd, &sa.sa, &len); |
297 newfd = accept(fd, &sa.sa, &len); |
285 |
298 |
286 if (newfd == INVALID_SOCKET) { |
299 if (newfd == INVALID_SOCKET) { |
287 if (WSAGetLastError() == -2) { |
300 NET_ThrowNew(env, WSAGetLastError(), "accept failed"); |
288 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException", |
|
289 "operation interrupted"); |
|
290 } else { |
|
291 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", |
|
292 "socket closed"); |
|
293 } |
|
294 return -1; |
301 return -1; |
295 } |
302 } |
296 |
303 |
297 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); |
304 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); |
298 |
305 |
299 ia = NET_SockaddrToInetAddress(env, &sa, &port); |
306 ia = NET_SockaddrToInetAddress(env, &sa, &port); |
300 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); |
307 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port); |
|
308 if (isa == NULL) { |
|
309 closesocket(newfd); |
|
310 return -1; |
|
311 } |
301 (*env)->SetObjectArrayElement(env, isaa, 0, isa); |
312 (*env)->SetObjectArrayElement(env, isaa, 0, isa); |
302 |
313 |
303 return newfd; |
314 return newfd; |
304 } |
315 } |
305 |
316 |
400 } |
411 } |
401 } |
412 } |
402 |
413 |
403 /* |
414 /* |
404 * Class: java_net_DualStackPlainSocketImpl |
415 * Class: java_net_DualStackPlainSocketImpl |
|
416 * Method: setSoTimeout0 |
|
417 * Signature: (II)V |
|
418 */ |
|
419 JNIEXPORT void JNICALL |
|
420 Java_java_net_DualStackPlainSocketImpl_setSoTimeout0 |
|
421 (JNIEnv *env, jclass clazz, jint fd, jint timeout) |
|
422 { |
|
423 /* |
|
424 * SO_TIMEOUT is the socket option used to specify the timeout |
|
425 * for ServerSocket.accept and Socket.getInputStream().read. |
|
426 * It does not typically map to a native level socket option. |
|
427 * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO |
|
428 * socket option to specify a receive timeout on the socket. This |
|
429 * receive timeout is applicable to Socket only and the socket |
|
430 * option should not be set on ServerSocket. |
|
431 */ |
|
432 |
|
433 /* |
|
434 * SO_RCVTIMEO is only supported on Microsoft's implementation |
|
435 * of Windows Sockets so if WSAENOPROTOOPT returned then |
|
436 * reset flag and timeout will be implemented using |
|
437 * select() -- see SocketInputStream.socketRead. |
|
438 */ |
|
439 if (isRcvTimeoutSupported) { |
|
440 /* |
|
441 * Disable SO_RCVTIMEO if timeout is <= 5 second. |
|
442 */ |
|
443 if (timeout <= 5000) { |
|
444 timeout = 0; |
|
445 } |
|
446 |
|
447 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, |
|
448 sizeof(timeout)) < 0) { |
|
449 int err = WSAGetLastError(); |
|
450 if (err == WSAENOPROTOOPT) { |
|
451 isRcvTimeoutSupported = JNI_FALSE; |
|
452 } else { |
|
453 NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO"); |
|
454 } |
|
455 } |
|
456 } |
|
457 } |
|
458 |
|
459 /* |
|
460 * Class: java_net_DualStackPlainSocketImpl |
405 * Method: getIntOption |
461 * Method: getIntOption |
406 * Signature: (II)I |
462 * Signature: (II)I |
407 */ |
463 */ |
408 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption |
464 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption |
409 (JNIEnv *env, jclass clazz, jint fd, jint cmd) |
465 (JNIEnv *env, jclass clazz, jint fd, jint cmd) |
464 (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) { |
520 (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) { |
465 u_long arg; |
521 u_long arg; |
466 int result; |
522 int result; |
467 |
523 |
468 if (blocking == JNI_TRUE) { |
524 if (blocking == JNI_TRUE) { |
469 arg = SET_BLOCKING; // 0 |
525 arg = SET_BLOCKING; // 0 |
470 } else { |
526 } else { |
471 arg = SET_NONBLOCKING; // 1 |
527 arg = SET_NONBLOCKING; // 1 |
472 } |
528 } |
473 |
529 |
474 result = ioctlsocket(fd, FIONBIO, &arg); |
530 result = ioctlsocket(fd, FIONBIO, &arg); |