Merge unixdomainchannels
authormichaelm
Fri, 29 Nov 2019 10:02:07 +0000
branchunixdomainchannels
changeset 59322 cfe31d2f935c
parent 59266 bfc8074ea4ef (diff)
parent 59321 5775e4825e58 (current diff)
Merge
--- a/src/java.base/share/classes/java/net/StandardProtocolFamily.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/java/net/StandardProtocolFamily.java	Fri Nov 29 10:02:07 2019 +0000
@@ -41,5 +41,10 @@
     /**
      * Internet Protocol Version 6 (IPv6)
      */
-    INET6
+    INET6,
+
+    /**
+     * Unix domain (AF_UNIX)
+     */
+    UNIX
 }
--- a/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java	Fri Nov 29 10:02:07 2019 +0000
@@ -26,6 +26,8 @@
 package java.nio.channels;
 
 import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.net.StandardProtocolFamily;
 import java.net.ServerSocket;
 import java.net.SocketOption;
 import java.net.SocketAddress;
@@ -35,16 +37,28 @@
 /**
  * A selectable channel for stream-oriented listening sockets.
  *
- * <p> A server-socket channel is created by invoking the {@link #open() open}
- * method of this class.  It is not possible to create a channel for an arbitrary,
+ * <p> A server-socket channel is created by invoking one of the open methods of this class.
+ * It is not possible to create a channel for an arbitrary,
  * pre-existing {@link ServerSocket}. A newly-created server-socket channel is
  * open but not yet bound.  An attempt to invoke the {@link #accept() accept}
  * method of an unbound server-socket channel will cause a {@link NotYetBoundException}
  * to be thrown. A server-socket channel can be bound by invoking one of the
  * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class.
  *
+ * <p>Two kinds of server-socket channel are supported: <i>IP</i> (Internet Protocol)
+ * and <i>Unix Domain</i> depending on which open method is used to create them and which subtype of
+ * {@link SocketAddress} that they support for local and remote addresses.
+ * <i>IP</i> channels are created using {@link #open()}. They use {@link
+ * InetSocketAddress} addresses and support both IPv4 and IPv6 TCP/IP.
+ * <i>Unix Domain</i> channels are created using {@link #open(ProtocolFamily)}
+ * with the family parameter set to {@link StandardProtocolFamily#UNIX}.
+ * They use {@link UnixDomainSocketAddress}es and also
+ * do not support the {@link #socket()} method. Note, it is also possible to
+ * create channels that support either IPv4 or IPv6 only through the
+ * {@link #open(ProtocolFamily)} method.
+ *
  * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
- * setOption} method. Server-socket channels support the following options:
+ * setOption} method. <i>IP</i> server-socket channels support the following options:
  * <blockquote>
  * <table class="striped">
  * <caption style="display:none">Socket options</caption>
@@ -66,11 +80,14 @@
  * </tbody>
  * </table>
  * </blockquote>
+ *
  * Additional (implementation specific) options may also be supported.
  *
  * <p> Server-socket channels are safe for use by multiple concurrent threads.
  * </p>
  *
+ * <p><i>Unix Domain</i> server-socket channels support a subset of the options listed above.
+ *
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  * @since 1.4
@@ -92,7 +109,7 @@
     }
 
     /**
-     * Opens a server-socket channel.
+     * Opens an <i>IP</i> server-socket channel.
      *
      * <p> The new channel is created by invoking the {@link
      * java.nio.channels.spi.SelectorProvider#openServerSocketChannel
@@ -114,6 +131,25 @@
     }
 
     /**
+     * Returns a {@link ServerSocketChannel} of the given protocol family.
+     * Where family is equal to {@link StandardProtocolFamily#INET} or {@link
+     * StandardProtocolFamily#INET6} the returned channel must be bound to an
+     * {@link InetSocketAddress}. If family is {@link StandardProtocolFamily#UNIX}
+     * the returned channel must be bound to a {@link UnixDomainSocketAddress}.
+     *
+     * @param family the protocol family
+     *
+     * @return a ServerSocketChannel
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws UnsupportedAddressTypeException if the protocol family is not supported
+     * @since 14
+     */
+    public static ServerSocketChannel open(ProtocolFamily family) throws IOException {
+        return SelectorProvider.provider().openServerSocketChannel(family);
+    }
+
+    /**
      * Returns an operation set identifying this channel's supported
      * operations.
      *
@@ -150,9 +186,11 @@
      * @throws  ClosedChannelException              {@inheritDoc}
      * @throws  IOException                         {@inheritDoc}
      * @throws  SecurityException
-     *          If a security manager has been installed and its {@link
-     *          SecurityManager#checkListen checkListen} method denies the
-     *          operation
+     *          If a security manager has been installed and its
+     *          {@link SecurityManager#checkListen checkListen} method denies
+     *          the operation for <i>IP</i> channels. Or with <i>Unix Domain</i>
+     *          channels, if the security manager denies "read" or "write"
+     *          {@link java.io.FilePermission} for the local path.
      *
      * @since 1.7
      */
@@ -177,14 +215,22 @@
      * the value {@code 0}, or a negative value, then an implementation specific
      * default is used.
      *
+     * <p> Note, for <i>Unix Domain</i> channels, a file is created in the file-system
+     * with the same path name as this channel's bound {@link UnixDomainSocketAddress}.
+     * This file persists after the channel is closed, and must be removed before
+     * another channel can bind to the same name. <i>Unix Domain</i>
+     * {@code ServerSocketChannels} do not support automatically assigned addresses.
+     *
      * @param   local
-     *          The address to bind the socket, or {@code null} to bind to an
-     *          automatically assigned socket address
+     *          The address to bind the socket, or {@code null} to bind an <i>IP</i> channel to
+     *          an automatically assigned socket address
      * @param   backlog
      *          The maximum number of pending connections
      *
      * @return  This channel
      *
+     * @throws  BindException
+     *          If this is a <i>Unix domain</i> channel and {@code local} is {@code null}
      * @throws  AlreadyBoundException
      *          If the socket is already bound
      * @throws  UnsupportedAddressTypeException
@@ -194,9 +240,11 @@
      * @throws  IOException
      *          If some other I/O error occurs
      * @throws  SecurityException
