--- a/src/java.base/share/classes/java/net/StandardProtocolFamily.java Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/java/net/StandardProtocolFamily.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/java/nio/channels/SocketChannel.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/net/util/SocketExceptions.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/Secrets.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/share/native/libnet/net_util.h Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/unix/native/libnet/net_util_md.h Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/unix/native/libnio/ch/InheritedChannel.c Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/unix/native/libnio/ch/Net.c Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/windows/native/libnet/net_util_md.h Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/src/java.base/windows/native/libnio/ch/Net.c Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:00:32 2019 +0100
+++ b/test/jdk/jdk/nio/Basic.java Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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 Mon Nov 25 15:16:29 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();
+ }
+ }
+ }
+
+}