1 /*
2 * Copyright (c) 2007, 2016, 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
43
44 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
45 CHECK_NULL(cls);
46 isa_class = (*env)->NewGlobalRef(env, cls);
47 CHECK_NULL(isa_class);
48 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
49 "(Ljava/net/InetAddress;I)V");
50 CHECK_NULL(isa_ctorID);
51 initInetAddressIDs(env);
52
53 // implement read timeout with select.
54 isRcvTimeoutSupported = JNI_FALSE;
55 }
56
57 /*
58 * Class: java_net_DualStackPlainSocketImpl
59 * Method: socket0
60 * Signature: (ZZ)I
61 */
62 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
63 (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
64 int fd, rv, opt=0;
65
66 fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
67 if (fd == INVALID_SOCKET) {
68 NET_ThrowNew(env, WSAGetLastError(), "create");
69 return -1;
70 }
71
72 rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
73 if (rv == SOCKET_ERROR) {
74 NET_ThrowNew(env, WSAGetLastError(), "create");
75 }
76
77 SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
78
79 return fd;
80 }
81
82 /*
83 * Class: java_net_DualStackPlainSocketImpl
84 * Method: bind0
85 * Signature: (ILjava/net/InetAddress;I)V
86 */
87 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
88 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
89 jboolean exclBind)
90 {
91 SOCKETADDRESS sa;
92 int rv, sa_len = 0;
93
94 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
95 &sa_len, JNI_TRUE) != 0) {
96 return;
97 }
98
99 rv = NET_WinBind(fd, &sa, sa_len, exclBind);
100
101 if (rv == SOCKET_ERROR)
102 NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
103 }
104
105 /*
106 * Class: java_net_DualStackPlainSocketImpl
107 * Method: connect0
108 * Signature: (ILjava/net/InetAddress;I)I
109 */
110 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
111 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
112 SOCKETADDRESS sa;
113 int rv, sa_len = 0;
114
115 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
116 &sa_len, JNI_TRUE) != 0) {
117 return -1;
118 }
119
120 rv = connect(fd, &sa.sa, sa_len);
121 if (rv == SOCKET_ERROR) {
122 int err = WSAGetLastError();
123 if (err == WSAEWOULDBLOCK) {
124 return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
125 } else if (err == WSAEADDRNOTAVAIL) {
126 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
127 "connect: Address is invalid on local machine, or port is not valid on remote machine");
128 } else {
129 NET_ThrowNew(env, err, "connect");
130 }
131 return -1; // return value not important.
132 }
133 return rv;
134 }
135
136 /*
137 * Class: java_net_DualStackPlainSocketImpl
138 * Method: waitForConnect
139 * Signature: (II)V
140 */
141 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
142 (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
143 int rv, retry;
144 int optlen = sizeof(rv);
145 fd_set wr, ex;
146 struct timeval t;
147
183 /*
184 * Connection failed. The logic here is designed to work around
185 * bug on Windows NT whereby using getsockopt to obtain the
186 * last error (SO_ERROR) indicates there is no error. The workaround
187 * on NT is to allow winsock to be scheduled and this is done by
188 * yielding and retrying. As yielding is problematic in heavy
189 * load conditions we attempt up to 3 times to get the error reason.
190 */
191 for (retry=0; retry<3; retry++) {
192 NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
193 (char*)&rv, &optlen);
194 if (rv) {
195 break;
196 }
197 Sleep(0);
198 }
199
200 if (rv == 0) {
201 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
202 "Unable to establish connection");
203 } else {
204 NET_ThrowNew(env, rv, "connect");
205 }
206 }
207
208 /*
209 * Class: java_net_DualStackPlainSocketImpl
210 * Method: localPort0
211 * Signature: (I)I
212 */
213 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0
214 (JNIEnv *env, jclass clazz, jint fd) {
215 SOCKETADDRESS sa;
216 int len = sizeof(sa);
217
218 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
219 if (WSAGetLastError() == WSAENOTSOCK) {
220 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
221 "Socket closed");
222 } else {
267 }
268 }
269
270 /*
271 * Class: java_net_DualStackPlainSocketImpl
272 * Method: accept0
273 * Signature: (I[Ljava/net/InetSocketAddress;)I
274 */
275 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
276 (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
277 int newfd, port=0;
278 jobject isa;
279 jobject ia;
280 SOCKETADDRESS sa;
281 int len = sizeof(sa);
282
283 memset((char *)&sa, 0, len);
284 newfd = accept(fd, &sa.sa, &len);
285
286 if (newfd == INVALID_SOCKET) {
287 if (WSAGetLastError() == -2) {
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;
295 }
296
297 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
298
299 ia = NET_SockaddrToInetAddress(env, &sa, &port);
300 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
301 (*env)->SetObjectArrayElement(env, isaa, 0, isa);
302
303 return newfd;
304 }
305
306 /*
307 * Class: java_net_DualStackPlainSocketImpl
308 * Method: waitForNewConnection
309 * Signature: (II)V
310 */
311 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection
312 (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
313 int rv;
314
315 rv = NET_Timeout(fd, timeout);
316 if (rv == 0) {
317 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
318 "Accept timed out");
319 } else if (rv == -1) {
320 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
385 arglen = sizeof(linger);
386 if (value >= 0) {
387 linger.l_onoff = 1;
388 linger.l_linger = (unsigned short)value;
389 } else {
390 linger.l_onoff = 0;
391 linger.l_linger = 0;
392 }
393 } else {
394 parg = (char *)&value;
395 arglen = sizeof(value);
396 }
397
398 if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
399 NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
400 }
401 }
402
403 /*
404 * Class: java_net_DualStackPlainSocketImpl
405 * Method: getIntOption
406 * Signature: (II)I
407 */
408 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
409 (JNIEnv *env, jclass clazz, jint fd, jint cmd)
410 {
411 int level = 0, opt = 0;
412 int result=0;
413 struct linger linger = {0, 0};
414 char *arg;
415 int arglen;
416
417 if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
418 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
419 return -1;
420 }
421
422 if (opt == java_net_SocketOptions_SO_LINGER) {
423 arg = (char *)&linger;
424 arglen = sizeof(linger);
|
1 /*
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.
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
43
44 jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
45 CHECK_NULL(cls);
46 isa_class = (*env)->NewGlobalRef(env, cls);
47 CHECK_NULL(isa_class);
48 isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
49 "(Ljava/net/InetAddress;I)V");
50 CHECK_NULL(isa_ctorID);
51 initInetAddressIDs(env);
52
53 // implement read timeout with select.
54 isRcvTimeoutSupported = JNI_FALSE;
55 }
56
57 /*
58 * Class: java_net_DualStackPlainSocketImpl
59 * Method: socket0
60 * Signature: (ZZ)I
61 */
62 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
63 (JNIEnv *env, jclass clazz, jboolean stream) {
64 int fd, rv, opt=0;
65 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
66 int domain = ipv6_available() ? AF_INET6 : AF_INET;
67
68 fd = NET_Socket(domain, type, 0);
69
70 if (fd == INVALID_SOCKET) {
71 NET_ThrowNew(env, WSAGetLastError(), "create");
72 return -1;
73 }
74
75 if (domain == AF_INET6) {
76 rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
77 sizeof(opt));
78 if (rv == SOCKET_ERROR) {
79 NET_ThrowNew(env, WSAGetLastError(), "create");
80 closesocket(fd);
81 return -1;
82 }
83 }
84
85 return fd;
86 }
87
88 /*
89 * Class: java_net_DualStackPlainSocketImpl
90 * Method: bind0
91 * Signature: (ILjava/net/InetAddress;I)V
92 */
93 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
94 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
95 jboolean exclBind)
96 {
97 SOCKETADDRESS sa;
98 int rv, sa_len = 0;
99 jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
100
101 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
102 &sa_len, v4MappedAddress) != 0) {
103 return;
104 }
105
106 rv = NET_WinBind(fd, &sa, sa_len, exclBind);
107
108 if (rv == SOCKET_ERROR)
109 NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
110 }
111
112 /*
113 * Class: java_net_DualStackPlainSocketImpl
114 * Method: connect0
115 * Signature: (ILjava/net/InetAddress;I)I
116 */
117 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
118 (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
119 SOCKETADDRESS sa;
120 int rv, sa_len = 0;
121 jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
122
123 if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
124 &sa_len, v4MappedAddress) != 0) {
125 return -1;
126 }
127
128 rv = connect(fd, &sa.sa, sa_len);
129 if (rv == SOCKET_ERROR) {
130 int err = WSAGetLastError();
131 if (err == WSAEWOULDBLOCK) {
132 return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
133 } else if (err == WSAEADDRNOTAVAIL) {
134 JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
135 "connect: Address is invalid on local machine,"
136 " or port is not valid on remote machine");
137 } else {
138 NET_ThrowNew(env, err, "connect");
139 }
140 return -1; // return value not important.
141 }
142 return rv;
143 }
144
145 /*
146 * Class: java_net_DualStackPlainSocketImpl
147 * Method: waitForConnect
148 * Signature: (II)V
149 */
150 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
151 (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
152 int rv, retry;
153 int optlen = sizeof(rv);
154 fd_set wr, ex;
155 struct timeval t;
156
192 /*
193 * Connection failed. The logic here is designed to work around
194 * bug on Windows NT whereby using getsockopt to obtain the
195 * last error (SO_ERROR) indicates there is no error. The workaround
196 * on NT is to allow winsock to be scheduled and this is done by
197 * yielding and retrying. As yielding is problematic in heavy
198 * load conditions we attempt up to 3 times to get the error reason.
199 */
200 for (retry=0; retry<3; retry++) {
201 NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
202 (char*)&rv, &optlen);
203 if (rv) {
204 break;
205 }
206 Sleep(0);
207 }
208
209 if (rv == 0) {
210 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
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");
216 } else {
217 NET_ThrowNew(env, rv, "connect");
218 }
219 }
220
221 /*
222 * Class: java_net_DualStackPlainSocketImpl
223 * Method: localPort0
224 * Signature: (I)I
225 */
226 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0
227 (JNIEnv *env, jclass clazz, jint fd) {
228 SOCKETADDRESS sa;
229 int len = sizeof(sa);
230
231 if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
232 if (WSAGetLastError() == WSAENOTSOCK) {
233 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
234 "Socket closed");
235 } else {
280 }
281 }
282
283 /*
284 * Class: java_net_DualStackPlainSocketImpl
285 * Method: accept0
286 * Signature: (I[Ljava/net/InetSocketAddress;)I
287 */
288 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
289 (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
290 int newfd, port=0;
291 jobject isa;
292 jobject ia;
293 SOCKETADDRESS sa;
294 int len = sizeof(sa);
295
296 memset((char *)&sa, 0, len);
297 newfd = accept(fd, &sa.sa, &len);
298
299 if (newfd == INVALID_SOCKET) {
300 NET_ThrowNew(env, WSAGetLastError(), "accept failed");
301 return -1;
302 }
303
304 SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
305
306 ia = NET_SockaddrToInetAddress(env, &sa, &port);
307 isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
308 if (isa == NULL) {
309 closesocket(newfd);
310 return -1;
311 }
312 (*env)->SetObjectArrayElement(env, isaa, 0, isa);
313
314 return newfd;
315 }
316
317 /*
318 * Class: java_net_DualStackPlainSocketImpl
319 * Method: waitForNewConnection
320 * Signature: (II)V
321 */
322 JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection
323 (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
324 int rv;
325
326 rv = NET_Timeout(fd, timeout);
327 if (rv == 0) {
328 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
329 "Accept timed out");
330 } else if (rv == -1) {
331 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
396 arglen = sizeof(linger);
397 if (value >= 0) {
398 linger.l_onoff = 1;
399 linger.l_linger = (unsigned short)value;
400 } else {
401 linger.l_onoff = 0;
402 linger.l_linger = 0;
403 }
404 } else {
405 parg = (char *)&value;
406 arglen = sizeof(value);
407 }
408
409 if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
410 NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
411 }
412 }
413
414 /*
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
461 * Method: getIntOption
462 * Signature: (II)I
463 */
464 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
465 (JNIEnv *env, jclass clazz, jint fd, jint cmd)
466 {
467 int level = 0, opt = 0;
468 int result=0;
469 struct linger linger = {0, 0};
470 char *arg;
471 int arglen;
472
473 if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
474 JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
475 return -1;
476 }
477
478 if (opt == java_net_SocketOptions_SO_LINGER) {
479 arg = (char *)&linger;
480 arglen = sizeof(linger);
|