-     *          If a security manager has been installed and its {@link
-     *          SecurityManager#checkListen checkListen} method denies the
-     *          operation
+     *          If a security manager has been installed and its
+     *          {@link SecurityManager#checkListen checkListen} method denies
+     *          the operation for <i>IP</i> channels; or in the case of <i>Unix Domain</i>
+     *          channels, if the security manager denies "read" or "write"
+     *          {@link java.io.FilePermission} for the local path.
      *
      * @since 1.7
      */
@@ -215,12 +263,15 @@
         throws IOException;
 
     /**
-     * Retrieves a server socket associated with this channel.
+     * Retrieves a server socket associated with this channel if it is an <i>IP</i>
+     * channel. The operation is not supported for <i>Unix Domain</i> channels.
      *
      * <p> The returned object will not declare any public methods that are not
      * declared in the {@link java.net.ServerSocket} class.  </p>
      *
      * @return  A server socket associated with this channel
+     *
+     * @throws UnsupportedOperationException if this is a Unix Domain channel
      */
     public abstract ServerSocket socket();
 
@@ -235,14 +286,19 @@
      * <p> The socket channel returned by this method, if any, will be in
      * blocking mode regardless of the blocking mode of this channel.
      *
-     * <p> This method performs exactly the same security checks as the {@link
-     * java.net.ServerSocket#accept accept} method of the {@link
+     * <p> For <i>IP</i> channels, this method performs exactly the same security checks
+     * as the {@link java.net.ServerSocket#accept accept} method of the {@link
      * java.net.ServerSocket} class.  That is, if a security manager has been
      * installed then for each new connection this method verifies that the
      * address and port number of the connection's remote endpoint are
      * permitted by the security manager's {@link
      * java.lang.SecurityManager#checkAccept checkAccept} method.  </p>
      *
+     * <p> For <i>Unix Domain</i> channels, this method performs a security
+     * manager {@link SecurityManager#checkPermission(Permission)} using
+     * a {@link java.io.FilePermission} constructed with the path from the
+     * remote address and "read,write" as the actions.
+     *
      * @return  The socket channel for the new connection,
      *          or {@code null} if this channel is in non-blocking mode
      *          and no connection is available to be accepted
@@ -275,17 +331,27 @@
 
     /**
      * {@inheritDoc}
+     * Where the channel is bound to a <i>Unix Domain</i> address, the return
+     * value from this method is of type  {@link UnixDomainSocketAddress}.
      * <p>
-     * If there is a security manager set, its {@code checkConnect} method is
+     * If there is a security manager set and this is an <i>IP</i> channel,
+     * {@code checkConnect} method is
      * called with the local address and {@code -1} as its arguments to see
      * if the operation is allowed. If the operation is not allowed,
      * a {@code SocketAddress} representing the
      * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
      * local port of the channel's socket is returned.
+     * <p>
+     * If there is a security manager set and this is a <i>Unix Domain</i> channel,
+     * then {@link SecurityManager#checkPermission(Permission)} is called using
+     * a {@link java.io.FilePermission} constructed with the path from the
+     * local address and "read" as the action. If this check fails
+     * then an unnamed {@link UnixDomainSocketAddress} (with empty pathname)
+     * is returned.
      *
      * @return  The {@code SocketAddress} that the socket is bound to, or the
-     *          {@code SocketAddress} representing the loopback address if
-     *          denied by the security manager, or {@code null} if the
+     *          {@code SocketAddress} representing the loopback address or empty
+     *          pathname if denied by the security manager, or {@code null} if the
      *          channel's socket is not bound
      *
      * @throws  ClosedChannelException     {@inheritDoc}
--- a/src/java.base/share/classes/java/nio/channels/SocketChannel.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/java/nio/channels/SocketChannel.java	Fri Nov 29 10:02:07 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -26,6 +26,9 @@
 package java.nio.channels;
 
 import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.StandardProtocolFamily;
 import java.net.Socket;
 import java.net.SocketOption;
 import java.net.SocketAddress;
@@ -36,8 +39,8 @@
 /**
  * A selectable channel for stream-oriented connecting sockets.
  *
- * <p> A socket channel is created by invoking one of the {@link #open open}
- * methods of this class.  It is not possible to create a channel for an arbitrary,
+ * <p> A socket channel is created by invoking one of the open methods of this class.
+ * It is not possible to create a channel for an arbitrary,
  * pre-existing socket. A newly-created socket channel is open but not yet
  * connected.  An attempt to invoke an I/O operation upon an unconnected
  * channel will cause a {@link NotYetConnectedException} to be thrown.  A
@@ -63,8 +66,20 @@
  * channel, then the blocked thread will receive an {@link
  * AsynchronousCloseException}.
  *
+ * <p>Two kinds of socket channel are supported: <i>IP</i> (Internet Protocol) and
+ * <i>Unix Domain</i> depending on which open method is used to create them and which
+ * subtype of {@link SocketAddress} that they support for local and remote addresses.
+ * <i>IP</i> channels are created using {@link #open()}. They use {@link
+ * InetSocketAddress} addresses and support both IPv4 and IPv6 TCP/IP.
+ * <i>Unix Domain</i> channels are created using {@link #open(ProtocolFamily)}
+ * with the family parameter set to {@link StandardProtocolFamily#UNIX}.
+ * They use {@link UnixDomainSocketAddress}es and also
+ * do not support the {@link #socket()} method. Note, it is also possible to
+ * create channels that support either IPv4 or IPv6 only through the
+ * {@link #open(ProtocolFamily)} method.
+ *
  * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
- * setOption} method. Socket channels support the following options:
+ * setOption} method. <i>IP</i> socket channels support the following options:
  * <blockquote>
  * <table class="striped">
  * <caption style="display:none">Socket options</caption>
@@ -113,6 +128,8 @@
  * or write operation while an invocation of one of these methods is in
  * progress will block until that invocation is complete.  </p>
  *
+ * <p><i>Unix Domain</i> channels support a subset of the options listed above.
+ *
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  * @since 1.4
@@ -124,7 +141,7 @@
 {
 
     /**
-     * Initializes a new instance of this class.
+     * Initializes a new <i>IP</i> instance of this class.
      *
      * @param  provider
      *         The provider that created this channel
@@ -134,7 +151,7 @@
     }
 
     /**
-     * Opens a socket channel.
+     * Opens an <i>IP</i> socket channel.
      *
      * <p> The new channel is created by invoking the {@link
      * java.nio.channels.spi.SelectorProvider#openSocketChannel
@@ -151,12 +168,35 @@
     }
 
     /**
-     * Opens a socket channel and connects it to a remote address.
+     * Returns a {@link SocketChannel} of the given {@link ProtocolFamily}.
+     *
+     * @param family the protocol family
+     *
+     * @return a SocketChannel
      *
-     * <p> This convenience method works as if by invoking the {@link #open()}
+     * @throws IOException if an I/O error occurs
+     * @throws UnsupportedAddressTypeException if the protocol family is not supported
+     * @since 14
+     */
+    public static SocketChannel open(ProtocolFamily family) throws IOException {
+        return SelectorProvider.provider().openSocketChannel(family);
+    }
+
+    /**
+     * Opens a socket channel and connects it to a remote address.
+     * Depending on the type of {@link SocketAddress} supplied, the returned object
+     * is an <i>IP</i> or <i>Unix Domain</i> channel.
+     *
+     * <p> For {@link InetSocketAddress}es this convenience method works as if by invoking the {@link #open()}
      * method, invoking the {@link #connect(SocketAddress) connect} method upon
-     * the resulting socket channel, passing it {@code remote}, and then
-     * returning that channel.  </p>
+     * the resulting socket channel, passing it {@code remote}, which must be an
+     * {@link InetSocketAddress} and then returning that channel.  </p>
+     *
+     * <p> For {@link UnixDomainSocketAddress}es it works as if by invoking the {@link
+     * #open(ProtocolFamily)} method with {@link StandardProtocolFamily#UNIX} as parameter,
+     * invoking the {@link #connect(SocketAddress) connect} method upon
+     * the resulting socket channel, passing it {@code remote}, which must be a
+     * {@link UnixDomainSocketAddress} and then returning that channel.  </p>
      *
      * @param  remote
      *         The remote address to which the new channel is to be connected
@@ -174,7 +214,7 @@
      *          interrupt status
      *
      * @throws  UnresolvedAddressException
-     *          If the given remote address is not fully resolved
+     *          If the given remote is an InetSocketAddress that is not fully resolved
      *
      * @throws  UnsupportedAddressTypeException
      *          If the type of the given remote address is not supported
@@ -189,7 +229,14 @@
     public static SocketChannel open(SocketAddress remote)
         throws IOException
     {
-        SocketChannel sc = open();
+        SocketChannel sc;
+        if (remote instanceof InetSocketAddress)
+            sc = open();
+        else if (remote instanceof UnixDomainSocketAddress)
+            sc = open(StandardProtocolFamily.UNIX);
+        else
+            throw new UnsupportedAddressTypeException();
+
         try {
             sc.connect(remote);
         } catch (Throwable x) {
@@ -225,6 +272,14 @@
     // -- Socket-specific operations --
 
     /**
+     * {@inheritDoc}
+     *
+     * <p> Note, for <i>Unix Domain</i> channels, a file is created in the file-system
+     * with the same name as this channel's bound address. This file persists after
+     * the channel is closed, and must be removed before another channel can bind
+     * to the same name. However, automatically assigned addresses have an empty
+     * pathname, and no corresponding file in the file-system.
+     *
      * @throws  ConnectionPendingException
      *          If a non-blocking connect operation is already in progress on
      *          this channel
@@ -235,7 +290,9 @@
      * @throws  SecurityException
      *          If a security manager has been installed and its
      *          {@link SecurityManager#checkListen checkListen} method denies
-     *          the operation
+     *          the operation for <i>IP</i> channels; or for <i>Unix Domain</i>
+     *          channels, if the security manager denies "read" or "write"
+     *          {@link java.io.FilePermission} for the local path.
      *
      * @since 1.7
      */
@@ -297,12 +354,15 @@
     public abstract SocketChannel shutdownOutput() throws IOException;
 
     /**
-     * Retrieves a socket associated with this channel.
+     * Retrieves a socket associated with this channel if it is an <i>IP</i>
+     * channel. The operation is not supported for <i>Unix Domain</i> channels.
      *
      * <p> The returned object will not declare any public methods that are not
      * declared in the {@link java.net.Socket} class.  </p>
      *
      * @return  A socket associated with this channel
+     *
+     * @throws UnsupportedOperationException is this is a <i>Unix Domain</i> channel
      */
     public abstract Socket socket();
 
@@ -338,12 +398,17 @@
      * method will block until the connection is established or an I/O error
      * occurs.
      *
-     * <p> This method performs exactly the same security checks as the {@link
-     * java.net.Socket} class.  That is, if a security manager has been
+     * <p> For <i>IP</i> channels, this method performs exactly the same security checks
+     * as the {@link java.net.Socket} class.  That is, if a security manager has been
      * installed then this method verifies that its {@link
      * java.lang.SecurityManager#checkConnect checkConnect} method permits
      * connecting to the address and port number of the given remote endpoint.
      *
+     * <p> For <i>Unix Domain</i> channels, this method performs a security
+     * manager {@link SecurityManager#checkPermission(Permission)} using
+     * a {@link java.io.FilePermission} constructed with the path from the
+     * destination address and "read,write" as the actions.
+     *
      * <p> This method may be invoked at any time.  If a read or write
      * operation upon this channel is invoked while an invocation of this
      * method is in progress then that operation will first block until this
@@ -379,7 +444,7 @@
      *          interrupt status
      *
      * @throws  UnresolvedAddressException
-     *          If the given remote address is not fully resolved
+     *          If the given remote address is an InetSocketAddress which is not fully resolved
      *
      * @throws  UnsupportedAddressTypeException
      *          If the type of the given remote address is not supported
@@ -451,6 +516,9 @@
      * socket address then the return value from this method is of type {@link
      * java.net.InetSocketAddress}.
      *
+     * <p> Where the channel is bound and connected to a <i>Unix Domain</i>
+     * address, the returned address is a {@link UnixDomainSocketAddress}
+     *
      * @return  The remote address; {@code null} if the channel's socket is not
      *          connected
      *
@@ -510,16 +578,24 @@
     /**
      * {@inheritDoc}
      * <p>
-     * If there is a security manager set, its {@code checkConnect} method is
+     * If there is a security manager set and this is an <i>IP</i> channel,
+     * {@code checkConnect} method is
      * called with the local address and {@code -1} as its arguments to see
      * if the operation is allowed. If the operation is not allowed,
      * a {@code SocketAddress} representing the
      * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
      * local port of the channel's socket is returned.
+     * <p>
+     * If there is a security manager set and this is a <i>Unix Domain</i> channel,
+     * {@code checkPermission} is called with a {@link FilePermission} whose {@code
+     * path} is the path of the bound address and actions is {@code "read"}
+     * and if the operation is allowed a {@link UnixDomainSocketAddress} 
+     * corresponding to the bound address is returned. If not, then an address with
+     * an empty path is returned.
      *
      * @return  The {@code SocketAddress} that the socket is bound to, or the
-     *          {@code SocketAddress} representing the loopback address if
-     *          denied by the security manager, or {@code null} if the
+     *          {@code SocketAddress} representing the loopback address or an
+     *          empty pathname, if denied by the security manager, or {@code null} if the
      *          channel's socket is not bound
      *
      * @throws  ClosedChannelException     {@inheritDoc}
@@ -527,5 +603,4 @@
      */
     @Override
     public abstract SocketAddress getLocalAddress() throws IOException;
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/nio/channels/UnixDomainSocketAddress.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019, 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.nio.channels;
+
+import java.net.SocketAddress;
+import java.nio.file.Path;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Objects;
+
+/**
+ * An address for a Unix domain {@link SocketChannel} or {@link ServerSocketChannel}.
+ * These addresses contain a String path name, which when bound to a channel,
+ * have an associated file in the file-system with the same name.
+ * <p>
+ * If a channel is automatically bound to a Unix domain address then its address
+ * is unnamed; it has an empty path field, and therefore has no associated
+ * file in the file-system. {@link SocketChannel}s can be automatically bound
+ * in this way, but {@link ServerSocketChannel}s cannot and must be bound to
+ * an explicit address.
+ *
+ * @since 14
+ */
+public class UnixDomainSocketAddress extends SocketAddress {
+
+    static final long serialVersionUID = 9829020419651288L;
+
+    static {
+        if (System.getSecurityManager() == null) {
+            System.loadLibrary("nio");
+        } else {
+            AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                System.loadLibrary("nio");
+                return null;
+            });
+        }
+        init();
+    }
+
+    private final String path;
+
+    /**
+     * Create a named UnixDomainSocketAddress for the given path string.
+     *
+     * @param path the pathname to the socket.
+     *
+     * @throws NullPointerException if path is null
+     */
+    public UnixDomainSocketAddress(String path) {
+        Objects.requireNonNull(path);
+        this.path = path;
+    }
+
+    /**
+     * Create a named UnixDomainSocketAddress for the given path.
+     *
+     * @param path the path to the socket.
+     *
+     * @throws NullPointerException if path is null
+     */
+    public UnixDomainSocketAddress(Path path) {
+        Objects.requireNonNull(path);
+        this.path = path.toString();
+    }
+
+    /**
+     * Return this address's path.
+     *
+     * @return this address's path
+     */
+    public String getPath() {
+        return path;
+    }
+
+    static native void init();
+
+    /**
+     * Returns a hashcode computed from this object's path string.
+     */
+    @Override
+    public int hashCode() {
+        return path.hashCode();
+    }
+
+    /**
+     * Compares this address with another object.
+     *
+     * @return true if the path fields are equal
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (! (o instanceof UnixDomainSocketAddress))
+            return false;
+        UnixDomainSocketAddress that = (UnixDomainSocketAddress)o;
+        return this.path.equals(that.path);
+    }
+
+    /**
+     * Returns a string representation of this {@code UnixDomainSocketAddress}.
+     * The format of the string is {@code "af_unix:<path>"} where {@code <path>}
+     * is this address's path field, which will be empty in the case of an
+     * unnamed socket address.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("af_unix:");
+        if (path != null)
+            sb.append(path);
+        return sb.toString();
+    }
+}
--- a/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java	Fri Nov 29 10:02:07 2019 +0000
@@ -317,8 +317,39 @@
      *
      * @since 1.5
      */
-   public Channel inheritedChannel() throws IOException {
+    public Channel inheritedChannel() throws IOException {
+        return null;
+    }
+
+    /**
+     * Returns a {@link SocketChannel} from the given protocol family.
+     *
+     * @param family the protocol family
+     *
+     * @return a SocketChannel
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws UnsupportedAddressTypeException if the protocol family not supported
+     *
+     * @since 14
+     */
+    public SocketChannel openSocketChannel(ProtocolFamily family) throws IOException {
         return null;
-   }
+    }
 
+    /**
+     * Returns a {@link ServerSocketChannel} from the given protocol family.
+     *
+     * @param family the protocol family
+     *
+     * @return a ServerSocketChannel
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws UnsupportedAddressTypeException if the protocol family not supported
+     *
+     * @since 14
+     */
+    public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) throws IOException {
+        return null;
+    }
 }
--- a/src/java.base/share/classes/sun/net/util/SocketExceptions.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/net/util/SocketExceptions.java	Fri Nov 29 10:02:07 2019 +0000
@@ -28,6 +28,8 @@
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.net.InetSocketAddress;
+import java.nio.channels.UnixDomainSocketAddress;
+import java.net.SocketAddress;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
@@ -51,7 +53,13 @@
      *
      * Only specific IOException subtypes are supported.
      */
-    public static IOException of(IOException e, InetSocketAddress address) {
+    public static IOException of(IOException e, SocketAddress addr) {
+        if (addr instanceof UnixDomainSocketAddress)
+            return ofUnixDomain(e, (UnixDomainSocketAddress)addr);
+        if (!(addr instanceof InetSocketAddress))
+            return e;
+
+        InetSocketAddress address = (InetSocketAddress)addr;
         if (!enhancedExceptionText || address == null)
             return e;
         int port = address.getPort();
@@ -66,6 +74,18 @@
         return create(e, enhancedMsg);
     }
 
+    private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) {
+        if (!enhancedExceptionText || addr == null)
+            return e;
+        String path = addr.getPath();
+        StringBuilder sb = new StringBuilder();
+        sb.append(e.getMessage());
+        sb.append(": ");
+        sb.append(path);
+        String enhancedMsg = sb.toString();
+        return create(e, enhancedMsg);
+    }
+
     // return a new instance of the same type with the given detail
     // msg, or if the type doesn't support detail msgs, return given
     // instance.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/InetServerSocketChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2000, 2019, 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 sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.SocketTimeoutException;
+import java.net.StandardSocketOptions;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import sun.net.NetHooks;
+import sun.net.ext.ExtendedSocketOptions;
+
+/**
+ * An implementation of ServerSocketChannels
+ */
+
+class InetServerSocketChannelImpl
+    extends ServerSocketChannelImpl
+{
+    // set true when exclusive binding is on and SO_REUSEADDR is emulated
+    private boolean isReuseAddress;
+
+    // Our socket adaptor, if any
+    private ServerSocket socket;
+
+    // -- End of fields protected by stateLock
+
+
+    InetServerSocketChannelImpl(SelectorProvider sp) throws IOException {
+        super(sp, Net.serverSocket(true));
+    }
+
+    InetServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
+        throws IOException
+    {
+        super(sp, fd);
+        if (bound) {
+            synchronized (stateLock) {
+                localAddress = Net.localAddress(fd);
+            }
+        }
+    }
+
+    @Override
+    public ServerSocket socket() {
+        synchronized (stateLock) {
+            if (socket == null)
+                socket = ServerSocketAdaptor.create(this);
+            return socket;
+        }
+    }
+
+    @Override
+    public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+        if (!name.type().isInstance(value))
+            throw new IllegalArgumentException("Invalid value '" + value + "'");
+
+        synchronized (stateLock) {
+            ensureOpen();
+
+            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
+                // SO_REUSEADDR emulated when using exclusive bind
+                isReuseAddress = (Boolean)value;
+            } else {
+                // no options that require special handling
+                Net.setSocketOption(fd, Net.UNSPEC, name, value);
+            }
+            return this;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SocketOption<T> name)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            ensureOpen();
+            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
+                // SO_REUSEADDR emulated when using exclusive bind
+                return (T)Boolean.valueOf(isReuseAddress);
+            }
+            // no options that require special handling
+            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SocketOption<?>> defaultOptions() {
+            HashSet<SocketOption<?>> set = new HashSet<>();
+            set.add(StandardSocketOptions.SO_RCVBUF);
+            set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
+            set.addAll(ExtendedSocketOptions.serverSocketOptions());
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            if (localAddress != null)
+                throw new AlreadyBoundException();
+            InetSocketAddress isa = (local == null)
+                                    ? new InetSocketAddress(0)
+                                    : Net.checkAddress(local);
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkListen(isa.getPort());
+            NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
+            Net.bind(fd, isa.getAddress(), isa.getPort());
+            Net.listen(fd, backlog < 1 ? 50 : backlog);
+            localAddress = Net.localAddress(fd);
+        }
+        return this;
+    }
+
+    protected int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] addrs)
+        throws IOException
+    {
+        InetSocketAddress[] a = new InetSocketAddress[1];
+        int n = Net.accept(fd, newfd, a);
+        addrs[0] = a[0];
+        return n;
+    }
+
+    protected SocketAddress getRevealedLocalAddress(SocketAddress addr) {
+        return Net.getRevealedLocalAddress((InetSocketAddress)addr);
+    }
+
+    protected String getRevealedLocalAddressAsString(SocketAddress addr) {
+        return Net.getRevealedLocalAddressAsString((InetSocketAddress)addr);
+    }
+
+
+    protected SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa)
+        throws IOException
+    {
+        InetSocketAddress isa = (InetSocketAddress)sa;
+        try {
+            // newly accepted socket is initially in blocking mode
+            IOUtil.configureBlocking(newfd, true);
+
+            // check permitted to accept connections from the remote address
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
+            }
+            return new InetSocketChannelImpl(provider(), newfd, isa);
+        } catch (Exception e) {
+            nd.close(newfd);
+            throw e;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/InetSocketChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2000, 2019, 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 sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolFamily;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.net.SocketTimeoutException;
+import java.net.StandardProtocolFamily;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import sun.net.ConnectionResetException;
+import sun.net.NetHooks;
+import sun.net.ext.ExtendedSocketOptions;
+import sun.net.util.SocketExceptions;
+
+/**
+ * An implementation of SocketChannels
+ */
+
+class InetSocketChannelImpl extends SocketChannelImpl
+{
+    // set true when exclusive binding is on and SO_REUSEADDR is emulated
+    private boolean isReuseAddress;
+
+    // Constructor for normal connecting sockets
+    //
+    InetSocketChannelImpl(SelectorProvider sp) throws IOException {
+        super(sp);
+    }
+
+    InetSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
+        throws IOException
+    {
+        super(sp, fd);
+        if (bound) {
+            synchronized (stateLock) {
+                this.localAddress = Net.localAddress(fd);
+            }
+        }
+    }
+
+    // Constructor for sockets obtained from server sockets
+    //
+    InetSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress isa)
+        throws IOException
+    {
+        super(sp, fd);
+        synchronized (stateLock) {
+            this.localAddress = Net.localAddress(fd);
+            this.remoteAddress = isa;
+            this.state = ST_CONNECTED;
+        }
+    }
+
+    @Override
+    public SocketAddress getLocalAddress() throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            return Net.getRevealedLocalAddress((InetSocketAddress)localAddress);
+        }
+    }
+
+    @Override
+    public SocketAddress getRemoteAddress() throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            return remoteAddress;
+        }
+    }
+
+    @Override
+    public <T> SocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+        if (!name.type().isInstance(value))
+            throw new IllegalArgumentException("Invalid value '" + value + "'");
+
+        synchronized (stateLock) {
+            ensureOpen();
+
+            if (name == StandardSocketOptions.IP_TOS) {
+                ProtocolFamily family = Net.isIPv6Available() ?
+                    StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+                Net.setSocketOption(fd, family, name, value);
+                return this;
+            }
+
+            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
+                // SO_REUSEADDR emulated when using exclusive bind
+                isReuseAddress = (Boolean)value;
+                return this;
+            }
+
+            // no options that require special handling
+            Net.setSocketOption(fd, name, value);
+            return this;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SocketOption<T> name)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            ensureOpen();
+
+            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
+                // SO_REUSEADDR emulated when using exclusive bind
+                return (T)Boolean.valueOf(isReuseAddress);
+            }
+
+            // special handling for IP_TOS: always return 0 when IPv6
+            if (name == StandardSocketOptions.IP_TOS) {
+                ProtocolFamily family = Net.isIPv6Available() ?
+                    StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+                return (T) Net.getSocketOption(fd, family, name);
+            }
+
+            // no options that require special handling
+            return (T) Net.getSocketOption(fd, name);
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SocketOption<?>> defaultOptions() {
+            HashSet<SocketOption<?>> set = new HashSet<>();
+            set.add(StandardSocketOptions.SO_SNDBUF);
+            set.add(StandardSocketOptions.SO_RCVBUF);
+            set.add(StandardSocketOptions.SO_KEEPALIVE);
+            set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
+            set.add(StandardSocketOptions.SO_LINGER);
+            set.add(StandardSocketOptions.TCP_NODELAY);
+            // additional options required by socket adaptor
+            set.add(StandardSocketOptions.IP_TOS);
+            set.add(ExtendedSocketOption.SO_OOBINLINE);
+            set.addAll(ExtendedSocketOptions.clientSocketOptions());
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public Socket socket() {
+        synchronized (stateLock) {
+            if (socket == null)
+                socket = SocketAdaptor.create(this);
+            return socket;
+        }
+    }
+
+    /**
+     * Writes a byte of out of band data.
+     */
+    int sendOutOfBandData(byte b) throws IOException {
+        writeLock.lock();
+        try {
+            boolean blocking = isBlocking();
+            int n = 0;
+            try {
+                beginWrite(blocking);
+                if (blocking) {
+                    do {
+                        n = Net.sendOOB(fd, b);
+                    } while (n == IOStatus.INTERRUPTED && isOpen());
+                } else {
+                    n = Net.sendOOB(fd, b);
+                }
+            } finally {
+                endWrite(blocking, n > 0);
+                if (n <= 0 && isOutputClosed)
+                    throw new AsynchronousCloseException();
+            }
+            return IOStatus.normalize(n);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public SocketChannel bind(SocketAddress local) throws IOException {
+        readLock.lock();
+        try {
+            writeLock.lock();
+            try {
+                synchronized (stateLock) {
+                    ensureOpen();
+                    if (state == ST_CONNECTIONPENDING)
+                        throw new ConnectionPendingException();
+                    if (localAddress != null)
+                        throw new AlreadyBoundException();
+                    InetSocketAddress isa = (local == null) ?
+                        new InetSocketAddress(0) : Net.checkAddress(local);
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        sm.checkListen(isa.getPort());
+                    }
+                    NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
+                    Net.bind(fd, isa.getAddress(), isa.getPort());
+                    localAddress = Net.localAddress(fd);
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        } finally {
+            readLock.unlock();
+        }
+        return this;
+    }
+
+
+    /**
+     * Checks the remote address to which this channel is to be connected.
+     */
+    @Override
+    protected SocketAddress checkRemote(SocketAddress sa) throws IOException {
+        InetSocketAddress isa = Net.checkAddress(sa);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
+        }
+        if (isa.getAddress().isAnyLocalAddress()) {
+            return new InetSocketAddress(InetAddress.getLocalHost(), isa.getPort());
+        } else {
+            return isa;
+        }
+    }
+
+    @Override
+    protected int connectImpl(FileDescriptor fd, SocketAddress sa) throws IOException {
+        InetSocketAddress isa = (InetSocketAddress)sa;
+        return Net.connect(fd, isa.getAddress(), isa.getPort());
+    }
+
+    @Override
+    protected SocketAddress localAddressImpl(FileDescriptor fd) throws IOException {
+        return Net.localAddress(fd);
+    }
+
+    @Override
+    protected String getRevealedLocalAddressAsString(SocketAddress sa) {
+        InetSocketAddress isa = (InetSocketAddress)sa;
+        return Net.getRevealedLocalAddressAsString(isa);
+    }
+}
--- a/src/java.base/share/classes/sun/nio/ch/Net.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java	Fri Nov 29 10:02:07 2019 +0000
@@ -26,6 +26,7 @@
 package sun.nio.ch;
 
 import java.io.FileDescriptor;
+import java.io.FilePermission;
 import java.io.IOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
@@ -43,6 +44,7 @@
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.NotYetBoundException;
 import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.UnixDomainSocketAddress;
 import java.nio.channels.UnresolvedAddressException;
 import java.nio.channels.UnsupportedAddressTypeException;
 import java.security.AccessController;
@@ -57,6 +59,9 @@
 
     private Net() { }
 
+    private static final boolean unixDomainSupported =
+        unixDomainSocketSupported();
+
     // unspecified protocol family
     static final ProtocolFamily UNSPEC = new ProtocolFamily() {
         public String name() {
@@ -703,6 +708,66 @@
      */
     public static final short POLLIN;
     public static final short POLLOUT;
+
+    public static UnixDomainSocketAddress checkUnixAddress(SocketAddress sa) {
+        if (sa == null)
+            return null;
+        if (!(sa instanceof UnixDomainSocketAddress))
+            throw new UnsupportedAddressTypeException();
+        UnixDomainSocketAddress usa = (UnixDomainSocketAddress)sa;
+        return usa;
+    }
+
+    public static boolean isUnixDomainSupported() {
+        return unixDomainSupported;
+    }
+
+    public static final UnixDomainSocketAddress UNNAMED = new UnixDomainSocketAddress("");
+
+    static UnixDomainSocketAddress getRevealedLocalAddress(UnixDomainSocketAddress addr) {
+        SecurityManager sm = System.getSecurityManager();
+        if (addr == null || sm == null)
+            return addr;
+
+        try{
+            FilePermission p = new FilePermission(addr.getPath(), "read");
+            sm.checkPermission(p);
+            // Security check passed
+        } catch (SecurityException e) {
+            // Return unnamed address only if security check fails
+            addr = UNNAMED;
+        }
+        return addr;
+    }
+
+    static String getRevealedLocalAddressAsString(UnixDomainSocketAddress addr) {
+        return System.getSecurityManager() == null ? addr.toString() :
+                UNNAMED.toString();
+    }
+
+    // -- Socket operations --
+
+    public static FileDescriptor unixDomainSocket() throws IOException {
+        return IOUtil.newFD(unixDomainSocket0());
+    }
+
+    private static native int unixDomainSocket0();
+
+    private static native boolean unixDomainSocketSupported();
+
+    static native void unixDomainBind(FileDescriptor fd, UnixDomainSocketAddress addr)
+        throws IOException;
+
+    static native int unixDomainConnect(FileDescriptor fd, UnixDomainSocketAddress remote)
+        throws IOException;
+
+    static native int unixDomainAccept(FileDescriptor fd,
+                                     FileDescriptor newfd,
+                                     SocketAddress[] isaa)
+        throws IOException;
+
+    public static native UnixDomainSocketAddress localUnixAddress(FileDescriptor fd)
+        throws IOException;
     public static final short POLLERR;
     public static final short POLLHUP;
     public static final short POLLNVAL;
--- a/src/java.base/share/classes/sun/nio/ch/Secrets.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/Secrets.java	Fri Nov 29 10:02:07 2019 +0000
@@ -47,7 +47,7 @@
 
     public static SocketChannel newSocketChannel(FileDescriptor fd) {
         try {
-            return new SocketChannelImpl(provider(), fd, false);
+            return new InetSocketChannelImpl(provider(), fd, false);
         } catch (IOException ioe) {
             throw new AssertionError(ioe);
         }
@@ -55,7 +55,7 @@
 
     public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
         try {
-            return new ServerSocketChannelImpl(provider(), fd, false);
+            return new InetServerSocketChannelImpl(provider(), fd, false);
         } catch (IOException ioe) {
             throw new AssertionError(ioe);
         }
--- a/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -30,6 +30,7 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.ProtocolFamily;
+import java.net.StandardProtocolFamily;
 import java.nio.channels.*;
 import java.nio.channels.spi.*;
 
@@ -53,10 +54,32 @@
     public abstract AbstractSelector openSelector() throws IOException;
 
     public ServerSocketChannel openServerSocketChannel() throws IOException {
-        return new ServerSocketChannelImpl(this);
+        return new InetServerSocketChannelImpl(this);
     }
 
     public SocketChannel openSocketChannel() throws IOException {
-        return new SocketChannelImpl(this);
+        return new InetSocketChannelImpl(this);
+    }
+
+    public SocketChannel openSocketChannel(ProtocolFamily family) throws IOException {
+        // TODO: This doesn't exclusively implement the given family
+        if (family == StandardProtocolFamily.INET || family == StandardProtocolFamily.INET6) {
+            throw new UnsupportedOperationException("This will be supported, but is not implemented yet");
+            //return new InetSocketChannelImpl(this);
+        } else if (family == StandardProtocolFamily.UNIX && Net.isUnixDomainSupported()) {
+            return new UnixDomainSocketChannelImpl(this, Net.unixDomainSocket(), false);
+        } else
+            throw new UnsupportedAddressTypeException();
+    }
+
+    public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) throws IOException {
+        // TODO: This doesn't exclusively implement the given family
+        if (family == StandardProtocolFamily.INET || family == StandardProtocolFamily.INET6) {
+            throw new UnsupportedOperationException("This will be supported, but is not implemented yet");
+            //return new InetServerSocketChannelImpl(this);
+        } else if (family == StandardProtocolFamily.UNIX && Net.isUnixDomainSupported()) {
+            return new UnixDomainServerSocketChannelImpl(this);
+        } else
+            throw new UnsupportedAddressTypeException();
     }
 }
--- a/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Fri Nov 29 10:02:07 2019 +0000
@@ -56,12 +56,12 @@
     extends ServerSocket
 {
     // The channel being adapted
-    private final ServerSocketChannelImpl ssc;
+    private final InetServerSocketChannelImpl ssc;
 
     // Timeout "option" value for accepts
     private volatile int timeout;
 
-    static ServerSocket create(ServerSocketChannelImpl ssc) {
+    static ServerSocket create(InetServerSocketChannelImpl ssc) {
         PrivilegedExceptionAction<ServerSocket> pa = () -> new ServerSocketAdaptor(ssc);
         try {
             return AccessController.doPrivileged(pa);
@@ -70,7 +70,7 @@
         }
     }
 
-    private ServerSocketAdaptor(ServerSocketChannelImpl ssc) {
+    private ServerSocketAdaptor(InetServerSocketChannelImpl ssc) {
         super(DummySocketImpl.create());
         this.ssc = ssc;
     }
@@ -93,7 +93,7 @@
 
     @Override
     public InetAddress getInetAddress() {
-        InetSocketAddress local = ssc.localAddress();
+        InetSocketAddress local = (InetSocketAddress)ssc.localAddress();
         if (local == null) {
             return null;
         } else {
@@ -103,7 +103,7 @@
 
     @Override
     public int getLocalPort() {
-        InetSocketAddress local = ssc.localAddress();
+        InetSocketAddress local = (InetSocketAddress)ssc.localAddress();
         if (local == null) {
             return -1;
         } else {
--- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -55,80 +55,57 @@
  * An implementation of ServerSocketChannels
  */
 
-class ServerSocketChannelImpl
+abstract class ServerSocketChannelImpl
     extends ServerSocketChannel
     implements SelChImpl
 {
     // Used to make native close and configure calls
-    private static final NativeDispatcher nd = new SocketDispatcher();
+    static final NativeDispatcher nd = new SocketDispatcher();
 
     // Our file descriptor
-    private final FileDescriptor fd;
-    private final int fdVal;
+    final FileDescriptor fd;
+    final int fdVal;
 
     // Lock held by thread currently blocked on this channel
-    private final ReentrantLock acceptLock = new ReentrantLock();
+    final ReentrantLock acceptLock = new ReentrantLock();
 
     // Lock held by any thread that modifies the state fields declared below
     // DO NOT invoke a blocking I/O operation while holding this lock!
-    private final Object stateLock = new Object();
+    final Object stateLock = new Object();
 
     // -- The following fields are protected by stateLock
 
     // Channel state, increases monotonically
-    private static final int ST_INUSE = 0;
-    private static final int ST_CLOSING = 1;
-    private static final int ST_CLOSED = 2;
-    private int state;
+    static final int ST_INUSE = 0;
+    static final int ST_CLOSING = 1;
+    static final int ST_CLOSED = 2;
+    int state;
 
     // ID of native thread currently blocked in this channel, for signalling
-    private long thread;
+    long thread;
 
     // Binding
-    private InetSocketAddress localAddress; // null => unbound
-
-    // set true when exclusive binding is on and SO_REUSEADDR is emulated
-    private boolean isReuseAddress;
-
-    // Our socket adaptor, if any
-    private ServerSocket socket;
+    SocketAddress localAddress; // null => unbound
 
     // -- End of fields protected by stateLock
 
-
-    ServerSocketChannelImpl(SelectorProvider sp) {
-        super(sp);
-        this.fd = Net.serverSocket(true);
-        this.fdVal = IOUtil.fdVal(fd);
-    }
-
-    ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
+    ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
         throws IOException
     {
         super(sp);
         this.fd =  fd;
         this.fdVal = IOUtil.fdVal(fd);
-        if (bound) {
-            synchronized (stateLock) {
-                localAddress = Net.localAddress(fd);
-            }
-        }
     }
 
     // @throws ClosedChannelException if channel is closed
-    private void ensureOpen() throws ClosedChannelException {
+    void ensureOpen() throws ClosedChannelException {
         if (!isOpen())
             throw new ClosedChannelException();
     }
 
-    @Override
-    public ServerSocket socket() {
-        synchronized (stateLock) {
-            if (socket == null)
-                socket = ServerSocketAdaptor.create(this);
-            return socket;
-        }
-    }
+    abstract SocketAddress getRevealedLocalAddress(SocketAddress addr);
+
+    abstract String getRevealedLocalAddressAsString(SocketAddress addr);
 
     @Override
     public SocketAddress getLocalAddress() throws IOException {
@@ -136,93 +113,10 @@
             ensureOpen();
             return (localAddress == null)
                     ? null
-                    : Net.getRevealedLocalAddress(localAddress);
-        }
-    }
-
-    @Override
-    public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
-        throws IOException
-    {
-        Objects.requireNonNull(name);
-        if (!supportedOptions().contains(name))
-            throw new UnsupportedOperationException("'" + name + "' not supported");
-        if (!name.type().isInstance(value))
-            throw new IllegalArgumentException("Invalid value '" + value + "'");
-
-        synchronized (stateLock) {
-            ensureOpen();
-
-            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
-                // SO_REUSEADDR emulated when using exclusive bind
-                isReuseAddress = (Boolean)value;
-            } else {
-                // no options that require special handling
-                Net.setSocketOption(fd, Net.UNSPEC, name, value);
-            }
-            return this;
+                    : getRevealedLocalAddress(localAddress);
         }
     }
 
-    @Override
-    @SuppressWarnings("unchecked")
-    public <T> T getOption(SocketOption<T> name)
-        throws IOException
-    {
-        Objects.requireNonNull(name);
-        if (!supportedOptions().contains(name))
-            throw new UnsupportedOperationException("'" + name + "' not supported");
-
-        synchronized (stateLock) {
-            ensureOpen();
-            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
-                // SO_REUSEADDR emulated when using exclusive bind
-                return (T)Boolean.valueOf(isReuseAddress);
-            }
-            // no options that require special handling
-            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
-        }
-    }
-
-    private static class DefaultOptionsHolder {
-        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
-
-        private static Set<SocketOption<?>> defaultOptions() {
-            HashSet<SocketOption<?>> set = new HashSet<>();
-            set.add(StandardSocketOptions.SO_RCVBUF);
-            set.add(StandardSocketOptions.SO_REUSEADDR);
-            if (Net.isReusePortAvailable()) {
-                set.add(StandardSocketOptions.SO_REUSEPORT);
-            }
-            set.addAll(ExtendedSocketOptions.serverSocketOptions());
-            return Collections.unmodifiableSet(set);
-        }
-    }
-
-    @Override
-    public final Set<SocketOption<?>> supportedOptions() {
-        return DefaultOptionsHolder.defaultOptions;
-    }
-
-    @Override
-    public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
-        synchronized (stateLock) {
-            ensureOpen();
-            if (localAddress != null)
-                throw new AlreadyBoundException();
-            InetSocketAddress isa = (local == null)
-                                    ? new InetSocketAddress(0)
-                                    : Net.checkAddress(local);
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null)
-                sm.checkListen(isa.getPort());
-            NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
-            Net.bind(fd, isa.getAddress(), isa.getPort());
-            Net.listen(fd, backlog < 1 ? 50 : backlog);
-            localAddress = Net.localAddress(fd);
-        }
-        return this;
-    }
 
     /**
      * Marks the beginning of an I/O operation that might block.
@@ -262,22 +156,25 @@
         }
     }
 
+    abstract int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] sa)
+        throws IOException;
+
     @Override
     public SocketChannel accept() throws IOException {
         int n = 0;
         FileDescriptor newfd = new FileDescriptor();
-        InetSocketAddress[] isaa = new InetSocketAddress[1];
+        SocketAddress[] isaa = new SocketAddress[1];
 
         acceptLock.lock();
         try {
             boolean blocking = isBlocking();
             try {
                 begin(blocking);
-                n = Net.accept(this.fd, newfd, isaa);
+                n = implAccept(this.fd, newfd, isaa);
                 if (blocking) {
                     while (IOStatus.okayToRetry(n) && isOpen()) {
                         park(Net.POLLIN);
-                        n = Net.accept(this.fd, newfd, isaa);
+                        n = implAccept(this.fd, newfd, isaa);
                     }
                 }
             } finally {
@@ -308,7 +205,7 @@
     SocketChannel blockingAccept(long nanos) throws IOException {
         int n = 0;
         FileDescriptor newfd = new FileDescriptor();
-        InetSocketAddress[] isaa = new InetSocketAddress[1];
+        SocketAddress[] isaa = new SocketAddress[1];
 
         acceptLock.lock();
         try {
@@ -322,14 +219,14 @@
                 lockedConfigureBlocking(false);
                 try {
                     long startNanos = System.nanoTime();
-                    n = Net.accept(fd, newfd, isaa);
+                    n = implAccept(fd, newfd, isaa);
                     while (n == IOStatus.UNAVAILABLE && isOpen()) {
                         long remainingNanos = nanos - (System.nanoTime() - startNanos);
                         if (remainingNanos <= 0) {
                             throw new SocketTimeoutException("Accept timed out");
                         }
                         park(Net.POLLIN, remainingNanos);
-                        n = Net.accept(fd, newfd, isaa);
+                        n = implAccept(fd, newfd, isaa);
                     }
                 } finally {
                     // restore socket to blocking mode (if channel is open)
@@ -346,24 +243,8 @@
         return finishAccept(newfd, isaa[0]);
     }
 
-    private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
-        throws IOException
-    {
-        try {
-            // newly accepted socket is initially in blocking mode
-            IOUtil.configureBlocking(newfd, true);
-
-            // check permitted to accept connections from the remote address
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
-            }
-            return new SocketChannelImpl(provider(), newfd, isa);
-        } catch (Exception e) {
-            nd.close(newfd);
-            throw e;
-        }
-    }
+    abstract SocketChannel finishAccept(FileDescriptor newfd, SocketAddress isa)
+        throws IOException;
 
     @Override
     protected void implConfigureBlocking(boolean block) throws IOException {
@@ -507,7 +388,7 @@
     /**
      * Returns the local address, or null if not bound
      */
-    InetSocketAddress localAddress() {
+    SocketAddress localAddress() {
         synchronized (stateLock) {
             return localAddress;
         }
@@ -576,11 +457,11 @@
             sb.append("closed");
         } else {
             synchronized (stateLock) {
-                InetSocketAddress addr = localAddress;
+                SocketAddress addr = localAddress;
                 if (addr == null) {
                     sb.append("unbound");
                 } else {
-                    sb.append(Net.getRevealedLocalAddressAsString(addr));
+                    sb.append(getRevealedLocalAddressAsString(addr));
                 }
             }
         }
--- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java	Fri Nov 29 10:02:07 2019 +0000
@@ -53,17 +53,17 @@
     extends Socket
 {
     // The channel being adapted
-    private final SocketChannelImpl sc;
+    private final InetSocketChannelImpl sc;
 
     // Timeout "option" value for reads
     private volatile int timeout;
 
-    private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
+    private SocketAdaptor(InetSocketChannelImpl sc) throws SocketException {
         super(DummySocketImpl.create());
         this.sc = sc;
     }
 
-    static Socket create(SocketChannelImpl sc) {
+    static Socket create(InetSocketChannelImpl sc) {
         PrivilegedExceptionAction<Socket> pa = () -> new SocketAdaptor(sc);
         try {
             return AccessController.doPrivileged(pa);
@@ -106,7 +106,7 @@
 
     @Override
     public InetAddress getInetAddress() {
-        InetSocketAddress remote = sc.remoteAddress();
+        InetSocketAddress remote = (InetSocketAddress)sc.remoteAddress();
         if (remote == null) {
             return null;
         } else {
@@ -117,7 +117,7 @@
     @Override
     public InetAddress getLocalAddress() {
         if (sc.isOpen()) {
-            InetSocketAddress local = sc.localAddress();
+            InetSocketAddress local = (InetSocketAddress)sc.localAddress();
             if (local != null) {
                 return Net.getRevealedLocalAddress(local).getAddress();
             }
@@ -127,7 +127,7 @@
 
     @Override
     public int getPort() {
-        InetSocketAddress remote = sc.remoteAddress();
+        InetSocketAddress remote = (InetSocketAddress)sc.remoteAddress();
         if (remote == null) {
             return 0;
         } else {
@@ -137,7 +137,7 @@
 
     @Override
     public int getLocalPort() {
-        InetSocketAddress local = sc.localAddress();
+        InetSocketAddress local = (InetSocketAddress)sc.localAddress();
         if (local == null) {
             return -1;
         } else {
@@ -152,7 +152,7 @@
 
     @Override
     public SocketAddress getLocalSocketAddress() {
-        InetSocketAddress local = sc.localAddress();
+        InetSocketAddress local = (InetSocketAddress)sc.localAddress();
         if (local != null) {
             return Net.getRevealedLocalAddress(local);
         } else {
--- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -64,7 +64,7 @@
  * An implementation of SocketChannels
  */
 
-class SocketChannelImpl
+abstract class SocketChannelImpl
     extends SocketChannel
     implements SelChImpl
 {
@@ -72,49 +72,46 @@
     private static final NativeDispatcher nd = new SocketDispatcher();
 
     // Our file descriptor object
-    private final FileDescriptor fd;
+    final FileDescriptor fd;
     private final int fdVal;
 
     // Lock held by current reading or connecting thread
-    private final ReentrantLock readLock = new ReentrantLock();
+    final ReentrantLock readLock = new ReentrantLock();
 
     // Lock held by current writing or connecting thread
-    private final ReentrantLock writeLock = new ReentrantLock();
+    final ReentrantLock writeLock = new ReentrantLock();
 
     // Lock held by any thread that modifies the state fields declared below
     // DO NOT invoke a blocking I/O operation while holding this lock!
-    private final Object stateLock = new Object();
+    final Object stateLock = new Object();
 
     // Input/Output closed
-    private volatile boolean isInputClosed;
-    private volatile boolean isOutputClosed;
+    volatile boolean isInputClosed;
+    volatile boolean isOutputClosed;
 
     // Connection reset protected by readLock
     private boolean connectionReset;
 
     // -- The following fields are protected by stateLock
 
-    // set true when exclusive binding is on and SO_REUSEADDR is emulated
-    private boolean isReuseAddress;
-
     // State, increases monotonically
-    private static final int ST_UNCONNECTED = 0;
-    private static final int ST_CONNECTIONPENDING = 1;
-    private static final int ST_CONNECTED = 2;
-    private static final int ST_CLOSING = 3;
-    private static final int ST_CLOSED = 4;
-    private volatile int state;  // need stateLock to change
+    static final int ST_UNCONNECTED = 0;
+    static final int ST_CONNECTIONPENDING = 1;
+    static final int ST_CONNECTED = 2;
+    static final int ST_CLOSING = 3;
+    static final int ST_CLOSED = 4;
+    volatile int state;  // need stateLock to change
 
     // IDs of native threads doing reads and writes, for signalling
     private long readerThread;
     private long writerThread;
 
     // Binding
-    private InetSocketAddress localAddress;
-    private InetSocketAddress remoteAddress;
+    SocketAddress localAddress;
+    SocketAddress remoteAddress;
 
     // Socket adaptor, created on demand
-    private Socket socket;
+    Socket socket;
 
     // -- End of fields protected by stateLock
 
@@ -127,32 +124,12 @@
         this.fdVal = IOUtil.fdVal(fd);
     }
 
-    SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
+    SocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
         throws IOException
     {
         super(sp);
         this.fd = fd;
         this.fdVal = IOUtil.fdVal(fd);
-        if (bound) {
-            synchronized (stateLock) {
-                this.localAddress = Net.localAddress(fd);
-            }
-        }
-    }
-
-    // Constructor for sockets obtained from server sockets
-    //
-    SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress isa)
-        throws IOException
-    {
-        super(sp);
-        this.fd = fd;
-        this.fdVal = IOUtil.fdVal(fd);
-        synchronized (stateLock) {
-            this.localAddress = Net.localAddress(fd);
-            this.remoteAddress = isa;
-            this.state = ST_CONNECTED;
-        }
     }
 
     /**
@@ -160,7 +137,7 @@
      *
      * @throws ClosedChannelException if channel is closed (or closing)
      */
-    private void ensureOpen() throws ClosedChannelException {
+    void ensureOpen() throws ClosedChannelException {
         if (!isOpen())
             throw new ClosedChannelException();
     }
@@ -186,119 +163,6 @@
         }
     }
 
-    @Override
-    public Socket socket() {
-        synchronized (stateLock) {
-            if (socket == null)
-                socket = SocketAdaptor.create(this);
-            return socket;
-        }
-    }
-
-    @Override
-    public SocketAddress getLocalAddress() throws IOException {
-        synchronized (stateLock) {
-            ensureOpen();
-            return Net.getRevealedLocalAddress(localAddress);
-        }
-    }
-
-    @Override
-    public SocketAddress getRemoteAddress() throws IOException {
-        synchronized (stateLock) {
-            ensureOpen();
-            return remoteAddress;
-        }
-    }
-
-    @Override
-    public <T> SocketChannel setOption(SocketOption<T> name, T value)
-        throws IOException
-    {
-        Objects.requireNonNull(name);
-        if (!supportedOptions().contains(name))
-            throw new UnsupportedOperationException("'" + name + "' not supported");
-        if (!name.type().isInstance(value))
-            throw new IllegalArgumentException("Invalid value '" + value + "'");
-
-        synchronized (stateLock) {
-            ensureOpen();
-
-            if (name == StandardSocketOptions.IP_TOS) {
-                ProtocolFamily family = Net.isIPv6Available() ?
-                    StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
-                Net.setSocketOption(fd, family, name, value);
-                return this;
-            }
-
-            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
-                // SO_REUSEADDR emulated when using exclusive bind
-                isReuseAddress = (Boolean)value;
-                return this;
-            }
-
-            // no options that require special handling
-            Net.setSocketOption(fd, name, value);
-            return this;
-        }
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <T> T getOption(SocketOption<T> name)
-        throws IOException
-    {
-        Objects.requireNonNull(name);
-        if (!supportedOptions().contains(name))
-            throw new UnsupportedOperationException("'" + name + "' not supported");
-
-        synchronized (stateLock) {
-            ensureOpen();
-
-            if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
-                // SO_REUSEADDR emulated when using exclusive bind
-                return (T)Boolean.valueOf(isReuseAddress);
-            }
-
-            // special handling for IP_TOS: always return 0 when IPv6
-            if (name == StandardSocketOptions.IP_TOS) {
-                ProtocolFamily family = Net.isIPv6Available() ?
-                    StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
-                return (T) Net.getSocketOption(fd, family, name);
-            }
-
-            // no options that require special handling
-            return (T) Net.getSocketOption(fd, name);
-        }
-    }
-
-    private static class DefaultOptionsHolder {
-        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
-
-        private static Set<SocketOption<?>> defaultOptions() {
-            HashSet<SocketOption<?>> set = new HashSet<>();
-            set.add(StandardSocketOptions.SO_SNDBUF);
-            set.add(StandardSocketOptions.SO_RCVBUF);
-            set.add(StandardSocketOptions.SO_KEEPALIVE);
-            set.add(StandardSocketOptions.SO_REUSEADDR);
-            if (Net.isReusePortAvailable()) {
-                set.add(StandardSocketOptions.SO_REUSEPORT);
-            }
-            set.add(StandardSocketOptions.SO_LINGER);
-            set.add(StandardSocketOptions.TCP_NODELAY);
-            // additional options required by socket adaptor
-            set.add(StandardSocketOptions.IP_TOS);
-            set.add(ExtendedSocketOption.SO_OOBINLINE);
-            set.addAll(ExtendedSocketOptions.clientSocketOptions());
-            return Collections.unmodifiableSet(set);
-        }
-    }
-
-    @Override
-    public final Set<SocketOption<?>> supportedOptions() {
-        return DefaultOptionsHolder.defaultOptions;
-    }
-
     /**
      * Marks the beginning of a read operation that might block.
      *
@@ -433,7 +297,7 @@
      * @throws ClosedChannelException if the channel is closed or output shutdown
      * @throws NotYetConnectedException if the channel is not yet connected
      */
-    private void beginWrite(boolean blocking) throws ClosedChannelException {
+    void beginWrite(boolean blocking) throws ClosedChannelException {
         if (blocking) {
             // set hook for Thread.interrupt
             begin();
@@ -456,7 +320,7 @@
      * @throws AsynchronousCloseException if the channel was closed due to this
      * thread being interrupted on a blocking write operation.
      */
-    private void endWrite(boolean blocking, boolean completed)
+    void endWrite(boolean blocking, boolean completed)
         throws AsynchronousCloseException
     {
         if (blocking) {
@@ -529,34 +393,6 @@
         }
     }
 
-    /**
-     * Writes a byte of out of band data.
-     */
-    int sendOutOfBandData(byte b) throws IOException {
-        writeLock.lock();
-        try {
-            boolean blocking = isBlocking();
-            int n = 0;
-            try {
-                beginWrite(blocking);
-                if (blocking) {
-                    do {
-                        n = Net.sendOOB(fd, b);
-                    } while (n == IOStatus.INTERRUPTED && isOpen());
-                } else {
-                    n = Net.sendOOB(fd, b);
-                }
-            } finally {
-                endWrite(blocking, n > 0);
-                if (n <= 0 && isOutputClosed)
-                    throw new AsynchronousCloseException();
-            }
-            return IOStatus.normalize(n);
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
     @Override
     protected void implConfigureBlocking(boolean block) throws IOException {
         readLock.lock();
@@ -605,7 +441,7 @@
     /**
      * Returns the local address, or null if not bound
      */
-    InetSocketAddress localAddress() {
+    SocketAddress localAddress() {
         synchronized (stateLock) {
             return localAddress;
         }
@@ -614,44 +450,13 @@
     /**
      * Returns the remote address, or null if not connected
      */
-    InetSocketAddress remoteAddress() {
+    SocketAddress remoteAddress() {
         synchronized (stateLock) {
             return remoteAddress;
         }
     }
 
     @Override
-    public SocketChannel bind(SocketAddress local) throws IOException {
-        readLock.lock();
-        try {
-            writeLock.lock();
-            try {
-                synchronized (stateLock) {
-                    ensureOpen();
-                    if (state == ST_CONNECTIONPENDING)
-                        throw new ConnectionPendingException();
-                    if (localAddress != null)
-                        throw new AlreadyBoundException();
-                    InetSocketAddress isa = (local == null) ?
-                        new InetSocketAddress(0) : Net.checkAddress(local);
-                    SecurityManager sm = System.getSecurityManager();
-                    if (sm != null) {
-                        sm.checkListen(isa.getPort());
-                    }
-                    NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
-                    Net.bind(fd, isa.getAddress(), isa.getPort());
-                    localAddress = Net.localAddress(fd);
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        } finally {
-            readLock.unlock();
-        }
-        return this;
-    }
-
-    @Override
     public boolean isConnected() {
         return (state == ST_CONNECTED);
     }
@@ -670,7 +475,7 @@
      * @throws ConnectionPendingException is a connection is pending
      * @throws IOException if the pre-connect hook fails
      */
-    private void beginConnect(boolean blocking, InetSocketAddress isa)
+    private void beginConnect(boolean blocking, SocketAddress sa)
         throws IOException
     {
         if (blocking) {
@@ -687,9 +492,11 @@
             assert state == ST_UNCONNECTED;
             this.state = ST_CONNECTIONPENDING;
 
-            if (localAddress == null)
+            if (localAddress == null && sa instanceof InetSocketAddress) {
+                InetSocketAddress isa = (InetSocketAddress)sa;
                 NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
-            remoteAddress = isa;
+            }
+            remoteAddress = sa;
 
             if (blocking) {
                 // record thread so it can be signalled if needed
@@ -705,7 +512,7 @@
      * thread being interrupted on a blocking connect operation.
      * @throws IOException if completed and unable to obtain the local address
      */
-    private void endConnect(boolean blocking, boolean completed)
+    void endConnect(boolean blocking, boolean completed)
         throws IOException
     {
         endRead(blocking, completed);
@@ -713,7 +520,7 @@
         if (completed) {
             synchronized (stateLock) {
                 if (state == ST_CONNECTIONPENDING) {
-                    localAddress = Net.localAddress(fd);
+                    localAddress = localAddressImpl(fd);
                     state = ST_CONNECTED;
                 }
             }
@@ -723,22 +530,13 @@
     /**
      * Checks the remote address to which this channel is to be connected.
      */
-    private InetSocketAddress checkRemote(SocketAddress sa) throws IOException {
-        InetSocketAddress isa = Net.checkAddress(sa);
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
-        }
-        if (isa.getAddress().isAnyLocalAddress()) {
-            return new InetSocketAddress(InetAddress.getLocalHost(), isa.getPort());
-        } else {
-            return isa;
-        }
-    }
+    abstract SocketAddress checkRemote(SocketAddress sa) throws IOException;
+
+    abstract int connectImpl(FileDescriptor fd,SocketAddress sa) throws IOException;
 
     @Override
     public boolean connect(SocketAddress remote) throws IOException {
-        InetSocketAddress isa = checkRemote(remote);
+        SocketAddress sa = checkRemote(remote);
         try {
             readLock.lock();
             try {
@@ -747,8 +545,8 @@
                     boolean blocking = isBlocking();
                     boolean connected = false;
                     try {
-                        beginConnect(blocking, isa);
-                        int n = Net.connect(fd, isa.getAddress(), isa.getPort());
+                        beginConnect(blocking, sa);
+                        int n = connectImpl(fd, sa);
                         if (n > 0) {
                             connected = true;
                         } else if (blocking) {
@@ -773,7 +571,7 @@
         } catch (IOException ioe) {
             // connect failed, close the channel
             close();
-            throw SocketExceptions.of(ioe, isa);
+            throw SocketExceptions.of(ioe, sa);
         }
     }
 
@@ -799,6 +597,9 @@
         }
     }
 
+    abstract SocketAddress localAddressImpl(FileDescriptor fd)
+        throws IOException;
+
     /**
      * Marks the end of a finishConnect operation that may have blocked.
      *
@@ -814,7 +615,7 @@
         if (completed) {
             synchronized (stateLock) {
                 if (state == ST_CONNECTIONPENDING) {
-                    localAddress = Net.localAddress(fd);
+                    localAddress = localAddressImpl(fd);
                     state = ST_CONNECTED;
                 }
             }
@@ -1053,7 +854,7 @@
      * @throws SocketTimeoutException if the read timeout elapses
      */
     void blockingConnect(SocketAddress remote, long nanos) throws IOException {
-        InetSocketAddress isa = checkRemote(remote);
+        SocketAddress sa = checkRemote(remote);
         try {
             readLock.lock();
             try {
@@ -1063,11 +864,11 @@
                         throw new IllegalBlockingModeException();
                     boolean connected = false;
                     try {
-                        beginConnect(true, isa);
+                        beginConnect(true, sa);
                         // change socket to non-blocking
                         lockedConfigureBlocking(false);
                         try {
-                            int n = Net.connect(fd, isa.getAddress(), isa.getPort());
+                            int n = connectImpl(fd, sa);
                             connected = (n > 0) ? true : finishTimedConnect(nanos);
                         } finally {
                             // restore socket to blocking mode (if channel is open)
@@ -1085,7 +886,7 @@
         } catch (IOException ioe) {
             // connect failed, close the channel
             close();
-            throw SocketExceptions.of(ioe, isa);
+            throw SocketExceptions.of(ioe, sa);
         }
     }
 
@@ -1328,6 +1129,8 @@
         return fdVal;
     }
 
+    abstract String getRevealedLocalAddressAsString(SocketAddress sa);
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -1352,10 +1155,10 @@
                         sb.append(" oshut");
                     break;
                 }
-                InetSocketAddress addr = localAddress();
+                SocketAddress addr = localAddress();
                 if (addr != null) {
                     sb.append(" local=");
-                    sb.append(Net.getRevealedLocalAddressAsString(addr));
+                    sb.append(getRevealedLocalAddressAsString(addr));
                 }
                 if (remoteAddress() != null) {
                     sb.append(" remote=");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainServerSocketChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2000, 2019, 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 sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.BindException;
+import java.net.ServerSocket;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.SocketTimeoutException;
+import java.net.StandardProtocolFamily;
+import java.net.StandardSocketOptions;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnixDomainSocketAddress;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import sun.net.NetHooks;
+import sun.net.ext.ExtendedSocketOptions;
+
+/**
+ * An implementation of ServerSocketChannels
+ */
+
+public class UnixDomainServerSocketChannelImpl
+    extends ServerSocketChannelImpl
+{
+    static {
+        // register with InheritedChannel mechanism so it can create instances
+        // not yet sun.nio.ch.InheritedChannel.register(UnixDomainServerSocketChannelImpl::create);
+    }
+
+    public UnixDomainServerSocketChannelImpl(SelectorProvider sp) throws IOException {
+        super(sp, Net.unixDomainSocket());
+    }
+
+    public UnixDomainServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
+        throws IOException
+    {
+        super(sp, fd);
+        if (bound) {
+            synchronized (stateLock) {
+                localAddress = Net.localUnixAddress(fd);
+            }
+        }
+    }
+
+    @Override
+    public ServerSocket socket() {
+        throw new UnsupportedOperationException("socket not supported");
+    }
+
+    @Override
+    public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+        if (!name.type().isInstance(value))
+            throw new IllegalArgumentException("Invalid value '" + value + "'");
+
+        synchronized (stateLock) {
+            ensureOpen();
+            // no options that require special handling
+            Net.setSocketOption(fd, Net.UNSPEC, name, value);
+            return this;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SocketOption<T> name)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            ensureOpen();
+            // no options that require special handling
+            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SocketOption<?>> defaultOptions() {
+            HashSet<SocketOption<?>> set = new HashSet<>();
+            set.add(StandardSocketOptions.SO_RCVBUF);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
+	if (local == null)
+	    throw new BindException("automatic bind not possible for Unix domain servers");
+
+        synchronized (stateLock) {
+            ensureOpen();
+            if (localAddress != null)
+                throw new AlreadyBoundException();
+            UnixDomainSocketAddress usa = Net.checkUnixAddress(local);
+            Net.unixDomainBind(fd, usa);
+            Net.listen(fd, backlog < 1 ? 50 : backlog);
+            localAddress = Net.localUnixAddress(fd);
+        }
+        return this;
+    }
+
+
+    @Override
+    int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] addrs)
+        throws IOException
+    {
+
+        return Net.unixDomainAccept(this.fd, newfd, addrs);
+    }
+
+    @Override
+    String getRevealedLocalAddressAsString(SocketAddress addr) {
+        // TODO
+        return addr.toString();
+    }
+
+    @Override
+    SocketAddress getRevealedLocalAddress(SocketAddress addr) {
+        return addr; // TODO
+    }
+
+    SocketChannel finishAccept(FileDescriptor newfd, SocketAddress isa)
+        throws IOException
+    {
+        try {
+            // newly accepted socket is initially in blocking mode
+            IOUtil.configureBlocking(newfd, true);
+            return new UnixDomainSocketChannelImpl(provider(), newfd, isa);
+        } catch (Exception e) {
+            nd.close(newfd);
+            throw e;
+        }
+    }
+
+    /**
+     * Returns the local address, or null if not bound
+     */
+    SocketAddress localAddress() {
+        synchronized (stateLock) {
+            return localAddress;
+        }
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(this.getClass().getName());
+        sb.append('[');
+        if (!isOpen()) {
+            sb.append("closed");
+        } else {
+            synchronized (stateLock) {
+                UnixDomainSocketAddress addr = (UnixDomainSocketAddress)localAddress;
+                if (addr == null) {
+                    sb.append("unbound");
+                } else {
+                    sb.append(getRevealedLocalAddressAsString(addr));
+                }
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2000, 2019, 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 sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.ProtocolFamily;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOption;
+import java.net.SocketTimeoutException;
+import java.net.StandardProtocolFamily;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnixDomainSocketAddress;
+import java.nio.channels.spi.SelectorProvider;
+import java.security.AccessController;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import sun.net.ConnectionResetException;
+import sun.net.NetHooks;
+import sun.net.ext.ExtendedSocketOptions;
+import sun.net.util.SocketExceptions;
+
+/**
+ * An implementation of SocketChannels
+ */
+
+public class UnixDomainSocketChannelImpl extends SocketChannelImpl
+{
+    public UnixDomainSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
+        throws IOException
+    {
+        super(sp, fd);
+        if (bound) {
+            synchronized (stateLock) {
+                this.localAddress = Net.localUnixAddress(fd);
+            }
+        }
+    }
+
+    // Constructor for sockets obtained from server sockets
+    //
+    UnixDomainSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, SocketAddress isa)
+        throws IOException
+    {
+        super(sp, fd);
+        synchronized (stateLock) {
+            this.localAddress = Net.localUnixAddress(fd);
+            this.remoteAddress = isa;
+            this.state = ST_CONNECTED;
+        }
+    }
+
+    @Override
+    public SocketAddress getLocalAddress() throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            return localAddress; // TODO: revealed local address?
+        }
+    }
+
+    @Override
+    public SocketAddress getRemoteAddress() throws IOException {
+        synchronized (stateLock) {
+            ensureOpen();
+            return remoteAddress;
+        }
+    }
+
+    @Override
+    public <T> SocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+        if (!name.type().isInstance(value))
+            throw new IllegalArgumentException("Invalid value '" + value + "'");
+
+        synchronized (stateLock) {
+            ensureOpen();
+
+            // no options that require special handling
+            Net.setSocketOption(fd, name, value);
+            return this;
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SocketOption<T> name)
+        throws IOException
+    {
+        Objects.requireNonNull(name);
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            ensureOpen();
+            // no options that require special handling
+            return (T) Net.getSocketOption(fd, name); // AF_UNIX
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SocketOption<?>> defaultOptions() {
+            HashSet<SocketOption<?>> set = new HashSet<>();
+            set.add(StandardSocketOptions.SO_SNDBUF);
+            set.add(StandardSocketOptions.SO_RCVBUF);
+            set.add(StandardSocketOptions.SO_LINGER);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public SocketChannel bind(SocketAddress local) throws IOException {
+        readLock.lock();
+        try {
+            writeLock.lock();
+            try {
+                synchronized (stateLock) {
+                    ensureOpen();
+                    if (state == ST_CONNECTIONPENDING)
+                        throw new ConnectionPendingException();
+                    if (localAddress != null)
+                        throw new AlreadyBoundException();
+                    UnixDomainSocketAddress usa = Net.checkUnixAddress(local);
+                    Net.unixDomainBind(fd, usa);
+                    if (usa == null) {
+                        localAddress = Net.UNNAMED;
+                    } else {
+                        localAddress = Net.localUnixAddress(fd);
+                    }
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        } finally {
+            readLock.unlock();
+        }
+        return this;
+    }
+
+    public Socket socket() {
+        throw new UnsupportedOperationException("socket not supported");
+    }
+
+    /**
+     * Checks the remote address to which this channel is to be connected.
+     */
+    @Override
+    SocketAddress checkRemote(SocketAddress sa) throws IOException {
+        SocketAddress isa = Net.checkUnixAddress(sa);
+        return isa; // TODO
+    }
+
+    @Override
+    int connectImpl(FileDescriptor fd, SocketAddress sa) throws IOException {
+        UnixDomainSocketAddress isa = (UnixDomainSocketAddress)sa;
+        return Net.unixDomainConnect(fd, isa);
+    }
+
+    @Override
+    SocketAddress localAddressImpl(FileDescriptor fd) throws IOException {
+        return Net.localUnixAddress(fd);
+    }
+
+    String getRevealedLocalAddressAsString(SocketAddress sa) {
+        return sa.toString(); // TODO
+    }
+
+}
--- a/src/java.base/share/native/libnet/net_util.h	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/share/native/libnet/net_util.h	Fri Nov 29 10:02:07 2019 +0000
@@ -40,6 +40,9 @@
 #define NET_WAIT_WRITE   0x02
 #define NET_WAIT_CONNECT 0x04
 
+/* 2 bytes to allow for null at end of string and null at start of string for abstract name */
+#define MAX_UNIX_DOMAIN_PATH_LEN (int)(sizeof(((struct sockaddr_un *)0)->sun_path)-2)
+
 /************************************************************************
  * Cached field IDs
  *
@@ -108,6 +111,11 @@
 extern jfieldID ia6_scopeifnameID;
 extern jmethodID ia6_ctrID;
 
+/* UnixDomainSocketAddress methods */
+extern jclass udsa_class;
+extern jmethodID udsa_ctorID;
+extern jfieldID udsa_pathID;
+
 /************************************************************************
  *  Utilities
  */
@@ -154,6 +162,12 @@
 JNIEXPORT jobject JNICALL
 NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port);
 
+JNIEXPORT jobject JNICALL
+NET_SockaddrToUnixAddress(JNIEnv *env, struct sockaddr_un *sa, socklen_t len);
+
+JNIEXPORT jint JNICALL
+NET_UnixSocketAddressToSockaddr(JNIEnv *env, jobject uaddr, struct sockaddr_un *sa, int *len);
+
 void platformInit();
 
 void parseExclusiveBindProperty(JNIEnv *env);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/native/libnio/ch/UnixDomainSocketAddress.c	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997, 2016, 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 <string.h>
+
+#include "java_nio_channels_UnixDomainSocketAddress.h"
+#include "net_util.h"
+
+/************************************************************************
+ * UnixDomainSocketAddress
+ */
+
+jclass udsa_class;
+jmethodID udsa_ctorID;
+jfieldID udsa_pathID;
+
+static int udsa_initialized = 0;
+
+/*
+ * Class:     java_nio_channels_UnixDomainSocketAddress
+ * Method:    init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_nio_channels_UnixDomainSocketAddress_init(JNIEnv *env, jclass dontuse) {
+    if (!udsa_initialized) {
+        jclass c = (*env)->FindClass(env,"java/nio/channels/UnixDomainSocketAddress");
+        CHECK_NULL(c);
+        udsa_class = (*env)->NewGlobalRef(env, c);
+        CHECK_NULL(udsa_class);
+
+        udsa_pathID = (*env)->GetFieldID(env, udsa_class, "path", "Ljava/lang/String;");
+        CHECK_NULL(udsa_pathID);
+
+        udsa_ctorID = (*env)->GetMethodID(env, udsa_class, "<init>", "(Ljava/lang/String;)V");
+        CHECK_NULL(udsa_ctorID);
+
+        udsa_initialized = 1;
+    }
+}
--- a/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java	Fri Nov 29 10:02:07 2019 +0000
@@ -28,12 +28,18 @@
 import java.lang.reflect.Constructor;
 import java.io.FileDescriptor;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.nio.ByteBuffer;
 import java.nio.channels.Channel;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.DatagramChannel;
+import java.nio.channels.UnixDomainSocketAddress;
 import java.nio.channels.spi.SelectorProvider;
 
 class InheritedChannel {
@@ -79,9 +85,9 @@
      * allows us to "detach" the standard streams after closing and ensures
      * that the underlying socket really closes.
      */
-    public static class InheritedSocketChannelImpl extends SocketChannelImpl {
+    public static class InheritedInetSocketChannelImpl extends InetSocketChannelImpl {
 
-        InheritedSocketChannelImpl(SelectorProvider sp,
+        InheritedInetSocketChannelImpl(SelectorProvider sp,
                                    FileDescriptor fd,
                                    InetSocketAddress remote)
             throws IOException
@@ -95,24 +101,42 @@
         }
     }
 
-    public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl {
+    public static class InheritedUnixSocketChannelImpl extends UnixDomainSocketChannelImpl {
 
-        InheritedUnixChannelImpl(FileDescriptor fd)
+        InheritedUnixSocketChannelImpl(SelectorProvider sp, 
+				FileDescriptor fd,
+				UnixDomainSocketAddress remote )
             throws IOException
         {
-            super(fd);
+            super(sp, fd, remote);
         }
 
+        @Override
         protected void implCloseSelectableChannel() throws IOException {
-            super.implCloseChannel();
+            super.implCloseSelectableChannel();
             detachIOStreams();
         }
     }
 
-    public static class InheritedServerSocketChannelImpl extends
-        ServerSocketChannelImpl {
+    public static class InheritedUnixServerSocketChannelImpl extends UnixDomainServerSocketChannelImpl {
+
+        InheritedUnixServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
+            throws IOException
+        {
+            super(sp, fd, true);
+        }
 
-        InheritedServerSocketChannelImpl(SelectorProvider sp,
+        @Override
+        protected void implCloseSelectableChannel() throws IOException {
+            super.implCloseSelectableChannel();
+            detachIOStreams();
+        }
+    }
+
+    public static class InheritedInetServerSocketChannelImpl extends
+        InetServerSocketChannelImpl {
+
+        InheritedInetServerSocketChannelImpl(SelectorProvider sp,
                                          FileDescriptor fd)
             throws IOException
         {
@@ -206,20 +230,21 @@
                 return null;
             if (family == AF_UNIX) {
                 if (isConnected(fdVal)) {
-                    return new InheritedUnixChannelImpl(fd);
+	            UnixDomainSocketAddress sa = peerAddressUnix(fdVal);
+                    return new InheritedUnixSocketChannelImpl(provider, fd, sa);
                 } else {
-                    // listener. unsupported.
-                    return null;
+                    return new InheritedUnixServerSocketChannelImpl(provider, fd);
                 }
             }
-            InetAddress ia = peerAddress0(fdVal);
+            InetAddress ia = peerAddressInet(fdVal);
             if (ia == null) {
-               c = new InheritedServerSocketChannelImpl(provider, fd);
+               c = new InheritedInetServerSocketChannelImpl(provider, fd);
             } else {
                int port = peerPort0(fdVal);
+
                assert port > 0;
                InetSocketAddress isa = new InetSocketAddress(ia, port);
-               c = new InheritedSocketChannelImpl(provider, fd, isa);
+               c = new InheritedInetSocketChannelImpl(provider, fd, isa);
             }
         } else {
             c = new InheritedDatagramChannelImpl(provider, fd);
@@ -263,7 +288,8 @@
     private static native void close0(int fd) throws IOException;
     private static native int soType0(int fd);
     private static native int addressFamily(int fd);
-    private static native InetAddress peerAddress0(int fd);
+    private static native InetAddress peerAddressInet(int fd);
+    private static native UnixDomainSocketAddress peerAddressUnix(int fd);
     private static native int peerPort0(int fd);
 
     // return true if socket is connected to a peer
--- a/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-/*
- * Copyright (c) 2019, 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 sun.nio.ch;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.AsynchronousCloseException;
-import java.nio.channels.ByteChannel;
-import java.nio.channels.ClosedChannelException;
-import java.nio.channels.NotYetConnectedException;
-import java.nio.channels.spi.AbstractInterruptibleChannel;
-import java.util.Objects;
-import java.util.concurrent.locks.ReentrantLock;
-
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
-class UnixDomainSocketChannelImpl
-    extends AbstractInterruptibleChannel
-    implements ByteChannel
-{
-    // Used to make native read and write calls
-    private static final NativeDispatcher nd = new SocketDispatcher();
-
-    // Our file descriptor object
-    private final FileDescriptor fd;
-    // Lock held by current reading or connecting thread
-    private final ReentrantLock readLock = new ReentrantLock();
-
-    // Lock held by current writing or connecting thread
-    private final ReentrantLock writeLock = new ReentrantLock();
-
-    // Lock for managing close state
-    private final Object stateLock = new Object();
-
-    // Channel state
-    private static final int ST_INUSE = 0;
-    private static final int ST_CLOSING = 1;
-    private static final int ST_CLOSED = 2;
-    private int state;
-
-    // IDs of native threads doing reads and writes, for signalling
-    private long readerThread;
-    private long writerThread;
-
-    UnixDomainSocketChannelImpl(FileDescriptor fd)
-        throws IOException
-    {
-        this.fd = fd;
-    }
-
-    /**
-     * Checks that the channel is open.
-     *
-     * @throws ClosedChannelException if channel is closed (or closing)
-     */
-    private void ensureOpen() throws ClosedChannelException {
-        if (!isOpen())
-            throw new ClosedChannelException();
-    }
-
-    /**
-     * Closes the socket if there are no I/O operations in progress
-     */
-    private boolean tryClose() throws IOException {
-        assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
-        if (readerThread == 0 && writerThread == 0) {
-            state = ST_CLOSED;
-            nd.close(fd);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Complete closure of pre-closed socket (release the file descriptor)
-     */
-    private void tryFinishClose() {
-        try {
-            tryClose();
-        } catch (IOException ignore) { }
-    }
-
-    /**
-     * Marks the beginning of a read operation
-     *
-     * @throws ClosedChannelException if the channel is closed
-     * @throws NotYetConnectedException if the channel is not yet connected
-     */
-    private void beginRead() throws ClosedChannelException {
-        // set hook for Thread.interrupt
-        begin();
-        synchronized (stateLock) {
-            ensureOpen();
-            readerThread = NativeThread.current();
-        }
-    }
-
-    /**
-     * Marks the end of a read operation that may have blocked.
-     *
-     * @throws AsynchronousCloseException if the channel was closed due to this
-     * thread being interrupted on a blocking read operation.
-     */
-    private void endRead(boolean completed)
-        throws AsynchronousCloseException
-    {
-        synchronized (stateLock) {
-            readerThread = 0;
-            if (state == ST_CLOSING) {
-                tryFinishClose();
-            }
-        }
-        end(completed);
-    }
-
-    @Override
-    public int read(ByteBuffer buf) throws IOException {
-        Objects.requireNonNull(buf);
-
-        readLock.lock();
-        try {
-            int n = 0;
-            try {
-                beginRead();
-                n = IOUtil.read(fd, buf, -1, nd);
-                while (IOStatus.okayToRetry(n) && isOpen()) {
-                    park(Net.POLLIN, 0L);
-                    n = IOUtil.read(fd, buf, -1, nd);
-                }
-            } finally {
-                endRead(n > 0);
-            }
-            return n;
-        } finally {
-            readLock.unlock();
-        }
-    }
-
-    /**
-     * Marks the beginning of a write operation that might block.
-     *
-     * @throws ClosedChannelException if the channel is closed
-     * @throws NotYetConnectedException if the channel is not yet connected
-     */
-    private void beginWrite() throws ClosedChannelException {
-        begin();
-        synchronized (stateLock) {
-            // set hook for Thread.interrupt
-            ensureOpen();
-            writerThread = NativeThread.current();
-        }
-    }
-
-    /**
-     * Marks the end of a write operation that may have blocked.
-     *
-     * @throws AsynchronousCloseException if the channel was closed due to this
-     * thread being interrupted on a blocking write operation.
-     */
-    private void endWrite(boolean completed)
-        throws AsynchronousCloseException
-    {
-        synchronized (stateLock) {
-            writerThread = 0;
-            if (state == ST_CLOSING) {
-                tryFinishClose();
-            }
-        }
-        end(completed);
-    }
-
-    void park(int event, long nanos) throws IOException {
-        long millis;
-        if (nanos <= 0) {
-            millis = -1;
-        } else {
-            millis = NANOSECONDS.toMillis(nanos);
-        }
-        Net.poll(fd, event, millis);
-    }
-
-    @Override
-    public int write(ByteBuffer buf) throws IOException {
-        Objects.requireNonNull(buf);
-
-        writeLock.lock();
-        try {
-            int n = 0;
-            try {
-                beginWrite();
-                n = IOUtil.write(fd, buf, -1, nd);
-                while (IOStatus.okayToRetry(n) && isOpen()) {
-                    park(Net.POLLOUT, 0L);
-                    n = IOUtil.write(fd, buf, -1, nd);
-                }
-            } finally {
-                endWrite(n > 0);
-            }
-            return n;
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
-    /**
-     * Closes this channel
-     *
-     * If there is an I/O operation in progress then the socket is pre-closed
-     * and the I/O threads signalled, in which case the final close is deferred
-     * until all I/O operations complete.
-     */
-    @Override
-    protected void implCloseChannel() throws IOException {
-        synchronized (stateLock) {
-            assert state == ST_INUSE;
-            state = ST_CLOSING;
-            if (!tryClose()) {
-                long reader = readerThread;
-                long writer = writerThread;
-                if (reader != 0 || writer != 0) {
-                    nd.preClose(fd);
-                    if (reader != 0)
-                        NativeThread.signal(reader);
-                    if (writer != 0)
-                        NativeThread.signal(writer);
-                }
-            }
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(this.getClass().getSuperclass().getName());
-        sb.append('[');
-        if (!isOpen())
-            sb.append("closed");
-        sb.append(']');
-        return sb.toString();
-    }
-}
--- a/src/java.base/unix/native/libnet/net_util_md.h	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/unix/native/libnet/net_util_md.h	Fri Nov 29 10:02:07 2019 +0000
@@ -29,6 +29,8 @@
 #include <netdb.h>
 #include <poll.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
 
 /************************************************************************
  * Macros and constants
@@ -71,6 +73,7 @@
     struct sockaddr     sa;
     struct sockaddr_in  sa4;
     struct sockaddr_in6 sa6;
+    struct sockaddr_un  saun;
 } SOCKETADDRESS;
 
 /************************************************************************
--- a/src/java.base/unix/native/libnio/ch/InheritedChannel.c	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/unix/native/libnio/ch/InheritedChannel.c	Fri Nov 29 10:02:07 2019 +0000
@@ -36,8 +36,9 @@
 #include "net_util.h"
 
 #include "sun_nio_ch_InheritedChannel.h"
+#include "java_nio_channels_UnixDomainSocketAddress.h"
 
-static int matchFamily(SOCKETADDRESS *sa) {
+static int matchFamilyInet(SOCKETADDRESS *sa) {
     return (sa->sa.sa_family == (ipv6_available() ? AF_INET6 : AF_INET));
 }
 
@@ -46,10 +47,12 @@
 {
     /* Initialize InetAddress IDs before later use of NET_XXX functions */
     initInetAddressIDs(env);
+    /* Same for UnixDomainSocketAddress */
+    Java_java_nio_channels_UnixDomainSocketAddress_init(env, NULL);
 }
 
 JNIEXPORT jobject JNICALL
-Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
+Java_sun_nio_ch_InheritedChannel_peerAddressInet(JNIEnv *env, jclass cla, jint fd)
 {
     SOCKETADDRESS sa;
     socklen_t len = sizeof(SOCKETADDRESS);
@@ -57,7 +60,7 @@
     jint remote_port;
 
     if (getpeername(fd, &sa.sa, &len) == 0) {
-        if (matchFamily(&sa)) {
+        if (matchFamilyInet(&sa)) {
             remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
         }
     }
@@ -65,6 +68,21 @@
     return remote_ia;
 }
 
+JNIEXPORT jobject JNICALL
+Java_sun_nio_ch_InheritedChannel_peerAddressUnix(JNIEnv *env, jclass cla, jint fd)
+{
+    struct sockaddr_un sa;
+    socklen_t len = sizeof(struct sockaddr_un);
+    jobject remote_sa = NULL;
+
+    if (getpeername(fd, (struct sockaddr *)&sa, &len) == 0) {
+        if (sa.sun_family == AF_UNIX) {
+            remote_sa = NET_SockaddrToUnixAddress(env, &sa, len);
+        }
+    }
+    return remote_sa;
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd)
 {
@@ -72,8 +90,8 @@
     socklen_t len = sizeof(SOCKETADDRESS);
     jint remote_port = -1;
 
-    if (getpeername(fd, &sa.sa, &len) == 0) {
-        if (matchFamily(&sa)) {
+    if (getpeername(fd, (struct sockaddr *)&sa.sa, &len) == 0) {
+        if (matchFamilyInet(&sa)) {
             NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
         }
     }
--- a/src/java.base/unix/native/libnio/ch/Net.c	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/unix/native/libnio/ch/Net.c	Fri Nov 29 10:02:07 2019 +0000
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <string.h>
+#include <stddef.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <limits.h>
@@ -46,6 +47,178 @@
 #include <sys/utsname.h>
 #endif
 
+
+extern jclass udsa_class;
+extern jmethodID udsa_ctorID;
+extern jfieldID udsa_pathID;
+
+/* Subtle platform differences in how unnamed sockets (empty path)
+ * are returned from getsockname()
+ */
+#if defined(__solaris__)
+  #define ZERO_PATHLEN(len) (len == 0)
+#elif defined(MACOSX)
+  #define ZERO_PATHLEN(len) (JNI_FALSE)
+#else
+  #define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path))
+#endif
+
+JNIEXPORT jobject JNICALL
+NET_SockaddrToUnixAddress(JNIEnv *env, struct sockaddr_un *sa, socklen_t len) {
+
+    if (sa->sun_family == AF_UNIX) {
+        char *name;
+
+        if (ZERO_PATHLEN(len)) {
+            name = "";
+        } else {
+            name = sa->sun_path;
+        }
+        jstring nstr = JNU_NewStringPlatform(env, name);
+        return (*env)->NewObject(env, udsa_class, udsa_ctorID, nstr);
+    }
+    return NULL;
+}
+
+JNIEXPORT jint JNICALL
+NET_UnixSocketAddressToSockaddr(JNIEnv *env, jobject uaddr, struct sockaddr_un *sa, int *len)
+{
+    jstring path;
+    memset(sa, 0, sizeof(struct sockaddr_un));
+    sa->sun_family = AF_UNIX;
+    path = (*env)->GetObjectField(env, uaddr, udsa_pathID);
+    jboolean isCopy;
+    int ret;
+    const char* pname = JNU_GetStringPlatformChars(env, path, &isCopy);
+    size_t name_len = strlen(pname)+1;
+    if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "unix domain path too long");
+        ret = 1;
+        goto finish;
+    }
+    strncpy(sa->sun_path, pname, name_len);
+    *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len);
+    ret = 0;
+  finish:
+    if (isCopy)
+        JNU_ReleaseStringPlatformChars(env, path, pname);
+    return ret;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_unixDomainSocketSupported(JNIEnv *env, jclass cl)
+{
+    return JNI_TRUE;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainSocket0(JNIEnv *env, jclass cl)
+{
+    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+        return handleSocketError(env, errno);
+    }
+    return fd;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_unixDomainBind(JNIEnv *env, jclass clazz, jobject fdo, jobject uaddr)
+{
+    struct sockaddr_un sa;
+    int sa_len = 0;
+    int rv = 0;
+
+    if (uaddr == NULL)
+        return; /* Rely on implicit bind: Unix */
+
+    if (NET_UnixSocketAddressToSockaddr(env, uaddr, &sa, &sa_len) != 0)
+        return;
+
+    int fd = fdval(env, fdo);
+
+    rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
+    if (rv != 0) {
+        handleSocketError(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainConnect(JNIEnv *env, jclass clazz, jobject fdo, jobject usa)
+{
+    struct sockaddr_un sa;
+    int sa_len = 0;
+    int rv;
+
+    if (NET_UnixSocketAddressToSockaddr(env, usa, &sa, &sa_len) != 0) {
+        return IOS_THROWN;
+    }
+
+    rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
+    if (rv != 0) {
+        if (errno == EINPROGRESS) {
+            return IOS_UNAVAILABLE;
+        } else if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        }
+        return handleSocketError(env, errno);
+    }
+    return 1;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainAccept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
+                           jobjectArray usaa)
+{
+    jint fd = fdval(env, fdo);
+    jint newfd;
+    struct sockaddr_un sa;
+    socklen_t sa_len = sizeof(struct sockaddr_un);
+    jobject usa;
+
+    /* accept connection but ignore ECONNABORTED */
+    for (;;) {
+        newfd = accept(fd, (struct sockaddr *)&sa, &sa_len);
+        if (newfd >= 0) {
+            break;
+        }
+        if (errno != ECONNABORTED) {
+            break;
+        }
+        /* ECONNABORTED => restart accept */
+    }
+
+    if (newfd < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK)
+            return IOS_UNAVAILABLE;
+        if (errno == EINTR)
+            return IOS_INTERRUPTED;
+        JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
+        return IOS_THROWN;
+    }
+
+    setfdval(env, newfdo, newfd);
+
+    usa = NET_SockaddrToUnixAddress(env, &sa, sa_len);
+    CHECK_NULL_RETURN(usa, IOS_THROWN);
+
+    (*env)->SetObjectArrayElement(env, usaa, 0, usa);
+
+    return 1;
+}
+
+JNIEXPORT jobject JNICALL
+Java_sun_nio_ch_Net_localUnixAddress(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    struct sockaddr_un sa;
+    socklen_t sa_len = sizeof(struct sockaddr_un);
+    int port;
+    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+        handleSocketError(env, errno);
+        return NULL;
+    }
+    return NET_SockaddrToUnixAddress(env, &sa, sa_len);
+}
+
 /**
  * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at
  * build time.
--- a/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -47,11 +47,11 @@
     final SocketChannel sc;
 
     public FileDescriptor getFD() {
-        return ((SocketChannelImpl)sc).getFD();
+        return ((InetSocketChannelImpl)sc).getFD();
     }
 
     public int getFDVal() {
-        return ((SocketChannelImpl)sc).getFDVal();
+        return ((InetSocketChannelImpl)sc).getFDVal();
     }
 
     SinkChannelImpl(SelectorProvider sp, SocketChannel sc) {
--- a/src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -46,11 +46,11 @@
     private final SocketChannel sc;
 
     public FileDescriptor getFD() {
-        return ((SocketChannelImpl) sc).getFD();
+        return ((InetSocketChannelImpl) sc).getFD();
     }
 
     public int getFDVal() {
-        return ((SocketChannelImpl) sc).getFDVal();
+        return ((InetSocketChannelImpl) sc).getFDVal();
     }
 
     SourceChannelImpl(SelectorProvider sp, SocketChannel sc) {
--- a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java	Fri Nov 29 10:02:07 2019 +0000
@@ -419,7 +419,7 @@
                 // OOB data queued to the socket. If there is OOB data then it
                 // is discarded and the key is not added to the selected set.
                 if (isExceptFds &&
-                    (sk.channel() instanceof SocketChannelImpl) &&
+                    (sk.channel() instanceof InetSocketChannelImpl) &&
                     discardUrgentData(desc))
                 {
                     continue;
--- a/src/java.base/windows/native/libnet/net_util_md.h	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/windows/native/libnet/net_util_md.h	Fri Nov 29 10:02:07 2019 +0000
@@ -26,6 +26,7 @@
 #include <WS2tcpip.h>
 #include <iphlpapi.h>
 #include <icmpapi.h>
+#include <afunix.h>
 
 /* used to disable connection reset messages on Windows XP */
 #ifndef SIO_UDP_CONNRESET
--- a/src/java.base/windows/native/libnio/ch/Net.c	Fri Nov 29 10:20:17 2019 +0100
+++ b/src/java.base/windows/native/libnio/ch/Net.c	Fri Nov 29 10:02:07 2019 +0000
@@ -86,6 +86,171 @@
 static jclass isa_class;        /* java.net.InetSocketAddress */
 static jmethodID isa_ctorID;    /* InetSocketAddress(InetAddress, int) */
 
+extern jclass udsa_class;
+extern jmethodID udsa_ctorID;
+extern jfieldID udsa_pathID;
+
+
+JNIEXPORT jobject JNICALL
+NET_SockaddrToUnixAddress(JNIEnv *env, struct sockaddr_un *sa, socklen_t len) {
+
+    if (sa->sun_family == AF_UNIX) {
+        jstring nstr = JNU_NewStringPlatform(env, sa->sun_path);
+        return (*env)->NewObject(env, udsa_class, udsa_ctorID, nstr);
+    }
+    return NULL;
+}
+
+JNIEXPORT jint JNICALL
+NET_UnixSocketAddressToSockaddr(JNIEnv *env, jobject uaddr, struct sockaddr_un *sa, int *len)
+{
+    jstring path;
+    memset(sa, 0, sizeof(struct sockaddr_un));
+    sa->sun_family = AF_UNIX;
+    if (uaddr == NULL) {
+ 	/* Do explicit bind on Windows */
+        *len = (int)(offsetof(struct sockaddr_un, sun_path));
+        return 0;
+    }
+    path = (*env)->GetObjectField(env, uaddr, udsa_pathID);
+    jboolean isCopy;
+    int ret;
+    const char* pname = JNU_GetStringPlatformChars(env, path, &isCopy);
+    size_t name_len = strlen(pname)+1;
+    if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "unix domain path too long");
+        ret = 1;
+        goto finish;
+    }
+    strncpy(sa->sun_path, pname, name_len);
+    *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len);
+    ret = 0;
+  finish:
+    if (isCopy)
+        JNU_ReleaseStringPlatformChars(env, path, pname);
+    return ret;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_unixDomainSocketSupported(JNIEnv *env, jclass cl)
+{
+    SOCKET fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd == INVALID_SOCKET) {
+        return JNI_FALSE;
+    }
+    closesocket(fd);
+    return JNI_TRUE;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainSocket0(JNIEnv *env, jclass cl)
+{
+    SOCKET fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (fd == INVALID_SOCKET) {
+        return handleSocketError(env, WSAGetLastError());
+    }
+    return (int)fd;
+}
+
+/**
+ * Windows does not support auto bind. So, the windows version of NET_UnixSocketAddressToSockaddr
+ * looks out for a null 'uaddr' and handles it specially
+ */
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_unixDomainBind(JNIEnv *env, jclass clazz, jobject fdo, jobject uaddr)
+{
+    struct sockaddr_un sa;
+    int sa_len = 0;
+    int rv = 0;
+
+    if (NET_UnixSocketAddressToSockaddr(env, uaddr, &sa, &sa_len) != 0)
+        return;
+
+    int fd = fdval(env, fdo);
+
+    rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
+    if (rv != 0) {
+        int err = WSAGetLastError();
+        NET_ThrowNew(env, err, "bind");
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainConnect(JNIEnv *env, jclass clazz, jobject fdo, jobject usa)
+{
+    struct sockaddr_un sa;
+    int sa_len = 0;
+    int rv;
+
+    if (NET_UnixSocketAddressToSockaddr(env, usa, &sa, &sa_len) != 0) {
+        return IOS_THROWN;
+    }
+
+    rv = connect(fdval(env, fdo), (const struct sockaddr *)&sa, sa_len);
+    if (rv != 0) {
+        int err = WSAGetLastError();
+        if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {
+            return IOS_UNAVAILABLE;
+        }
+        NET_ThrowNew(env, err, "connect");
+        return IOS_THROWN;
+    }
+    return 1;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_unixDomainAccept(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
+                           jobjectArray usaa)
+{
+    jint fd = fdval(env, fdo);
+    jint newfd;
+    struct sockaddr_un sa;
+    socklen_t sa_len = sizeof(sa);
+    jobject usa;
+
+    /* accept connection but ignore ECONNABORTED */
+    for (;;) {
+        newfd = (jint)accept(fd, (struct sockaddr *)&sa, &sa_len);
+        if (newfd >= 0) {
+            break;
+        }
+        if (errno != ECONNABORTED) {
+            break;
+        }
+        /* ECONNABORTED => restart accept */
+    }
+
+    if (newfd < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK)
+            return IOS_UNAVAILABLE;
+        if (errno == EINTR)
+            return IOS_INTERRUPTED;
+        JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
+        return IOS_THROWN;
+    }
+
+    setfdval(env, newfdo, newfd);
+
+    usa = NET_SockaddrToUnixAddress(env, &sa, sa_len);
+    CHECK_NULL_RETURN(usa, IOS_THROWN);
+
+    (*env)->SetObjectArrayElement(env, usaa, 0, usa);
+
+    return 1;
+}
+
+JNIEXPORT jobject JNICALL
+Java_sun_nio_ch_Net_localUnixAddress(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    struct sockaddr_un sa;
+    socklen_t sa_len = sizeof(sa);
+    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+        handleSocketError(env, WSAGetLastError());
+        return NULL;
+    }
+    return NET_SockaddrToUnixAddress(env, &sa, sa_len);
+}
+
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
 {
--- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java	Fri Nov 29 10:02:07 2019 +0000
@@ -27,7 +27,7 @@
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
 
 /*
- * Make sure that System.inheritedChannel returns null when given a UNIX domain socket
+ * Make sure that System.inheritedChannel returns the correct type
  */
 
 public class UnixDomainChannelTest {
@@ -45,11 +45,18 @@
                 bc.write(buf);
             } else { // test3
                 // in this case the socket is a listener
-                // we can't write to it. So, use UnixDatagramSocket
-                // to accept a writeable socket
-                UnixDomainSocket listener = new UnixDomainSocket(0); // fd 0
-                UnixDomainSocket sock = listener.accept();
-                sock.write((int)result.charAt(0));
+		if (!(channel instanceof ServerSocketChannel)) {
+                    // we can't write to it. So, use UnixDatagramSocket
+                    // to accept a writeable socket
+                    UnixDomainSocket listener = new UnixDomainSocket(0); // fd 0
+                    UnixDomainSocket sock = listener.accept();
+                    sock.write((int)'X');
+		} else {
+		    ServerSocketChannel server = (ServerSocketChannel)channel;
+		    ByteChannel bc = server.accept();
+                    ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1));
+                    bc.write(buf);
+		}
             }
         }
     }
@@ -107,7 +114,7 @@
         System.out.println("test3: launching child");
         Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", listener, "test3");
         sock1.connect("foo.socket");
-        if (sock1.read() != 'N') {
+        if (sock1.read() != 'Y') {
             System.err.println("test3: failed");
             passed = false;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/unixdomain/Basic.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8231358
+ * @run main/othervm Basic 32000 32000 nagle-off
+ * @run main/othervm Basic default default nagle-off
+ * @summary Basic test for Unix Domain and Inet socket and server socket channels
+ */
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Basic {
+    static int sockRxBufsize, sockTxBufsize;
+    static boolean nagle;
+    static String tempDir;
+
+    static {
+        try {
+            Path parent = Paths.get(".");
+            Path child = Files.createTempDirectory(parent, null);
+            tempDir = child.toString();
+        } catch (IOException e) {
+            tempDir = null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+        if (args.length != 3)
+            usage();
+
+        if (!supported()) {
+            System.out.println("Unix domain channels not supported");
+            return;
+        }
+        sockRxBufsize = getInt(args[0]);
+        sockTxBufsize = getInt(args[1]);
+        if (args[2].equals("nagle-on"))
+            nagle = true;
+        else if (args[2].equals("nagle-off"))
+            nagle = false;
+
+        warmup();
+        test(128, 1000);
+        test(8 * 1024, 10000);
+        test(16 * 1024, 10000);
+        test(32 * 1024, 10000);
+    }
+
+    static boolean supported() {
+        try {
+            SocketChannel.open(StandardProtocolFamily.UNIX);
+        } catch (UnsupportedAddressTypeException e) {
+            return false;
+        } catch (Exception e) {
+            return true; // continue test to see what problem is
+        }
+        return true;
+    }
+
+    static int getInt(String s) {
+        if (s.equalsIgnoreCase("default"))
+            return -1;
+        else
+            return Integer.parseInt(s);
+    }
+
+    static void usage() {
+        System.out.println("usage: java Basic " +
+            "<kernel sock read buf size> <kernel sock send buf size> {nagle-on|nagle-off}");
+        System.out.println("nagle setting only affects TCP sockets");
+        System.exit(-1);
+    }
+
+    static void warmup() throws Exception {
+        Server server = new Server(StandardProtocolFamily.UNIX, 1024);
+        Client client = new Client(server, 128, 100);
+        server.start();
+        client.run();
+
+        server = new Server(StandardProtocolFamily.INET, 1024);
+        client = new Client(server, 128, 100);
+        server.start();
+        client.run();
+    }
+
+    static void test(int bufsize, int nbufs) throws Exception {
+        long unix = testUnix(bufsize, nbufs);
+        long inet = testInet(bufsize, nbufs);
+        // expect unix to be faster (express as percentage of inet)
+        long percent = (unix * 100) / inet;
+        System.out.printf ("Unix elapsed time is %d%% of the INET time\n\n", percent);
+    }
+
+    static long testUnix(int bufsize, int nbufs) throws Exception {
+        Server server = new Server(StandardProtocolFamily.UNIX, bufsize);
+        Client client = new Client(server, bufsize, nbufs);
+        System.out.printf("Test (family=unix bufsize=%d, nbufs=%d) ", bufsize, nbufs);
+        server.start();
+        client.run();
+        long unix = client.elapsed();
+        int sbuf = client.sendSocketBufsize();
+        int rbuf = client.receiveSocketBufsize();
+        System.out.printf("completed in %d ns (sbuf=%d, rbuf=%d)\n", unix, sbuf, rbuf);
+        System.gc();
+        return unix;
+    }
+
+    static long testInet(int bufsize, int nbufs) throws Exception {
+        Server server = new Server(StandardProtocolFamily.INET, bufsize);
+        Client client = new Client(server, bufsize, nbufs);
+        System.out.printf("Test (family=inet bufsize=%d, nbufs=%d) ", bufsize, nbufs);
+        server.start();
+        client.run();
+        long inet = client.elapsed();
+        System.gc();
+        int sbuf = client.sendSocketBufsize();
+        int rbuf = client.receiveSocketBufsize();
+        System.out.printf("completed in %d ns (sbuf=%d, rbuf=%d)\n", inet, sbuf, rbuf);
+        return inet;
+    }
+
+    static void setNagle(SocketChannel chan, boolean value) throws IOException {
+        if (chan.getRemoteAddress() instanceof InetSocketAddress) {
+            chan.setOption(StandardSocketOptions.TCP_NODELAY, value);
+        }
+    }
+
+    static void setSendBufferSize(SocketChannel chan, int bufsize) throws IOException {
+        if (bufsize < 0)
+            return;
+        chan.setOption(StandardSocketOptions.SO_SNDBUF, bufsize);
+    }
+
+    static void setRecvBufferSize(SocketChannel chan, int bufsize) throws IOException {
+        if (bufsize < 0)
+            return;
+        chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
+    }
+
+    static class Server extends Thread {
+
+        ServerSocketChannel server;
+        SocketAddress address;
+        SocketChannel connection;
+        SelectionKey ckey;
+        List<ByteBuffer> toSend = new LinkedList<>();
+        final int bufsize;
+        Path sockfile;
+
+        Server(ProtocolFamily family, int bufsize) throws IOException {
+            //setDaemon(true);
+            SocketAddress addr;
+            this.bufsize = bufsize;
+            if (family == StandardProtocolFamily.UNIX) {
+                server = ServerSocketChannel.open(family);
+                sockfile = Path.of(tempDir, "server.sock");
+                Files.deleteIfExists(sockfile);
+                addr = new UnixDomainSocketAddress(sockfile);
+                System.out.println("ADDR = " + addr);
+            } else {
+                server = ServerSocketChannel.open();
+                addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
+            }
+            server.bind(addr);
+            address = server.getLocalAddress();
+        }
+
+        SocketAddress getAddress() {
+            return address;
+        }
+
+        public void  run() {
+            try {
+                server.configureBlocking(false);
+                Selector sel = Selector.open();
+                server.register(sel, SelectionKey.OP_ACCEPT, server);
+
+                while (true) {
+                    int n = sel.select();
+                    var keys = sel.selectedKeys();
+                    for (SelectionKey key : keys) {
+                        if (key.isAcceptable()) {
+                            if (connection != null)
+                                throw new RuntimeException("One connection per server");
+                            ServerSocketChannel server = (ServerSocketChannel)key.attachment();
+                            connection = server.accept();
+                            connection.configureBlocking(false);
+                            setNagle(connection, nagle);
+                            setSendBufferSize(connection, sockTxBufsize);
+                            setRecvBufferSize(connection, sockRxBufsize);
+                            ckey = connection.register(sel, SelectionKey.OP_READ, connection);
+                        }
+                        if (key.isReadable()) {
+                            ByteBuffer buf = ByteBuffer.allocate(bufsize);
+                            SocketChannel channel = (SocketChannel)key.attachment();
+                            int m = channel.read(buf);
+                            if (m == -1) {
+                                channel.close();
+                                return;
+                            } else {
+                                buf.flip();
+                                // ECHO
+                                toSend.add(buf);
+                                ckey.interestOpsOr(SelectionKey.OP_WRITE);
+                            }
+                        }
+                        if (key.isWritable()) {
+                            if (toSend.isEmpty()) {
+                                ckey.interestOpsAnd(~SelectionKey.OP_WRITE);
+                            } else {
+                                ByteBuffer b = toSend.get(0);
+                                connection.write(b);
+                                if (b.remaining() == 0)
+                                    toSend.remove(0);
+                            }
+                        }
+                    }
+                    keys.clear();
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            } finally {
+                try {
+                    if (server.isOpen()) server.close();
+                    if (sockfile != null)
+                        Files.deleteIfExists(sockfile);
+                } catch (IOException ee) {}
+            }
+        }
+    }
+
+    static void fill(ByteBuffer buf) {
+        int n = buf.remaining();
+        for (int i=0; i<n; i++) {
+            buf.put((byte)(i % 127));
+        }
+    }
+
+    static void check(ByteBuffer buf, int expected, int iteration) throws Exception {
+        if (buf.remaining() != expected)
+            throw new RuntimeException();
+        for (int i=0; i<expected; i++) {
+            int b = buf.get();
+            if (b != (i % 127)) {
+                System.out.printf("b = %d , i = %d\n", b, i);
+                throw new RuntimeException("Iteration " + Integer.toString(iteration));
+            }
+        }
+    }
+
+// read until buf is full
+
+    static void readFully(SocketChannel chan, ByteBuffer buf) throws Exception {
+        int n = buf.remaining();
+        while (n > 0) {
+            int c = chan.read(buf);
+            if (c == -1)
+                throw new RuntimeException("EOF");
+            n -= c;
+        }
+    }
+
+    static class Client {
+        Server server;
+        int bufsize, nbufs, sbuf, rbuf;
+        long elapsed;
+
+        Client(Server server, int bufsize, int nbufs) {
+            this.server = server;
+            this.bufsize = bufsize;
+            this.nbufs = nbufs;
+        }
+
+        public void run() throws Exception {
+            SocketAddress remote = server.getAddress();
+            long start = System.nanoTime();
+            SocketChannel c = null;
+            String fam;
+            if (remote instanceof UnixDomainSocketAddress) {
+                c = SocketChannel.open(StandardProtocolFamily.UNIX);
+                fam = "unix";
+            } else {
+                c = SocketChannel.open();
+                fam = "inet";
+            }
+            setNagle(c, nagle);
+            c.connect(remote);
+            setSendBufferSize(c, sockTxBufsize);
+            setRecvBufferSize(c, sockRxBufsize);
+            ByteBuffer tx = ByteBuffer.allocate(bufsize);
+            ByteBuffer rx = ByteBuffer.allocate(bufsize);
+            fill(tx);
+            for (int i=0; i<nbufs; i++) {
+                tx.rewind();
+                c.write(tx);
+                rx.clear();
+                readFully(c, rx);
+                rx.flip();
+                check(rx, bufsize, i);
+            }
+            long end = System.nanoTime();
+            elapsed = end - start;
+            sbuf = c.getOption(StandardSocketOptions.SO_SNDBUF);
+            rbuf = c.getOption(StandardSocketOptions.SO_SNDBUF);
+            c.close();
+        }
+
+        long elapsed() {
+            return elapsed;
+        }
+
+        int receiveSocketBufsize() {return rbuf;}
+        int sendSocketBufsize() {return sbuf;}
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/unixdomain/Bind.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8231358
+ * @run main Bind
+ * @summary Bind test
+ */
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Set;
+
+/**
+ * Check that all bind variations work
+ */
+public class Bind {
+
+    static Path spath, cpath;
+
+    static UnixDomainSocketAddress sAddr, cAddr, nullAddr;
+    static ServerSocketChannel server;
+    static SocketChannel client, accept1;
+
+    public static void main(String args[]) throws Exception {
+        if (!supported()) {
+            System.out.println("Unix domain channels not supported");
+            return;
+        }
+        spath = Path.of("server.sock");
+        cpath = Path.of("client.sock");
+        sAddr = new UnixDomainSocketAddress(spath);
+        cAddr = new UnixDomainSocketAddress(cpath);
+        nullAddr = new UnixDomainSocketAddress("");
+        runTests();
+    }
+
+    static boolean supported() {
+        try {
+            SocketChannel.open(StandardProtocolFamily.UNIX);
+        } catch (UnsupportedAddressTypeException e) {
+            return false;
+        } catch (Exception e) {
+            return true; // continue test to see what problem is
+        }
+        return true;
+    }
+
+    static interface ThrowingRunnable {
+        public void run() throws Exception;
+    }
+
+    static void init() throws IOException {
+        Files.deleteIfExists(cpath);
+        Files.deleteIfExists(spath);
+        client = null; server = null; accept1 = null;
+    }
+
+    static void checkNormal(ThrowingRunnable r) {
+        try {
+            init();
+            r.run();
+            System.out.println("PASS:");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            cleanup();
+        }
+    }
+
+    static void checkException(Class<? extends Exception> expected, ThrowingRunnable r) {
+        try {
+            init();
+            r.run();
+            throw new RuntimeException("Exception expected");
+        } catch (Exception e) {
+            if (!expected.isAssignableFrom(e.getClass())) {
+                String msg = "Expected: " + expected + " Got: " + e.getClass();
+                throw new RuntimeException(msg);
+            }
+            System.out.println("PASS: Got " + e);
+        } finally {
+            cleanup();
+        }
+    }
+
+    static void cleanup() {
+        try {
+            if (server != null)
+                server.close();
+            if (client != null)
+                client.close();
+            if (accept1 != null)
+                accept1.close();
+        } catch (IOException e) {}
+    }
+
+    static void assertClientAddress(SocketAddress a) {
+        assertAddress(a, cAddr, "client");
+    }
+
+    static void assertServerAddress(SocketAddress a) {
+        assertAddress(a, sAddr, "server");
+    }
+
+    static void assertAddress(SocketAddress a, UnixDomainSocketAddress a1, String s) {
+        if (!(a instanceof UnixDomainSocketAddress)) {
+            System.err.println("adddr = " + a);
+            throw new RuntimeException("wrong address type");
+        }
+        UnixDomainSocketAddress ua = (UnixDomainSocketAddress)a;
+        if (!a.equals(a1))
+            throw new RuntimeException("this is not the " + s + " address");
+    }
+
+    public static void runTests() throws IOException {
+        checkNormal(() -> {
+            client = SocketChannel.open(StandardProtocolFamily.UNIX);
+            client.bind(cAddr);
+        });
+        checkNormal(() -> {
+            server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+            server.bind(sAddr);
+        });
+        // Repeat first two to make sure they are repeatable
+        checkNormal(() -> {
+            client = SocketChannel.open(StandardProtocolFamily.UNIX);
+            client.bind(cAddr);
+        });
+        checkNormal(() -> {
+            server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+            server.bind(sAddr);
+        });
+        // client bind to null: allowed
+        checkNormal(() -> {
+            client = SocketChannel.open(StandardProtocolFamily.UNIX);
+            client.bind(null);
+            SocketAddress a = client.getLocalAddress();
+            assertAddress(client.getLocalAddress(), nullAddr, "null address");
+        });
+        // server bind to null: not allowed
+        checkException(
+            BindException.class, () -> {
+                server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+                server.bind(null);
+            }
+        );
+        // server no bind : not allowed
+        checkException(
+            NotYetBoundException.class, () -> {
+                server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+                server.accept();
+            }
+        );
+        // client implicit bind and connect
+        checkNormal(() -> {
+            server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+            client = SocketChannel.open(StandardProtocolFamily.UNIX);
+            server.bind(sAddr);
+            client.connect(sAddr);
+            assertAddress(client.getLocalAddress(), nullAddr, "null address");
+            assertServerAddress(server.getLocalAddress());
+        });
+        // client null bind and connect (check all addresses)
+        checkNormal(() -> {
+            server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+            client = SocketChannel.open(StandardProtocolFamily.UNIX);
+            server.bind(sAddr);
+            client.bind(null);
+            client.connect(sAddr);
+            assertAddress(client.getLocalAddress(), nullAddr, "null address");
+            assertServerAddress(server.getLocalAddress());
+        });
+        // client explicit bind and connect (check all addresses)
+        checkNormal(() -> {
+            server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+            client = SocketChannel.open(StandardProtocolFamily.UNIX);
+            server.bind(sAddr);
+            client.bind(cAddr);
+            client.connect(sAddr);
+            accept1 = server.accept();
+            assertClientAddress(client.getLocalAddress());
+            assertServerAddress(server.getLocalAddress());
+            assertAddress(client.getRemoteAddress(), sAddr, "client's remote server address");
+            assertAddress(accept1.getLocalAddress(), sAddr, "accepted local address (server)");
+            assertAddress(accept1.getRemoteAddress(), cAddr, "accepted remote address (client)");
+        });
+        // server multiple bind : not allowed
+        checkException(
+            AlreadyBoundException.class, () -> {
+                server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+                server.bind(sAddr);
+                server.bind(sAddr);
+            }
+        );
+        // client multiple bind : not allowed
+        checkException(
+            AlreadyBoundException.class, () -> {
+                client = SocketChannel.open(StandardProtocolFamily.UNIX);
+                client.bind(cAddr);
+                client.bind(cAddr);
+            }
+        );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/unixdomain/SocketOptions.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8231358
+ * @run main SocketOptions
+ * @summary Socket option test
+ */
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Set;
+
+/**
+ * Check that all supported options can actually be set and got
+ */
+public class SocketOptions {
+
+    public static void main(String args[]) throws Exception {
+        if (!supported()) {
+            System.out.println("Unix domain channels not supported");
+            return;
+        }
+        test(ServerSocketChannel.open(StandardProtocolFamily.UNIX));
+        test(SocketChannel.open(StandardProtocolFamily.UNIX));
+    }
+
+    static boolean supported() {
+	try {
+	    SocketChannel.open(StandardProtocolFamily.UNIX);
+	} catch (UnsupportedAddressTypeException e) {
+	    return false;
+	} catch (Exception e) {
+	    return true; // continue test to see what problem is
+	}
+	return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void test(NetworkChannel chan) throws IOException {
+        System.out.println("Checking: " + chan.getClass());
+        Set<SocketOption<?>> supported = chan.supportedOptions();
+        for (SocketOption<?> option : supported) {
+            String name = option.name();
+            System.out.println("Checking option " + name);
+            if (option.type() == Boolean.class) {
+                chan.setOption((SocketOption<Boolean>)option, true);
+                chan.setOption((SocketOption<Boolean>)option, false);
+                chan.getOption(option);
+            } else if (option.type() == Integer.class) {
+                chan.setOption((SocketOption<Integer>)option, 10);
+                chan.getOption(option);
+            }
+        }
+    }
+}
--- a/test/jdk/jdk/nio/Basic.java	Fri Nov 29 10:20:17 2019 +0100
+++ b/test/jdk/jdk/nio/Basic.java	Fri Nov 29 10:02:07 2019 +0000
@@ -265,11 +265,20 @@
     }
 
     private static FileDescriptor getFD(SocketChannel sc) {
+	return getFD1(sc, sc.getClass());
+    }
+
+    private static FileDescriptor getFD1(SocketChannel sc, Class<?> clazz) {
         try {
-            Class<?> clazz = sc.getClass();
             Field f = clazz.getDeclaredField("fd");
             f.setAccessible(true);
             return (FileDescriptor) f.get(sc);
+        } catch (NoSuchFieldException e1) {
+	    Class<?> superclass = clazz.getSuperclass();
+	    if (superclass == null)
+		throw new Error(e1);
+	    else
+		return getFD1(sc, superclass);
         } catch (Exception e) {
             throw new Error(e);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/net/SocketChannelCompare.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014 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.
+ *
+ * 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 org.openjdk.bench.java.net;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.channels.UnixDomainSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.file.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * Tests sending a 128 byte message on a second, to a thread which
+ * echo's it back and received by the original thread.
+ * Benchmark is performed for "inet" channels over TCP/IP
+ * and "unix" domain channels.
+ */
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Thread)
+public class SocketChannelCompare {
+
+    static final int BUFSIZE = 128; // message size sent and received
+    private ServerSocketChannel ssc;
+    private SocketChannel s1, s2;
+    private EchoThread rt;
+    private ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
+
+    private static volatile String tempDir;
+    private static final AtomicInteger count = new AtomicInteger(0);
+    private volatile Path socket;
+
+    @Param({"inet", "unix"})
+    private volatile String family;
+
+    static {
+        try {
+            Path p = Files.createTempDirectory("readWriteTest");
+            tempDir = p.toString();
+        } catch (IOException e) {
+            tempDir = null;
+        }
+    }
+
+    private ServerSocketChannel getServerSocketChannel() throws IOException {
+        if (family.equals("inet"))
+            return getInetServerSocketChannel();
+        else if (family.equals("unix"))
+            return getUnixServerSocketChannel();
+        throw new InternalError();
+    }
+
+
+    private ServerSocketChannel getInetServerSocketChannel() throws IOException {
+        InetAddress iaddr = InetAddress.getLoopbackAddress();
+        return ServerSocketChannel.open().bind(null);
+    }
+
+    private ServerSocketChannel getUnixServerSocketChannel() throws IOException {
+        int next = count.incrementAndGet();
+        socket = Paths.get(tempDir, Integer.toString(next));
+        UnixDomainSocketAddress addr = new UnixDomainSocketAddress(socket);
+        return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr);
+    }
+
+    @Setup(Level.Trial)
+    public void beforeRun() throws IOException {
+        ssc = getServerSocketChannel();
+        s1 = SocketChannel.open(ssc.getLocalAddress());
+        s2 = ssc.accept();
+
+        rt = new EchoThread(s2);
+        rt.start();
+    }
+
+    @TearDown(Level.Trial)
+    public void afterRun() throws IOException, InterruptedException {
+        s1.close();
+        s2.close();
+        ssc.close();
+        if (family.equals("unix")) {
+            Files.delete(socket);
+            Files.delete(Path.of(tempDir));
+        }
+        rt.join();
+    }
+
+    @Benchmark
+    public void test() throws IOException {
+        bb.position(0).limit(BUFSIZE);
+        s1.write(bb);
+        bb.clear();
+        readFully(s1, bb);
+    }
+
+    // read until buf is full, or EOF. Always returns number of bytes read
+
+    static int readFully(SocketChannel chan, ByteBuffer buf) throws IOException {
+        int n = buf.remaining();
+        int count = 0;
+        while (n > 0) {
+            int c = chan.read(buf);
+            if (c == -1)
+                return count;
+            n -= c;
+            count += c;
+        }
+        return count;
+    }
+
+    static class EchoThread extends Thread {
+        private SocketChannel sc;
+
+        public EchoThread(SocketChannel s2) {
+            this.sc = s2;
+        }
+
+        public void run() {
+            try {
+                ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
+                while (true) {
+                    bb.clear();
+                    int c = readFully(sc, bb);
+                    if (c == 0) {
+                        sc.close();
+                        return;
+                    }
+                    bb.flip();
+                    sc.write(bb);
+                }
+            } catch (ClosedChannelException ex) {
+                // shutdown time
+            } catch (IOException ioex) {
+                ioex.printStackTrace();
+            }
+        }
+    }
+
+    public static void main(String[] args) throws RunnerException {
+        Options opt = new OptionsBuilder()
+                .include(org.openjdk.bench.java.net.SocketChannelCompare.class.getSimpleName())
+                .forks(3)
+                .build();
+
+        new Runner(opt).run();
+
+        opt = new OptionsBuilder()
+                .include(org.openjdk.bench.java.net.SocketChannelCompare.class.getSimpleName())
+                .jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true")
+                .forks(3)
+                .build();
+
+        new Runner(opt).run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ * 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 org.openjdk.bench.java.net;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.StandardProtocolFamily;
+import java.nio.channels.UnixDomainSocketAddress;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.file.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * Measures connection setup times
+ */
+@BenchmarkMode(Mode.SingleShotTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Thread)
+public class SocketChannelConnectionSetup {
+
+    private ServerSocketChannel ssc;
+    private SocketChannel s1, s2;
+
+    private static volatile String tempDir;
+    private static final AtomicInteger count = new AtomicInteger(0);
+    private volatile Path socket;
+
+    @Param({"inet", "unix"})
+    private volatile String family;
+
+    static {
+        try {
+            Path p = Files.createTempDirectory("readWriteTest");
+            tempDir = p.toString();
+        } catch (IOException e) {
+            tempDir = null;
+        }
+    }
+
+    private ServerSocketChannel getServerSocketChannel() throws IOException {
+        if (family.equals("inet"))
+            return getInetServerSocketChannel();
+        else if (family.equals("unix"))
+            return getUnixServerSocketChannel();
+        throw new InternalError();
+    }
+
+
+    private ServerSocketChannel getInetServerSocketChannel() throws IOException {
+        InetAddress iaddr = InetAddress.getLoopbackAddress();
+        return ServerSocketChannel.open().bind(null);
+    }
+
+    private ServerSocketChannel getUnixServerSocketChannel() throws IOException {
+        int next = count.incrementAndGet();
+        socket = Paths.get(tempDir, Integer.toString(next));
+        UnixDomainSocketAddress addr = new UnixDomainSocketAddress(socket);
+        return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr);
+    }
+
+    @Setup(Level.Trial)
+    public void beforeRun() throws IOException {
+        ssc = getServerSocketChannel();
+    }
+
+    @TearDown(Level.Trial)
+    public void afterRun() throws IOException, InterruptedException {
+        ssc.close();
+        if (family.equals("unix")) {
+            Files.delete(socket);
+            Files.delete(Path.of(tempDir));
+        }
+    }
+
+    @Benchmark
+    @Measurement(iterations = 5, batchSize=50)
+    public void test() throws IOException {
+        s1 = SocketChannel.open(ssc.getLocalAddress());
+        s2 = ssc.accept();
+        s1.close();
+        s2.close();
+    }
+
+    public static void main(String[] args) throws RunnerException {
+        Options opt = new OptionsBuilder()
+                .include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName())
+                .forks(3)
+                .build();
+
+        new Runner(opt).run();
+
+        opt = new OptionsBuilder()
+                .include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName())
+                .jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true")
+                .forks(3)
+                .build();
+
+        new Runner(opt).run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java	Fri Nov 29 10:02:07 2019 +0000
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2014 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.
+ *
+ * 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 org.openjdk.bench.java.net;
+
+import java.io.IOException;
+import java.net.StandardProtocolFamily;
+import java.nio.channels.UnixDomainSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.file.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.openjdk.jmh.annotations.*;
+
+/**
+ * Tests the overheads of I/O API.
+ * This test is known to depend heavily on network conditions and paltform.
+ */
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@State(Scope.Thread)
+public class UnixSocketChannelReadWrite {
+
+    private ServerSocketChannel ssc;
+    private SocketChannel s1, s2;
+    private ReadThread rt;
+    private ByteBuffer bb = ByteBuffer.allocate(1);
+
+    private static volatile String tempDir;
+    private static final AtomicInteger count = new AtomicInteger(0);
+    private volatile Path socket;
+
+    static {
+        try {
+            Path p = Files.createTempDirectory("readWriteTest");
+            tempDir = p.toString();
+        } catch (IOException e) {
+            tempDir = null;
+        }
+    }
+
+    private ServerSocketChannel getServerSocketChannel() throws IOException {
+        int next = count.incrementAndGet();
+        socket = Paths.get(tempDir, Integer.toString(next));
+        UnixDomainSocketAddress addr = new UnixDomainSocketAddress(socket);
+        ServerSocketChannel c = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+        c.bind(addr);
+        return c;
+    }
+
+    @Setup(Level.Trial)
+    public void beforeRun() throws IOException {
+        ssc = getServerSocketChannel();
+        s1 = SocketChannel.open(ssc.getLocalAddress());
+        s2 = ssc.accept();
+
+        rt = new ReadThread(s2);
+        rt.start();
+
+        bb.put((byte) 47);
+        bb.flip();
+    }
+
+    @TearDown(Level.Trial)
+    public void afterRun() throws IOException, InterruptedException {
+        s1.close();
+        s2.close();
+        ssc.close();
+        Files.delete(socket);
+        Files.delete(Path.of(tempDir));
+        rt.join();
+    }
+
+    @Benchmark
+    public void test() throws IOException {
+        s1.write(bb);
+        bb.flip();
+    }
+
+    static class ReadThread extends Thread {
+        private SocketChannel sc;
+
+        public ReadThread(SocketChannel s2) {
+            this.sc = s2;
+        }
+
+        public void run() {
+            try {
+                ByteBuffer bb = ByteBuffer.allocate(1);
+                while (sc.read(bb) > 0) {
+                    bb.flip();
+                }
+            } catch (ClosedChannelException ex) {
+                // shutdown time
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+}