8202091: Rename DualStackPlainSocketImpl to PlainSocketImpl [win]
authorigerasim
Mon, 23 Apr 2018 08:36:41 -0700
changeset 49854 0724da162227
parent 49853 08829995db7c
child 49855 3739e9a5b6b5
8202091: Rename DualStackPlainSocketImpl to PlainSocketImpl [win] Reviewed-by: clanger, chegar
src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java
src/java.base/windows/classes/java/net/PlainSocketImpl.java
src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
src/java.base/windows/native/libnet/PlainSocketImpl.c
--- 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");
+    }
+}