8202091: Rename DualStackPlainSocketImpl to PlainSocketImpl [win]
Reviewed-by: clanger, chegar
--- a/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java Mon Apr 23 07:51:46 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 2007, 2018, 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;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import sun.security.action.GetPropertyAction;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaIOFileDescriptorAccess;
-
-/**
- * This class defines the plain SocketImpl.
- * When java.net.preferIPv4Stack system property is set to true, it uses
- * IPv4-only socket.
- * When java.net.preferIPv4Stack is set to false, it handles both IPv4
- * and IPv6 through a single file descriptor.
- *
- * @author Chris Hegarty
- */
-
-class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
-
- private static final JavaIOFileDescriptorAccess fdAccess =
- SharedSecrets.getJavaIOFileDescriptorAccess();
-
- private static final boolean preferIPv4Stack =
- Boolean.parseBoolean(AccessController.doPrivileged(
- new GetPropertyAction("java.net.preferIPv4Stack", "false")));
-
- /**
- * Empty value of sun.net.useExclusiveBind is treated as 'true'.
- */
- private static final boolean useExclusiveBind;
-
- static {
- String exclBindProp = AccessController.doPrivileged(
- new GetPropertyAction("sun.net.useExclusiveBind", ""));
- useExclusiveBind = exclBindProp.isEmpty()
- || Boolean.parseBoolean(exclBindProp);
- }
-
- // emulates SO_REUSEADDR when useExclusiveBind is true
- private boolean isReuseAddress;
-
- public DualStackPlainSocketImpl() {
- }
-
- public DualStackPlainSocketImpl(FileDescriptor fd) {
- this.fd = fd;
- }
-
- @Override
- void socketCreate(boolean stream) throws IOException {
- if (fd == null)
- throw new SocketException("Socket closed");
-
- int newfd = socket0(stream);
-
- fdAccess.set(fd, newfd);
- }
-
- @Override
- void socketConnect(InetAddress address, int port, int timeout)
- throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- if (address == null)
- throw new NullPointerException("inet address argument is null.");
-
- if (preferIPv4Stack && !(address instanceof Inet4Address))
- throw new SocketException("Protocol family not supported");
-
- 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);
- }
-
- @Override
- void socketBind(InetAddress address, int port) throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- if (address == null)
- throw new NullPointerException("inet address argument is null.");
-
- if (preferIPv4Stack && !(address instanceof Inet4Address))
- throw new SocketException("Protocol family not supported");
-
- bind0(nativefd, address, port, useExclusiveBind);
- if (port == 0) {
- localport = localPort0(nativefd);
- } else {
- localport = port;
- }
-
- this.address = address;
- }
-
- @Override
- void socketListen(int backlog) throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- listen0(nativefd, backlog);
- }
-
- @Override
- void socketAccept(SocketImpl s) throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- if (s == null)
- throw new NullPointerException("socket is null");
-
- int newfd = -1;
- 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 != -1) {
- configureBlocking(newfd, true);
- }
- } finally {
- configureBlocking(nativefd, true);
- }
- }
- /* Update (SocketImpl)s' fd */
- fdAccess.set(s.fd, newfd);
- /* Update socketImpls remote port, address and localport */
- InetSocketAddress isa = isaa[0];
- s.port = isa.getPort();
- s.address = isa.getAddress();
- s.localport = localport;
- if (preferIPv4Stack && !(s.address instanceof Inet4Address))
- throw new SocketException("Protocol family not supported");
- }
-
- @Override
- int socketAvailable() throws IOException {
- int nativefd = checkAndReturnNativeFD();
- return available0(nativefd);
- }
-
- @Override
- void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
- if (fd == null)
- throw new SocketException("Socket closed");
-
- if (!fd.valid())
- return;
-
- final int nativefd = fdAccess.get(fd);
- fdAccess.set(fd, -1);
- close0(nativefd);
- }
-
- @Override
- void socketShutdown(int howto) throws IOException {
- int nativefd = checkAndReturnNativeFD();
- shutdown0(nativefd, howto);
- }
-
- // Intentional fallthrough after SO_REUSEADDR
- @SuppressWarnings("fallthrough")
- @Override
- void socketSetOption(int opt, boolean on, Object value)
- throws SocketException {
-
- // SO_REUSEPORT is not supported on Windows.
- if (opt == SO_REUSEPORT) {
- throw new UnsupportedOperationException("unsupported option");
- }
-
- int nativefd = checkAndReturnNativeFD();
-
- if (opt == SO_TIMEOUT) {
- if (preferIPv4Stack) {
- // Don't enable the socket option on ServerSocket as it's
- // meaningless (we don't receive on a ServerSocket).
- if (serverSocket == null) {
- setSoTimeout0(nativefd, ((Integer)value).intValue());
- }
- } // else timeout is implemented through select.
- return;
- }
-
- int optionValue = 0;
-
- switch(opt) {
- case SO_REUSEADDR:
- if (useExclusiveBind) {
- // 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);
- }
-
- @Override
- int socketGetOption(int opt, Object iaContainerObj)
- throws SocketException {
-
- // SO_REUSEPORT is not supported on Windows.
- if (opt == SO_REUSEPORT) {
- throw new UnsupportedOperationException("unsupported option");
- }
-
- int 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 && useExclusiveBind)
- 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;
- }
-
- @Override
- void socketSendUrgentData(int data) throws IOException {
- int nativefd = checkAndReturnNativeFD();
- sendOOB(nativefd, data);
- }
-
- private int checkAndReturnNativeFD() throws SocketException {
- if (fd == null || !fd.valid())
- throw new SocketException("Socket closed");
-
- return fdAccess.get(fd);
- }
-
- static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
-
- static {
- initIDs();
- }
-
- /* Native methods */
-
- static native void initIDs();
-
- static native int socket0(boolean stream) throws IOException;
-
- static native void bind0(int fd, InetAddress localAddress, int localport,
- boolean exclBind)
- throws IOException;
-
- static native int connect0(int fd, InetAddress remote, int remotePort)
- throws IOException;
-
- static native void waitForConnect(int fd, int timeout) throws IOException;
-
- static native int localPort0(int fd) throws IOException;
-
- static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
-
- static native void listen0(int fd, int backlog) throws IOException;
-
- static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
-
- static native void waitForNewConnection(int fd, int timeout) throws IOException;
-
- static native int available0(int fd) throws IOException;
-
- static native void close0(int fd) throws IOException;
-
- static native void shutdown0(int fd, int howto) throws IOException;
-
- static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
-
- static native void setSoTimeout0(int fd, int timeout) throws SocketException;
-
- static native int getIntOption(int fd, int cmd) throws SocketException;
-
- static native void sendOOB(int fd, int data) throws IOException;
-
- static native void configureBlocking(int fd, boolean blocking) throws IOException;
-}
--- a/src/java.base/windows/classes/java/net/PlainSocketImpl.java Mon Apr 23 07:51:46 2018 -0700
+++ b/src/java.base/windows/classes/java/net/PlainSocketImpl.java Mon Apr 23 08:36:41 2018 -0700
@@ -24,261 +24,335 @@
*/
package java.net;
-import java.io.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.JavaIOFileDescriptorAccess;
-/*
- * This class PlainSocketImpl simply delegates to the appropriate real
- * SocketImpl. We do this because PlainSocketImpl is already extended
- * by SocksSocketImpl.
- * <p>
- * There is one possibility for the real SocketImpl: DualStackPlainSocketImpl.
+/**
+ * On Windows system we simply delegate to native methods.
*
* @author Chris Hegarty
*/
class PlainSocketImpl extends AbstractPlainSocketImpl {
- private AbstractPlainSocketImpl impl;
+
+ private static final JavaIOFileDescriptorAccess fdAccess =
+ SharedSecrets.getJavaIOFileDescriptorAccess();
+
+ private static final boolean preferIPv4Stack =
+ Boolean.parseBoolean(AccessController.doPrivileged(
+ new GetPropertyAction("java.net.preferIPv4Stack", "false")));
+
+ /**
+ * Empty value of sun.net.useExclusiveBind is treated as 'true'.
+ */
+ private static final boolean useExclusiveBind;
+
+ static {
+ String exclBindProp = AccessController.doPrivileged(
+ new GetPropertyAction("sun.net.useExclusiveBind", ""));
+ useExclusiveBind = exclBindProp.isEmpty()
+ || Boolean.parseBoolean(exclBindProp);
+ }
+
+ // emulates SO_REUSEADDR when useExclusiveBind is true
+ private boolean isReuseAddress;
/**
* Constructs an empty instance.
*/
- PlainSocketImpl() {
- impl = new DualStackPlainSocketImpl();
+ public PlainSocketImpl() {
}
/**
* Constructs an instance with the given file descriptor.
*/
- PlainSocketImpl(FileDescriptor fd) {
- impl = new DualStackPlainSocketImpl(fd);
- }
-
- // Override methods in SocketImpl that access impl's fields.
-
- protected FileDescriptor getFileDescriptor() {
- return impl.getFileDescriptor();
+ public PlainSocketImpl(FileDescriptor fd) {
+ this.fd = fd;
}
- protected InetAddress getInetAddress() {
- return impl.getInetAddress();
- }
+ @Override
+ void socketCreate(boolean stream) throws IOException {
+ if (fd == null)
+ throw new SocketException("Socket closed");
- protected int getPort() {
- return impl.getPort();
- }
+ int newfd = socket0(stream);
- protected int getLocalPort() {
- return impl.getLocalPort();
- }
-
- void setSocket(Socket soc) {
- impl.setSocket(soc);
+ fdAccess.set(fd, newfd);
}
- Socket getSocket() {
- return impl.getSocket();
- }
+ @Override
+ void socketConnect(InetAddress address, int port, int timeout)
+ throws IOException {
+ int nativefd = checkAndReturnNativeFD();
- void setServerSocket(ServerSocket soc) {
- impl.setServerSocket(soc);
- }
+ if (address == null)
+ throw new NullPointerException("inet address argument is null.");
- ServerSocket getServerSocket() {
- return impl.getServerSocket();
- }
+ if (preferIPv4Stack && !(address instanceof Inet4Address))
+ throw new SocketException("Protocol family not supported");
- public String toString() {
- return impl.toString();
- }
-
- // Override methods in AbstractPlainSocketImpl that access impl's fields.
-
- protected synchronized void create(boolean stream) throws IOException {
- impl.create(stream);
-
- // set fd to delegate's fd to be compatible with older releases
- this.fd = impl.fd;
- }
-
- protected void connect(String host, int port)
- throws UnknownHostException, IOException
- {
- impl.connect(host, port);
+ 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);
}
- protected void connect(InetAddress address, int port) throws IOException {
- impl.connect(address, port);
- }
+ @Override
+ void socketBind(InetAddress address, int port) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (address == null)
+ throw new NullPointerException("inet address argument is null.");
- protected void connect(SocketAddress address, int timeout) throws IOException {
- impl.connect(address, timeout);
- }
+ if (preferIPv4Stack && !(address instanceof Inet4Address))
+ throw new SocketException("Protocol family not supported");
- public void setOption(int opt, Object val) throws SocketException {
- impl.setOption(opt, val);
+ bind0(nativefd, address, port, useExclusiveBind);
+ if (port == 0) {
+ localport = localPort0(nativefd);
+ } else {
+ localport = port;
+ }
+
+ this.address = address;
}
- public Object getOption(int opt) throws SocketException {
- return impl.getOption(opt);
- }
+ @Override
+ void socketListen(int backlog) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
- synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
- impl.doConnect(address, port, timeout);
- }
-
- protected synchronized void bind(InetAddress address, int lport)
- throws IOException
- {
- impl.bind(address, lport);
+ listen0(nativefd, backlog);
}
- protected synchronized void accept(SocketImpl s) throws IOException {
- if (s instanceof PlainSocketImpl) {
- // pass in the real impl not the wrapper.
- SocketImpl delegate = ((PlainSocketImpl)s).impl;
- delegate.address = new InetAddress();
- delegate.fd = new FileDescriptor();
- impl.accept(delegate);
- // set fd to delegate's fd to be compatible with older releases
- s.fd = delegate.fd;
+ @Override
+ void socketAccept(SocketImpl s) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+
+ if (s == null)
+ throw new NullPointerException("socket is null");
+
+ int newfd = -1;
+ InetSocketAddress[] isaa = new InetSocketAddress[1];
+ if (timeout <= 0) {
+ newfd = accept0(nativefd, isaa);
} else {
- impl.accept(s);
+ configureBlocking(nativefd, false);
+ try {
+ waitForNewConnection(nativefd, timeout);
+ newfd = accept0(nativefd, isaa);
+ if (newfd != -1) {
+ configureBlocking(newfd, true);
+ }
+ } finally {
+ configureBlocking(nativefd, true);
+ }
}
+ /* Update (SocketImpl)s' fd */
+ fdAccess.set(s.fd, newfd);
+ /* Update socketImpls remote port, address and localport */
+ InetSocketAddress isa = isaa[0];
+ s.port = isa.getPort();
+ s.address = isa.getAddress();
+ s.localport = localport;
+ if (preferIPv4Stack && !(s.address instanceof Inet4Address))
+ throw new SocketException("Protocol family not supported");
}
- void setFileDescriptor(FileDescriptor fd) {
- impl.setFileDescriptor(fd);
- }
-
- void setAddress(InetAddress address) {
- impl.setAddress(address);
+ @Override
+ int socketAvailable() throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+ return available0(nativefd);
}
- void setPort(int port) {
- impl.setPort(port);
+ @Override
+ void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
+ if (fd == null)
+ throw new SocketException("Socket closed");
+
+ if (!fd.valid())
+ return;
+
+ final int nativefd = fdAccess.get(fd);
+ fdAccess.set(fd, -1);
+ close0(nativefd);
}
- void setLocalPort(int localPort) {
- impl.setLocalPort(localPort);
- }
-
- protected synchronized InputStream getInputStream() throws IOException {
- return impl.getInputStream();
+ @Override
+ void socketShutdown(int howto) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+ shutdown0(nativefd, howto);
}
- void setInputStream(SocketInputStream in) {
- impl.setInputStream(in);
- }
+ // Intentional fallthrough after SO_REUSEADDR
+ @SuppressWarnings("fallthrough")
+ @Override
+ void socketSetOption(int opt, boolean on, Object value)
+ throws SocketException {
- protected synchronized OutputStream getOutputStream() throws IOException {
- return impl.getOutputStream();
- }
+ // SO_REUSEPORT is not supported on Windows.
+ if (opt == SO_REUSEPORT) {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+
+ int nativefd = checkAndReturnNativeFD();
- protected void close() throws IOException {
- try {
- impl.close();
- } finally {
- // set fd to delegate's fd to be compatible with older releases
- this.fd = null;
+ if (opt == SO_TIMEOUT) {
+ if (preferIPv4Stack) {
+ // Don't enable the socket option on ServerSocket as it's
+ // meaningless (we don't receive on a ServerSocket).
+ if (serverSocket == null) {
+ setSoTimeout0(nativefd, ((Integer)value).intValue());
+ }
+ } // else timeout is implemented through select.
+ return;
}
- }
- void reset() throws IOException {
- try {
- impl.reset();
- } finally {
- // set fd to delegate's fd to be compatible with older releases
- this.fd = null;
- }
- }
+ int optionValue = 0;
- protected void shutdownInput() throws IOException {
- impl.shutdownInput();
- }
-
- protected void shutdownOutput() throws IOException {
- impl.shutdownOutput();
- }
-
- protected void sendUrgentData(int data) throws IOException {
- impl.sendUrgentData(data);
- }
+ switch(opt) {
+ case SO_REUSEADDR:
+ if (useExclusiveBind) {
+ // 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");
+ }
- FileDescriptor acquireFD() {
- return impl.acquireFD();
- }
-
- void releaseFD() {
- impl.releaseFD();
- }
-
- boolean isConnectionReset() {
- return impl.isConnectionReset();
- }
-
- void setConnectionReset() {
- impl.setConnectionReset();
- }
-
- public boolean isClosedOrPending() {
- return impl.isClosedOrPending();
+ setIntOption(nativefd, opt, optionValue);
}
- public int getTimeout() {
- return impl.getTimeout();
- }
+ @Override
+ int socketGetOption(int opt, Object iaContainerObj)
+ throws SocketException {
+
+ // SO_REUSEPORT is not supported on Windows.
+ if (opt == SO_REUSEPORT) {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+
+ int nativefd = checkAndReturnNativeFD();
- // Override methods in AbstractPlainSocketImpl that need to be implemented.
+ // 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 && useExclusiveBind)
+ return isReuseAddress ? 1 : -1;
- void socketCreate(boolean stream) throws IOException {
- impl.socketCreate(stream);
+ 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 socketConnect(InetAddress address, int port, int timeout)
- throws IOException {
- impl.socketConnect(address, port, timeout);
+ @Override
+ void socketSendUrgentData(int data) throws IOException {
+ int nativefd = checkAndReturnNativeFD();
+ sendOOB(nativefd, data);
}
- void socketBind(InetAddress address, int port)
- throws IOException {
- impl.socketBind(address, port);
- }
+ private int checkAndReturnNativeFD() throws SocketException {
+ if (fd == null || !fd.valid())
+ throw new SocketException("Socket closed");
- void socketListen(int count) throws IOException {
- impl.socketListen(count);
- }
-
- void socketAccept(SocketImpl s) throws IOException {
- impl.socketAccept(s);
+ return fdAccess.get(fd);
}
- int socketAvailable() throws IOException {
- return impl.socketAvailable();
- }
+ static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
- void socketClose0(boolean useDeferredClose) throws IOException {
- impl.socketClose0(useDeferredClose);
- }
-
- void socketShutdown(int howto) throws IOException {
- impl.socketShutdown(howto);
+ static {
+ initIDs();
}
- void socketSetOption(int cmd, boolean on, Object value)
- throws SocketException {
- impl.socketSetOption(cmd, on, value);
- }
+ /* Native methods */
+
+ static native void initIDs();
+
+ static native int socket0(boolean stream) throws IOException;
+
+ static native void bind0(int fd, InetAddress localAddress, int localport,
+ boolean exclBind)
+ throws IOException;
- int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
- return impl.socketGetOption(opt, iaContainerObj);
- }
+ static native int connect0(int fd, InetAddress remote, int remotePort)
+ throws IOException;
+
+ static native void waitForConnect(int fd, int timeout) throws IOException;
+
+ static native int localPort0(int fd) throws IOException;
+
+ static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
+
+ static native void listen0(int fd, int backlog) throws IOException;
- void socketSendUrgentData(int data) throws IOException {
- impl.socketSendUrgentData(data);
- }
+ static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
+
+ static native void waitForNewConnection(int fd, int timeout) throws IOException;
+
+ static native int available0(int fd) throws IOException;
+
+ static native void close0(int fd) throws IOException;
+
+ static native void shutdown0(int fd, int howto) throws IOException;
- static boolean isReusePortAvailable() {
- // SO_REUSEPORT is not supported on Windows.
- return false;
- }
+ static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
+
+ static native void setSoTimeout0(int fd, int timeout) throws SocketException;
+
+ static native int getIntOption(int fd, int cmd) throws SocketException;
+
+ static native void sendOOB(int fd, int data) throws IOException;
+
+ static native void configureBlocking(int fd, boolean blocking) throws IOException;
}
--- a/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Mon Apr 23 07:51:46 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,534 +0,0 @@
-/*
- * Copyright (c) 2007, 2018, 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.
- */
-#include "net_util.h"
-
-#include "java_net_DualStackPlainSocketImpl.h"
-#include "java_net_SocketOptions.h"
-
-#define SET_BLOCKING 0
-#define SET_NONBLOCKING 1
-
-static jclass isa_class; /* java.net.InetSocketAddress */
-static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: initIDs
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs
- (JNIEnv *env, jclass clazz) {
-
- jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
- CHECK_NULL(cls);
- isa_class = (*env)->NewGlobalRef(env, cls);
- CHECK_NULL(isa_class);
- isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
- "(Ljava/net/InetAddress;I)V");
- CHECK_NULL(isa_ctorID);
- initInetAddressIDs(env);
-
- // implement read timeout with select.
- isRcvTimeoutSupported = JNI_FALSE;
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: socket0
- * Signature: (ZZ)I
- */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
- (JNIEnv *env, jclass clazz, jboolean stream) {
- int fd, rv, opt=0;
- int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
- int domain = ipv6_available() ? AF_INET6 : AF_INET;
-
- fd = NET_Socket(domain, type, 0);
-
- if (fd == INVALID_SOCKET) {
- NET_ThrowNew(env, WSAGetLastError(), "create");
- return -1;
- }
-
- if (domain == AF_INET6) {
- rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
- sizeof(opt));
- if (rv == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "create");
- closesocket(fd);
- return -1;
- }
- }
-
- return fd;
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: bind0
- * Signature: (ILjava/net/InetAddress;I)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
- (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
- jboolean exclBind)
-{
- SOCKETADDRESS sa;
- int rv, sa_len = 0;
- jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
-
- if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, v4MappedAddress) != 0) {
- return;
- }
-
- rv = NET_WinBind(fd, &sa, sa_len, exclBind);
-
- if (rv == SOCKET_ERROR)
- NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: connect0
- * Signature: (ILjava/net/InetAddress;I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
- (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
- SOCKETADDRESS sa;
- int rv, sa_len = 0;
- jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
-
- if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, v4MappedAddress) != 0) {
- return -1;
- }
-
- rv = connect(fd, &sa.sa, sa_len);
- if (rv == SOCKET_ERROR) {
- int err = WSAGetLastError();
- if (err == WSAEWOULDBLOCK) {
- return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
- } else if (err == WSAEADDRNOTAVAIL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine,"
- " or port is not valid on remote machine");
- } else {
- NET_ThrowNew(env, err, "connect");
- }
- return -1; // return value not important.
- }
- return rv;
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: waitForConnect
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
- (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
- int rv, retry;
- int optlen = sizeof(rv);
- fd_set wr, ex;
- struct timeval t;
-
- FD_ZERO(&wr);
- FD_ZERO(&ex);
- FD_SET(fd, &wr);
- FD_SET(fd, &ex);
- t.tv_sec = timeout / 1000;
- t.tv_usec = (timeout % 1000) * 1000;
-
- /*
- * Wait for timeout, connection established or
- * connection failed.
- */
- rv = select(fd+1, 0, &wr, &ex, &t);
-
- /*
- * Timeout before connection is established/failed so
- * we throw exception and shutdown input/output to prevent
- * socket from being used.
- * The socket should be closed immediately by the caller.
- */
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "connect timed out");
- shutdown( fd, SD_BOTH );
- return;
- }
-
- /*
- * Socket is writable or error occurred. On some Windows editions
- * the socket will appear writable when the connect fails so we
- * check for error rather than writable.
- */
- if (!FD_ISSET(fd, &ex)) {
- return; /* connection established */
- }
-
- /*
- * Connection failed. The logic here is designed to work around
- * bug on Windows NT whereby using getsockopt to obtain the
- * last error (SO_ERROR) indicates there is no error. The workaround
- * on NT is to allow winsock to be scheduled and this is done by
- * yielding and retrying. As yielding is problematic in heavy
- * load conditions we attempt up to 3 times to get the error reason.
- */
- for (retry=0; retry<3; retry++) {
- NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
- (char*)&rv, &optlen);
- if (rv) {
- break;
- }
- Sleep(0);
- }
-
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Unable to establish connection");
- } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine,"
- " or port is not valid on remote machine");
- } else {
- NET_ThrowNew(env, rv, "connect");
- }
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: localPort0
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_localPort0
- (JNIEnv *env, jclass clazz, jint fd) {
- SOCKETADDRESS sa;
- int len = sizeof(sa);
-
- if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
- if (WSAGetLastError() == WSAENOTSOCK) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- } else {
- NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
- }
- return -1;
- }
- return (int) ntohs((u_short)GET_PORT(&sa));
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: localAddress
- * Signature: (ILjava/net/InetAddressContainer;)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_localAddress
- (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
- int port;
- SOCKETADDRESS sa;
- int len = sizeof(sa);
- jobject iaObj;
- jclass iaContainerClass;
- jfieldID iaFieldID;
-
- if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
- return;
- }
- iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
- CHECK_NULL(iaObj);
-
- iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
- iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
- CHECK_NULL(iaFieldID);
- (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
-}
-
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: listen0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0
- (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
- if (listen(fd, backlog) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "listen failed");
- }
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: accept0
- * Signature: (I[Ljava/net/InetSocketAddress;)I
- */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
- (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
- int newfd, port=0;
- jobject isa;
- jobject ia;
- SOCKETADDRESS sa;
- int len = sizeof(sa);
-
- memset((char *)&sa, 0, len);
- newfd = accept(fd, &sa.sa, &len);
-
- if (newfd == INVALID_SOCKET) {
- NET_ThrowNew(env, WSAGetLastError(), "accept failed");
- return -1;
- }
-
- SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
-
- ia = NET_SockaddrToInetAddress(env, &sa, &port);
- isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
- if (isa == NULL) {
- closesocket(newfd);
- return -1;
- }
- (*env)->SetObjectArrayElement(env, isaa, 0, isa);
-
- return newfd;
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: waitForNewConnection
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForNewConnection
- (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
- int rv;
-
- rv = NET_Timeout(fd, timeout);
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Accept timed out");
- } else if (rv == -1) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
- } else if (rv == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- }
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: available0
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_available0
- (JNIEnv *env, jclass clazz, jint fd) {
- jint available = -1;
-
- if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "socket available");
- }
-
- return available;
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: close0
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_close0
- (JNIEnv *env, jclass clazz, jint fd) {
- NET_SocketClose(fd);
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: shutdown0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_shutdown0
- (JNIEnv *env, jclass clazz, jint fd, jint howto) {
- shutdown(fd, howto);
-}
-
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: setIntOption
- * Signature: (III)V
- */
-JNIEXPORT void JNICALL
-Java_java_net_DualStackPlainSocketImpl_setIntOption
- (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
-{
- int level = 0, opt = 0;
- struct linger linger = {0, 0};
- char *parg;
- int arglen;
-
- if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
- JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
- return;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
- parg = (char *)&linger;
- arglen = sizeof(linger);
- if (value >= 0) {
- linger.l_onoff = 1;
- linger.l_linger = (unsigned short)value;
- } else {
- linger.l_onoff = 0;
- linger.l_linger = 0;
- }
- } else {
- parg = (char *)&value;
- arglen = sizeof(value);
- }
-
- if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
- }
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: setSoTimeout0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_java_net_DualStackPlainSocketImpl_setSoTimeout0
- (JNIEnv *env, jclass clazz, jint fd, jint timeout)
-{
- /*
- * SO_TIMEOUT is the socket option used to specify the timeout
- * for ServerSocket.accept and Socket.getInputStream().read.
- * It does not typically map to a native level socket option.
- * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
- * socket option to specify a receive timeout on the socket. This
- * receive timeout is applicable to Socket only and the socket
- * option should not be set on ServerSocket.
- */
-
- /*
- * SO_RCVTIMEO is only supported on Microsoft's implementation
- * of Windows Sockets so if WSAENOPROTOOPT returned then
- * reset flag and timeout will be implemented using
- * select() -- see SocketInputStream.socketRead.
- */
- if (isRcvTimeoutSupported) {
- /*
- * Disable SO_RCVTIMEO if timeout is <= 5 second.
- */
- if (timeout <= 5000) {
- timeout = 0;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
- sizeof(timeout)) < 0) {
- int err = WSAGetLastError();
- if (err == WSAENOPROTOOPT) {
- isRcvTimeoutSupported = JNI_FALSE;
- } else {
- NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
- }
- }
- }
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: getIntOption
- * Signature: (II)I
- */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
- (JNIEnv *env, jclass clazz, jint fd, jint cmd)
-{
- int level = 0, opt = 0;
- int result=0;
- struct linger linger = {0, 0};
- char *arg;
- int arglen;
-
- if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
- JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
- arg = (char *)&linger;
- arglen = sizeof(linger);
- } else {
- arg = (char *)&result;
- arglen = sizeof(result);
- }
-
- if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER)
- return linger.l_onoff ? linger.l_linger : -1;
- else
- return result;
-}
-
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: sendOOB
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_sendOOB
- (JNIEnv *env, jclass clazz, jint fd, jint data) {
- jint n;
- unsigned char d = (unsigned char) data & 0xff;
-
- n = send(fd, (char *)&data, 1, MSG_OOB);
- if (n == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "send");
- }
-}
-
-/*
- * Class: java_net_DualStackPlainSocketImpl
- * Method: configureBlocking
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking
- (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
- u_long arg;
- int result;
-
- if (blocking == JNI_TRUE) {
- arg = SET_BLOCKING; // 0
- } else {
- arg = SET_NONBLOCKING; // 1
- }
-
- result = ioctlsocket(fd, FIONBIO, &arg);
- if (result == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/windows/native/libnet/PlainSocketImpl.c Mon Apr 23 08:36:41 2018 -0700
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ */
+#include "net_util.h"
+
+#include "java_net_PlainSocketImpl.h"
+#include "java_net_SocketOptions.h"
+
+#define SET_BLOCKING 0
+#define SET_NONBLOCKING 1
+
+static jclass isa_class; /* java.net.InetSocketAddress */
+static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_initIDs
+ (JNIEnv *env, jclass clazz) {
+
+ jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
+ CHECK_NULL(cls);
+ isa_class = (*env)->NewGlobalRef(env, cls);
+ CHECK_NULL(isa_class);
+ isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
+ "(Ljava/net/InetAddress;I)V");
+ CHECK_NULL(isa_ctorID);
+ initInetAddressIDs(env);
+
+ // implement read timeout with select.
+ isRcvTimeoutSupported = JNI_FALSE;
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: socket0
+ * Signature: (ZZ)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_socket0
+ (JNIEnv *env, jclass clazz, jboolean stream) {
+ int fd, rv, opt = 0;
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
+
+ fd = NET_Socket(domain, type, 0);
+
+ if (fd == INVALID_SOCKET) {
+ NET_ThrowNew(env, WSAGetLastError(), "create");
+ return -1;
+ }
+
+ if (domain == AF_INET6) {
+ rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
+ sizeof(opt));
+ if (rv == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "create");
+ closesocket(fd);
+ return -1;
+ }
+ }
+
+ return fd;
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: bind0
+ * Signature: (ILjava/net/InetAddress;I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_bind0
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
+ jboolean exclBind)
+{
+ SOCKETADDRESS sa;
+ int rv, sa_len = 0;
+ jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
+ &sa_len, v4MappedAddress) != 0) {
+ return;
+ }
+
+ rv = NET_WinBind(fd, &sa, sa_len, exclBind);
+
+ if (rv == SOCKET_ERROR)
+ NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: connect0
+ * Signature: (ILjava/net/InetAddress;I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_connect0
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
+ SOCKETADDRESS sa;
+ int rv, sa_len = 0;
+ jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
+
+ if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
+ &sa_len, v4MappedAddress) != 0) {
+ return -1;
+ }
+
+ rv = connect(fd, &sa.sa, sa_len);
+ if (rv == SOCKET_ERROR) {
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ return java_net_PlainSocketImpl_WOULDBLOCK;
+ } else if (err == WSAEADDRNOTAVAIL) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
+ "connect: Address is invalid on local machine,"
+ " or port is not valid on remote machine");
+ } else {
+ NET_ThrowNew(env, err, "connect");
+ }
+ // return value not important.
+ }
+ return rv;
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: waitForConnect
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForConnect
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
+ int rv, retry;
+ int optlen = sizeof(rv);
+ fd_set wr, ex;
+ struct timeval t;
+
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(fd, &wr);
+ FD_SET(fd, &ex);
+ t.tv_sec = timeout / 1000;
+ t.tv_usec = (timeout % 1000) * 1000;
+
+ /*
+ * Wait for timeout, connection established or
+ * connection failed.
+ */
+ rv = select(fd+1, 0, &wr, &ex, &t);
+
+ /*
+ * Timeout before connection is established/failed so
+ * we throw exception and shutdown input/output to prevent
+ * socket from being used.
+ * The socket should be closed immediately by the caller.
+ */
+ if (rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "connect timed out");
+ shutdown(fd, SD_BOTH);
+ return;
+ }
+
+ /*
+ * Socket is writable or error occurred. On some Windows editions
+ * the socket will appear writable when the connect fails so we
+ * check for error rather than writable.
+ */
+ if (!FD_ISSET(fd, &ex)) {
+ return; /* connection established */
+ }
+
+ /*
+ * Connection failed. The logic here is designed to work around
+ * bug on Windows NT whereby using getsockopt to obtain the
+ * last error (SO_ERROR) indicates there is no error. The workaround
+ * on NT is to allow winsock to be scheduled and this is done by
+ * yielding and retrying. As yielding is problematic in heavy
+ * load conditions we attempt up to 3 times to get the error reason.
+ */
+ for (retry = 0; retry < 3; retry++) {
+ NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
+ (char*)&rv, &optlen);
+ if (rv) {
+ break;
+ }
+ Sleep(0);
+ }
+
+ if (rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Unable to establish connection");
+ } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
+ "connect: Address is invalid on local machine,"
+ " or port is not valid on remote machine");
+ } else {
+ NET_ThrowNew(env, rv, "connect");
+ }
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: localPort0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_localPort0
+ (JNIEnv *env, jclass clazz, jint fd) {
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+
+ if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
+ if (WSAGetLastError() == WSAENOTSOCK) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ } else {
+ NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
+ }
+ return -1;
+ }
+ return (int) ntohs((u_short)GET_PORT(&sa));
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: localAddress
+ * Signature: (ILjava/net/InetAddressContainer;)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_localAddress
+ (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
+ int port;
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+ jobject iaObj;
+ jclass iaContainerClass;
+ jfieldID iaFieldID;
+
+ if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
+ return;
+ }
+ iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
+ CHECK_NULL(iaObj);
+
+ iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
+ iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
+ CHECK_NULL(iaFieldID);
+ (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: listen0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_listen0
+ (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
+ if (listen(fd, backlog) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "listen failed");
+ }
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: accept0
+ * Signature: (I[Ljava/net/InetSocketAddress;)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_accept0
+ (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
+ int newfd, port = 0;
+ jobject isa;
+ jobject ia;
+ SOCKETADDRESS sa;
+ int len = sizeof(sa);
+
+ memset((char *)&sa, 0, len);
+ newfd = accept(fd, &sa.sa, &len);
+
+ if (newfd == INVALID_SOCKET) {
+ NET_ThrowNew(env, WSAGetLastError(), "accept failed");
+ return -1;
+ }
+
+ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
+
+ ia = NET_SockaddrToInetAddress(env, &sa, &port);
+ isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
+ if (isa == NULL) {
+ closesocket(newfd);
+ return -1;
+ }
+ (*env)->SetObjectArrayElement(env, isaa, 0, isa);
+
+ return newfd;
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: waitForNewConnection
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_waitForNewConnection
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
+ int rv;
+
+ rv = NET_Timeout(fd, timeout);
+ if (rv == 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "Accept timed out");
+ } else if (rv == -1) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
+ } else if (rv == -2) {
+ JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+ "operation interrupted");
+ }
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: available0
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_available0
+ (JNIEnv *env, jclass clazz, jint fd) {
+ jint available = -1;
+
+ if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "socket available");
+ }
+
+ return available;
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: close0
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_close0
+ (JNIEnv *env, jclass clazz, jint fd) {
+ NET_SocketClose(fd);
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: shutdown0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_shutdown0
+ (JNIEnv *env, jclass clazz, jint fd, jint howto) {
+ shutdown(fd, howto);
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: setIntOption
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_setIntOption
+ (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
+{
+ int level = 0, opt = 0;
+ struct linger linger = {0, 0};
+ char *parg;
+ int arglen;
+
+ if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
+ return;
+ }
+
+ if (opt == java_net_SocketOptions_SO_LINGER) {
+ parg = (char *)&linger;
+ arglen = sizeof(linger);
+ if (value >= 0) {
+ linger.l_onoff = 1;
+ linger.l_linger = (unsigned short)value;
+ } else {
+ linger.l_onoff = 0;
+ linger.l_linger = 0;
+ }
+ } else {
+ parg = (char *)&value;
+ arglen = sizeof(value);
+ }
+
+ if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
+ }
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: setSoTimeout0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_PlainSocketImpl_setSoTimeout0
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout)
+{
+ /*
+ * SO_TIMEOUT is the socket option used to specify the timeout
+ * for ServerSocket.accept and Socket.getInputStream().read.
+ * It does not typically map to a native level socket option.
+ * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
+ * socket option to specify a receive timeout on the socket. This
+ * receive timeout is applicable to Socket only and the socket
+ * option should not be set on ServerSocket.
+ */
+
+ /*
+ * SO_RCVTIMEO is only supported on Microsoft's implementation
+ * of Windows Sockets so if WSAENOPROTOOPT returned then
+ * reset flag and timeout will be implemented using
+ * select() -- see SocketInputStream.socketRead.
+ */
+ if (isRcvTimeoutSupported) {
+ /*
+ * Disable SO_RCVTIMEO if timeout is <= 5 second.
+ */
+ if (timeout <= 5000) {
+ timeout = 0;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
+ sizeof(timeout)) < 0) {
+ int err = WSAGetLastError();
+ if (err == WSAENOPROTOOPT) {
+ isRcvTimeoutSupported = JNI_FALSE;
+ } else {
+ NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
+ }
+ }
+ }
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: getIntOption
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_java_net_PlainSocketImpl_getIntOption
+ (JNIEnv *env, jclass clazz, jint fd, jint cmd)
+{
+ int level = 0, opt = 0;
+ int result = 0;
+ struct linger linger = {0, 0};
+ char *arg;
+ int arglen;
+
+ if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
+ JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
+ return -1;
+ }
+
+ if (opt == java_net_SocketOptions_SO_LINGER) {
+ arg = (char *)&linger;
+ arglen = sizeof(linger);
+ } else {
+ arg = (char *)&result;
+ arglen = sizeof(result);
+ }
+
+ if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
+ return -1;
+ }
+
+ if (opt == java_net_SocketOptions_SO_LINGER)
+ return linger.l_onoff ? linger.l_linger : -1;
+ else
+ return result;
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: sendOOB
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_sendOOB
+ (JNIEnv *env, jclass clazz, jint fd, jint data) {
+ jint n;
+ unsigned char d = (unsigned char) data & 0xff;
+
+ n = send(fd, (char *)&data, 1, MSG_OOB);
+ if (n == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "send");
+ }
+}
+
+/*
+ * Class: java_net_PlainSocketImpl
+ * Method: configureBlocking
+ * Signature: (IZ)V
+ */
+JNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_configureBlocking
+ (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
+ u_long arg;
+ int result;
+
+ if (blocking == JNI_TRUE) {
+ arg = SET_BLOCKING; // 0
+ } else {
+ arg = SET_NONBLOCKING; // 1
+ }
+
+ result = ioctlsocket(fd, FIONBIO, &arg);
+ if (result == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
+ }
+}