2
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
27
import java.io.FileDescriptor;
28
import static ikvm.internal.JNI.*;
29
import static ikvm.internal.Winsock.*;
30
import static java.net.net_util_md.*;
32
final class DualStackPlainSocketImpl_c
34
private static final int JVM_IO_ERR = -1;
35
private static final int JVM_IO_INTR = -2;
37
private static final int SET_BLOCKING = 0;
38
private static final int SET_NONBLOCKING = 1;
44
#include "java_net_DualStackPlainSocketImpl.h"
46
#define SET_BLOCKING 0
47
#define SET_NONBLOCKING 1
49
static jclass isa_class; /* java.net.InetSocketAddress *-/
50
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) *-/
53
* Class: java_net_DualStackPlainSocketImpl
57
JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs
58
(JNIEnv *env, jclass clazz) {
60
jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
61
isa_class = (*env)->NewGlobalRef(env, cls);
62
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
63
"(Ljava/net/InetAddress;I)V");
65
// implement read timeout with select.
66
isRcvTimeoutSupported = 0;
70
* Class: java_net_DualStackPlainSocketImpl
74
static cli.System.Net.Sockets.Socket socket0
75
(JNIEnv env, boolean stream, boolean v6Only /*unused*/) {
76
cli.System.Net.Sockets.Socket fd;
79
fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
80
if (fd == INVALID_SOCKET) {
81
NET_ThrowNew(env, WSAGetLastError(), "create");
85
rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, opt);
86
if (rv == SOCKET_ERROR) {
87
NET_ThrowNew(env, WSAGetLastError(), "create");
95
* Class: java_net_DualStackPlainSocketImpl
97
* Signature: (ILjava/net/InetAddress;I)V
100
(JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddress iaObj, int port) {
102
sa = new SOCKETADDRESS();
105
if (NET_InetAddressToSockaddr(env, iaObj, port, sa,
110
rv = NET_Bind(fd, sa);
112
if (rv == SOCKET_ERROR)
113
NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind");
117
* Class: java_net_DualStackPlainSocketImpl
119
* Signature: (ILjava/net/InetAddress;I)I
122
(JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddress iaObj, int port) {
124
sa = new SOCKETADDRESS();
127
if (NET_InetAddressToSockaddr(env, iaObj, port, sa,
132
rv = connect(fd, sa);
133
if (rv == SOCKET_ERROR) {
134
int err = WSAGetLastError();
135
if (err == WSAEWOULDBLOCK) {
136
return java.net.DualStackPlainSocketImpl.WOULDBLOCK;
137
} else if (err == WSAEADDRNOTAVAIL) {
138
JNU_ThrowByName(env, JNU_JAVANETPKG+"ConnectException",
139
"connect: Address is invalid on local machine, or port is not valid on remote machine");
141
NET_ThrowNew(env, err, "connect");
143
return -1; // return value not important.
149
* Class: java_net_DualStackPlainSocketImpl
150
* Method: waitForConnect
153
static void waitForConnect
154
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int timeout) {
157
wr = new fd_set(); ex = new fd_set();
158
timeval t = new timeval();
164
t.tv_sec = timeout / 1000;
165
t.tv_usec = (timeout % 1000) * 1000;
168
* Wait for timeout, connection established or
171
rv = select(null, wr, ex, t);
174
* Timeout before connection is established/failed so
175
* we throw exception and shutdown input/output to prevent
176
* socket from being used.
177
* The socket should be closed immediately by the caller.
180
JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException",
181
"connect timed out");
182
shutdown( fd, SD_BOTH );
187
* Socket is writable or error occured. On some Windows editions
188
* the socket will appear writable when the connect fails so we
189
* check for error rather than writable.
191
if (!FD_ISSET(fd, ex)) {
192
return; /* connection established */
196
* Connection failed. The logic here is designed to work around
197
* bug on Windows NT whereby using getsockopt to obtain the
198
* last error (SO_ERROR) indicates there is no error. The workaround
199
* on NT is to allow winsock to be scheduled and this is done by
200
* yielding and retrying. As yielding is problematic in heavy
201
* load conditions we attempt up to 3 times to get the error reason.
203
for (retry=0; retry<3; retry++) {
205
NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
215
JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException",
216
"Unable to establish connection");
218
NET_ThrowNew(env, rv, "connect");
223
* Class: java_net_DualStackPlainSocketImpl
227
static int localPort0
228
(JNIEnv env, cli.System.Net.Sockets.Socket fd) {
230
sa = new SOCKETADDRESS();
232
if (getsockname(fd, sa) == SOCKET_ERROR) {
233
if (WSAGetLastError() == WSAENOTSOCK) {
234
JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException",
237
NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
241
return ntohs(GET_PORT(sa));
245
* Class: java_net_DualStackPlainSocketImpl
246
* Method: localAddress
247
* Signature: (ILjava/net/InetAddressContainer;)V
249
static void localAddress
250
(JNIEnv env, cli.System.Net.Sockets.Socket fd, InetAddressContainer iaContainerObj) {
253
sa = new SOCKETADDRESS();
256
if (getsockname(fd, sa) == SOCKET_ERROR) {
257
NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
260
iaObj = NET_SockaddrToInetAddress(env, sa, port);
262
iaContainerObj.addr = iaObj;
267
* Class: java_net_DualStackPlainSocketImpl
272
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int backlog) {
273
if (listen(fd, backlog) == SOCKET_ERROR) {
274
NET_ThrowNew(env, WSAGetLastError(), "listen failed");
279
* Class: java_net_DualStackPlainSocketImpl
281
* Signature: (I[Ljava/net/InetSocketAddress;)I
283
static cli.System.Net.Sockets.Socket accept0
284
(JNIEnv env, cli.System.Net.Sockets.Socket fd, InetSocketAddress[] isaa) {
285
cli.System.Net.Sockets.Socket newfd;
287
InetSocketAddress isa;
290
sa = new SOCKETADDRESS();
292
newfd = accept(fd, sa);
294
if (newfd == INVALID_SOCKET) {
295
if (WSAGetLastError() == -2) {
296
JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException",
297
"operation interrupted");
299
JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException",
305
ia = NET_SockaddrToInetAddress(env, sa, port);
306
isa = new InetSocketAddress(ia, port[0]);
313
* Class: java_net_DualStackPlainSocketImpl
314
* Method: waitForNewConnection
317
static void waitForNewConnection
318
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int timeout) {
321
rv = NET_Timeout(fd, timeout);
323
JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketTimeoutException",
325
} else if (rv == -1) {
326
JNU_ThrowByName(env, JNU_JAVANETPKG+"SocketException", "socket closed");
327
} else if (rv == -2) {
328
JNU_ThrowByName(env, JNU_JAVAIOPKG+"InterruptedIOException",
329
"operation interrupted");
334
* Class: java_net_DualStackPlainSocketImpl
338
static int available0
339
(JNIEnv env, cli.System.Net.Sockets.Socket fd) {
340
int[] available = { -1 };
342
if ((ioctlsocket(fd, FIONREAD, available)) == SOCKET_ERROR) {
343
NET_ThrowNew(env, WSAGetLastError(), "socket available");
350
* Class: java_net_DualStackPlainSocketImpl
355
(JNIEnv env, cli.System.Net.Sockets.Socket fd) {
360
* Class: java_net_DualStackPlainSocketImpl
364
static void shutdown0
365
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int howto) {
371
* Class: java_net_DualStackPlainSocketImpl
372
* Method: setIntOption
375
static void setIntOption
376
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int cmd, int value) {
383
if (NET_MapSocketOption(cmd, level, opt) < 0) {
385
JNU_JAVANETPKG+"SocketException",
390
if (opt[0] == java.net.SocketOptions.SO_LINGER) {
391
linger = new linger();
394
linger.l_linger = value & 0xFFFF;
404
if (NET_SetSockOpt(fd, level[0], opt[0], optval) < 0) {
405
NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
410
* Class: java_net_DualStackPlainSocketImpl
411
* Method: getIntOption
414
static int getIntOption
415
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int cmd) {
419
int[] result = { 0 };
423
if (NET_MapSocketOption(cmd, level, opt) < 0) {
425
JNU_JAVANETPKG+"SocketException",
426
"Unsupported socket option");
430
if (opt[0] == java.net.SocketOptions.SO_LINGER) {
431
linger = new linger();
438
if (NET_GetSockOpt(fd, level[0], opt[0], optval) < 0) {
439
NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
443
if (opt[0] == java.net.SocketOptions.SO_LINGER)
444
return linger.l_onoff != 0 ? linger.l_linger : -1;
451
* Class: java_net_DualStackPlainSocketImpl
456
(JNIEnv env, cli.System.Net.Sockets.Socket fd, int data) {
459
n = send(fd, new byte[] { (byte)data }, 1, MSG_OOB);
460
if (n == JVM_IO_ERR) {
461
NET_ThrowNew(env, WSAGetLastError(), "send");
462
} else if (n == JVM_IO_INTR) {
463
JNU_ThrowByName(env, "java.io.InterruptedIOException", null);
468
* Class: java_net_DualStackPlainSocketImpl
469
* Method: configureBlocking
472
static void configureBlocking
473
(JNIEnv env, cli.System.Net.Sockets.Socket fd, boolean blocking) {
477
if (blocking == JNI_TRUE) {
478
arg = SET_BLOCKING; // 0
480
arg = SET_NONBLOCKING; // 1
483
result = ioctlsocket(fd, FIONBIO, arg);
484
if (result == SOCKET_ERROR) {
485
NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");