linux-packaging-mono/external/ikvm/openjdk/java/net/DualStackPlainSocketImpl.java
Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

361 lines
13 KiB
Java

/*
* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.io.FileDescriptor;
/**
* This class defines the plain SocketImpl that is used on Windows platforms
* greater or equal to Windows Vista. These platforms have a dual
* layer TCP/IP stack and can handle both IPv4 and IPV6 through a
* single file descriptor.
*
* @author Chris Hegarty
*/
class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
{
// true if this socket is exclusively bound
private final boolean exclusiveBind;
// emulates SO_REUSEADDR when exclusiveBind is true
private boolean isReuseAddress;
public DualStackPlainSocketImpl(boolean exclBind) {
exclusiveBind = exclBind;
}
public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
this.fd = fd;
exclusiveBind = exclBind;
}
void socketCreate(boolean stream) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
cli.System.Net.Sockets.Socket newfd = socket0(stream, false /*v6 Only*/);
fd.setSocket(newfd);
}
void socketConnect(InetAddress address, int port, int timeout)
throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
int connectResult;
if (timeout <= 0) {
connectResult = connect0(nativefd, address, port);
} else {
configureBlocking(nativefd, false);
try {
connectResult = connect0(nativefd, address, port);
if (connectResult == WOULDBLOCK) {
waitForConnect(nativefd, timeout);
}
} finally {
configureBlocking(nativefd, true);
}
}
/*
* We need to set the local port field. If bind was called
* previous to the connect (by the client) then localport field
* will already be set.
*/
if (localport == 0)
localport = localPort0(nativefd);
}
void socketBind(InetAddress address, int port) throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
bind0(nativefd, address, port, exclusiveBind);
if (port == 0) {
localport = localPort0(nativefd);
} else {
localport = port;
}
this.address = address;
}
void socketListen(int backlog) throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
listen0(nativefd, backlog);
}
void socketAccept(SocketImpl s) throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
if (s == null)
throw new NullPointerException("socket is null");
cli.System.Net.Sockets.Socket newfd = null;
InetSocketAddress[] isaa = new InetSocketAddress[1];
if (timeout <= 0) {
newfd = accept0(nativefd, isaa);
} else {
configureBlocking(nativefd, false);
try {
waitForNewConnection(nativefd, timeout);
newfd = accept0(nativefd, isaa);
if (newfd != null) {
configureBlocking(newfd, true);
}
} finally {
configureBlocking(nativefd, true);
}
}
/* Update (SocketImpl)s' fd */
s.fd.setSocket(newfd);
/* Update socketImpls remote port, address and localport */
InetSocketAddress isa = isaa[0];
s.port = isa.getPort();
s.address = isa.getAddress();
s.localport = localport;
}
int socketAvailable() throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
return available0(nativefd);
}
void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
if (!fd.valid())
return;
close0(fd.getSocket());
fd.setSocket(null);
}
void socketShutdown(int howto) throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
shutdown0(nativefd, howto);
}
// Intentional fallthrough after SO_REUSEADDR
@SuppressWarnings("fallthrough")
void socketSetOption(int opt, boolean on, Object value)
throws SocketException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
if (opt == SO_TIMEOUT) { // timeout implemented through select.
return;
}
int optionValue = 0;
switch(opt) {
case SO_REUSEADDR :
if (exclusiveBind) {
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = on;
return;
}
// intentional fallthrough
case TCP_NODELAY :
case SO_OOBINLINE :
case SO_KEEPALIVE :
optionValue = on ? 1 : 0;
break;
case SO_SNDBUF :
case SO_RCVBUF :
case IP_TOS :
optionValue = ((Integer)value).intValue();
break;
case SO_LINGER :
if (on) {
optionValue = ((Integer)value).intValue();
} else {
optionValue = -1;
}
break;
default :/* shouldn't get here */
throw new SocketException("Option not supported");
}
setIntOption(nativefd, opt, optionValue);
}
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
// SO_BINDADDR is not a socket option.
if (opt == SO_BINDADDR) {
localAddress(nativefd, (InetAddressContainer)iaContainerObj);
return 0; // return value doesn't matter.
}
// SO_REUSEADDR emulated when using exclusive bind
if (opt == SO_REUSEADDR && exclusiveBind)
return isReuseAddress? 1 : -1;
int value = getIntOption(nativefd, opt);
switch (opt) {
case TCP_NODELAY :
case SO_OOBINLINE :
case SO_KEEPALIVE :
case SO_REUSEADDR :
return (value == 0) ? -1 : 1;
}
return value;
}
void socketSendUrgentData(int data) throws IOException {
cli.System.Net.Sockets.Socket nativefd = checkAndReturnNativeFD();
sendOOB(nativefd, data);
}
private cli.System.Net.Sockets.Socket checkAndReturnNativeFD() throws SocketException {
if (fd == null || !fd.valid())
throw new SocketException("Socket closed");
return fd.getSocket();
}
static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
/* Native methods */
static cli.System.Net.Sockets.Socket socket0(boolean stream, boolean v6Only) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
cli.System.Net.Sockets.Socket ret = DualStackPlainSocketImpl_c.socket0(env, stream, v6Only);
env.ThrowPendingException();
return ret;
}
static void bind0(cli.System.Net.Sockets.Socket fd, InetAddress localAddress, int localport,
boolean exclBind)
throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.bind0(env, fd, localAddress, localport, exclBind);
env.ThrowPendingException();
}
static int connect0(cli.System.Net.Sockets.Socket fd, InetAddress remote, int remotePort)
throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
int ret = DualStackPlainSocketImpl_c.connect0(env, fd, remote, remotePort);
env.ThrowPendingException();
return ret;
}
static void waitForConnect(cli.System.Net.Sockets.Socket fd, int timeout) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.waitForConnect(env, fd, timeout);
env.ThrowPendingException();
}
static int localPort0(cli.System.Net.Sockets.Socket fd) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
int ret = DualStackPlainSocketImpl_c.localPort0(env, fd);
env.ThrowPendingException();
return ret;
}
static void localAddress(cli.System.Net.Sockets.Socket fd, InetAddressContainer in) throws SocketException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.localAddress(env, fd, in);
env.ThrowPendingException();
}
static void listen0(cli.System.Net.Sockets.Socket fd, int backlog) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.listen0(env, fd, backlog);
env.ThrowPendingException();
}
static cli.System.Net.Sockets.Socket accept0(cli.System.Net.Sockets.Socket fd, InetSocketAddress[] isaa) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
cli.System.Net.Sockets.Socket ret = DualStackPlainSocketImpl_c.accept0(env, fd, isaa);
env.ThrowPendingException();
return ret;
}
static void waitForNewConnection(cli.System.Net.Sockets.Socket fd, int timeout) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.waitForNewConnection(env, fd, timeout);
env.ThrowPendingException();
}
static int available0(cli.System.Net.Sockets.Socket fd) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
int ret = DualStackPlainSocketImpl_c.available0(env, fd);
env.ThrowPendingException();
return ret;
}
static void close0(cli.System.Net.Sockets.Socket fd) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.close0(env, fd);
env.ThrowPendingException();
}
static void shutdown0(cli.System.Net.Sockets.Socket fd, int howto) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.shutdown0(env, fd, howto);
env.ThrowPendingException();
}
static void setIntOption(cli.System.Net.Sockets.Socket fd, int cmd, int optionValue) throws SocketException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.setIntOption(env, fd, cmd, optionValue);
env.ThrowPendingException();
}
static int getIntOption(cli.System.Net.Sockets.Socket fd, int cmd) throws SocketException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
int ret = DualStackPlainSocketImpl_c.getIntOption(env, fd, cmd);
env.ThrowPendingException();
return ret;
}
static void sendOOB(cli.System.Net.Sockets.Socket fd, int data) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.sendOOB(env, fd, data);
env.ThrowPendingException();
}
static void configureBlocking(cli.System.Net.Sockets.Socket fd, boolean blocking) throws IOException {
ikvm.internal.JNI.JNIEnv env = new ikvm.internal.JNI.JNIEnv();
DualStackPlainSocketImpl_c.configureBlocking(env, fd, blocking);
env.ThrowPendingException();
}
}