# HG changeset patch # User michaelm # Date 1572015395 -3600 # Node ID 119ac9128c1b7de32022f0aa2a35094dfa825c73 # Parent eb491334113f6f01b514dbfead9e231f8d6ce2db Initial implementation of unix domain channels. See j.n.c.{Server}SocketChannel apidoc diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/java/net/StandardProtocolFamily.java --- a/src/java.base/share/classes/java/net/StandardProtocolFamily.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/java/net/StandardProtocolFamily.java Fri Oct 25 15:56:35 2019 +0100 @@ -41,5 +41,10 @@ /** * Internet Protocol Version 6 (IPv6) */ - INET6 + INET6, + + /** + * Unix domain (AF_UNIX) + */ + UNIX } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java --- a/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java Fri Oct 25 15:56:35 2019 +0100 @@ -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,26 @@ /** * A selectable channel for stream-oriented listening sockets. * - *

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, + *

A server-socket channel is created by invoking 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. * + *

Two kinds of server-socket channel are supported: IP (Internet Protocol) + * and unix domain depending on which open method is used to create them and which subtype of + * {@link SocketAddress} that they support for local and remote addresses. + * IP channels are created using {@link #open()}. They use {@link + * InetSocketAddress} addresses and support both IPv4 and IPv6 TCP/IP. + * unix domain 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. + * *

Socket options are configured using the {@link #setOption(SocketOption,Object) - * setOption} method. Server-socket channels support the following options: + * setOption} method. IP server-socket channels support the following options: *

* * @@ -66,11 +78,14 @@ * *
Socket options
*
+ * * Additional (implementation specific) options may also be supported. * *

Server-socket channels are safe for use by multiple concurrent threads. *

* + *

Unix domain server-socket channels support a subset of the options listed above. + * * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 @@ -92,7 +107,7 @@ } /** - * Opens a server-socket channel. + * Opens an IP server-socket channel. * *

The new channel is created by invoking the {@link * java.nio.channels.spi.SelectorProvider#openServerSocketChannel @@ -114,6 +129,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 jdk.net.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 +184,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 IP channels or for unix domain + * channels, if the security manager denies "read" or "write" + * {@link FilePermission} for the local path. * * @since 1.7 */ @@ -177,6 +213,11 @@ * the value {@code 0}, or a negative value, then an implementation specific * default is used. * + *

Note, for Unix domain 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. + * * @param local * The address to bind the socket, or {@code null} to bind to an * automatically assigned socket address @@ -194,9 +235,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 IP channels or for unix domain + * channels, if the security manager denies "read" or "write" + * {@link FilePermission} for the local path. * * @since 1.7 */ @@ -215,12 +258,14 @@ throws IOException; /** - * Retrieves a server socket associated with this channel. + * Retrieves a server socket associated with this channel if it is an IP + * channel. The operation is not supported for unix domain channels. * *

The returned object will not declare any public methods that are not * declared in the {@link java.net.ServerSocket} class.

* * @return A server socket associated with this channel + * @throws UnsupportedOperationException is this is a Unix domain channel */ public abstract ServerSocket socket(); @@ -235,7 +280,7 @@ *

The socket channel returned by this method, if any, will be in * blocking mode regardless of the blocking mode of this channel. * - *

This method performs exactly the same security checks as the {@link + *

For IP 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 @@ -243,6 +288,11 @@ * permitted by the security manager's {@link * java.lang.SecurityManager#checkAccept checkAccept} method.

* + *

For unix domain 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 @@ -276,12 +326,17 @@ /** * {@inheritDoc} *

- * If there is a security manager set, its {@code checkConnect} method is + * If there is a security manager set and this is an IP 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. + *

+ * If there is a security manager set and this is an unix domain channel, + * then this returns a {@link UnixDomainSocketAddress} corresponding to the + * bound address. * * @return The {@code SocketAddress} that the socket is bound to, or the * {@code SocketAddress} representing the loopback address if diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/java/nio/channels/SocketChannel.java --- a/src/java.base/share/classes/java/nio/channels/SocketChannel.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/java/nio/channels/SocketChannel.java Fri Oct 25 15:56:35 2019 +0100 @@ -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. * - *

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, + *

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,18 @@ * channel, then the blocked thread will receive an {@link * AsynchronousCloseException}. * + *

Two kinds of socket channel are supported: IP (Internet Protocol) and + * unix domain depending on which open method is used to create them and which + * subtype of {@link SocketAddress} that they support for local and remote addresses. + * IP channels are created using {@link #open()}. They use {@link + * InetSocketAddress} addresses and support both IPv4 and IPv6 TCP/IP. + * unix domain 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. + * *

Socket options are configured using the {@link #setOption(SocketOption,Object) - * setOption} method. Socket channels support the following options: + * setOption} method. IP socket channels support the following options: *

* * @@ -103,6 +116,7 @@ * *
Socket options
*
+ * * Additional (implementation specific) options may also be supported. * *

Socket channels are safe for use by multiple concurrent threads. They @@ -113,6 +127,8 @@ * or write operation while an invocation of one of these methods is in * progress will block until that invocation is complete.

* + *

Unix domain channels support a subset of the options listed above. + * * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 @@ -124,7 +140,7 @@ { /** - * Initializes a new instance of this class. + * Initializes a new IP instance of this class. * * @param provider * The provider that created this channel @@ -134,7 +150,7 @@ } /** - * Opens a socket channel. + * Opens an IP socket channel. * *

The new channel is created by invoking the {@link * java.nio.channels.spi.SelectorProvider#openSocketChannel @@ -151,13 +167,36 @@ } /** - * 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 * - *

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 IP or unix domain channel. + * + *

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.

* + *

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}, and then + * returning that channel.

+ * * @param remote * The remote address to which the new channel is to be connected * @@ -174,7 +213,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 +228,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 +271,13 @@ // -- Socket-specific operations -- /** + * {@inheritDoc} + * + *

Note, for Unix domain 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. + * * @throws ConnectionPendingException * If a non-blocking connect operation is already in progress on * this channel @@ -235,7 +288,9 @@ * @throws SecurityException * If a security manager has been installed and its * {@link SecurityManager#checkListen checkListen} method denies - * the operation + * the operation for IP channels or for unix domain + * channels, if the security manager denies "read" or "write" + * {@link FilePermission} for the local path. * * @since 1.7 */ @@ -297,12 +352,14 @@ public abstract SocketChannel shutdownOutput() throws IOException; /** - * Retrieves a socket associated with this channel. + * Retrieves a socket associated with this channel if it is an IP + * channel. The operation is not supported for unix domain channels. * *

The returned object will not declare any public methods that are not * declared in the {@link java.net.Socket} class.

* * @return A socket associated with this channel + * @throws UnsupportedOperationException is this is a Unix domain channel */ public abstract Socket socket(); @@ -338,12 +395,17 @@ * method will block until the connection is established or an I/O error * occurs. * - *

This method performs exactly the same security checks as the {@link - * java.net.Socket} class. That is, if a security manager has been + *

For IP 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. * + *

For unix domain 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. + * *

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 +441,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 +513,9 @@ * socket address then the return value from this method is of type {@link * java.net.InetSocketAddress}. * + *

Where the channel is bound and connected to a Unix domain + * address, the returned address is a {@link UnixDomainSocketAddress} + * * @return The remote address; {@code null} if the channel's socket is not * connected * @@ -510,12 +575,17 @@ /** * {@inheritDoc} *

- * If there is a security manager set, its {@code checkConnect} method is + * If there is a security manager set and this is an IP 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. + *

+ * If there is a security manager set and this is an unix domain channel, + * then this returns a {@link UnixDomainSocketAddress} corresponding to the + * bound address. * * @return The {@code SocketAddress} that the socket is bound to, or the * {@code SocketAddress} representing the loopback address if @@ -527,5 +597,4 @@ */ @Override public abstract SocketAddress getLocalAddress() throws IOException; - } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/java/nio/channels/UnixDomainSocketAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/nio/channels/UnixDomainSocketAddress.java Fri Oct 25 15:56:35 2019 +0100 @@ -0,0 +1,129 @@ +/* + * 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 socket or server socket channel. 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. + *

+ * If a channel is automatically bound to Unix domain address then its address + * is unnamed, has an empty path field, and therefore has no associated + * file in the file-system. + *

+ * Note, not all channel types support Unix domain addresses. + * + * @since 14 + */ +public class UnixDomainSocketAddress extends SocketAddress { + + static final long serialVersionUID = 9829020419651288L; + + static { + if (System.getSecurityManager() == null) { + System.loadLibrary("nio"); + } else { + AccessController.doPrivileged((PrivilegedAction) () -> { + 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); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("af_unix:"); + if (path != null) + sb.append(path); + return sb.toString(); + } +} diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java --- a/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java Fri Oct 25 15:56:35 2019 +0100 @@ -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; + } } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/module-info.java --- a/src/java.base/share/classes/module-info.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/module-info.java Fri Oct 25 15:56:35 2019 +0100 @@ -232,6 +232,7 @@ jdk.jfr; exports sun.net to java.net.http, + jdk.net, jdk.naming.dns; exports sun.net.ext to jdk.net; @@ -241,6 +242,7 @@ exports sun.net.util to java.desktop, jdk.jconsole, + jdk.net, java.net.http; exports sun.net.www to java.net.http, @@ -267,7 +269,8 @@ java.sql.rowset; exports sun.security.action to java.desktop, - java.security.jgss; + java.security.jgss, + jdk.net; exports sun.security.internal.interfaces to jdk.crypto.cryptoki; exports sun.security.internal.spec to diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/net/util/SocketExceptions.java --- a/src/java.base/share/classes/sun/net/util/SocketExceptions.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/net/util/SocketExceptions.java Fri Oct 25 15:56:35 2019 +0100 @@ -28,6 +28,7 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.security.AccessController; import java.security.PrivilegedAction; @@ -51,7 +52,10 @@ * * 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 InetSocketAddress)) + return e; + InetSocketAddress address = (InetSocketAddress)addr; if (!enhancedExceptionText || address == null) return e; int port = address.getPort(); diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/IOStatus.java --- a/src/java.base/share/classes/sun/nio/ch/IOStatus.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/IOStatus.java Fri Oct 25 15:56:35 2019 +0100 @@ -85,7 +85,7 @@ * Returns true if the error code is UNAVAILABLE or INTERRUPTED, the * error codes to indicate that an I/O operation can be retried. */ - static boolean okayToRetry(long n) { + public static boolean okayToRetry(long n) { return (n == IOStatus.UNAVAILABLE) || (n == IOStatus.INTERRUPTED); } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/IOUtil.java --- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java Fri Oct 25 15:56:35 2019 +0100 @@ -43,14 +43,14 @@ private IOUtil() { } // No instantiation - static int write(FileDescriptor fd, ByteBuffer src, long position, + public static int write(FileDescriptor fd, ByteBuffer src, long position, NativeDispatcher nd) throws IOException { return write(fd, src, position, false, -1, nd); } - static int write(FileDescriptor fd, ByteBuffer src, long position, + public static int write(FileDescriptor fd, ByteBuffer src, long position, boolean directIO, int alignment, NativeDispatcher nd) throws IOException { @@ -117,20 +117,20 @@ return written; } - static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) + public static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) throws IOException { return write(fd, bufs, 0, bufs.length, false, -1, nd); } - static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + public static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, NativeDispatcher nd) throws IOException { return write(fd, bufs, offset, length, false, -1, nd); } - static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + public static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, boolean directIO, int alignment, NativeDispatcher nd) throws IOException { @@ -216,14 +216,14 @@ } } - static int read(FileDescriptor fd, ByteBuffer dst, long position, + public static int read(FileDescriptor fd, ByteBuffer dst, long position, NativeDispatcher nd) throws IOException { return read(fd, dst, position, false, -1, nd); } - static int read(FileDescriptor fd, ByteBuffer dst, long position, + public static int read(FileDescriptor fd, ByteBuffer dst, long position, boolean directIO, int alignment, NativeDispatcher nd) throws IOException { @@ -280,20 +280,20 @@ return n; } - static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) + public static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) throws IOException { return read(fd, bufs, 0, bufs.length, false, -1, nd); } - static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + public static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, NativeDispatcher nd) throws IOException { return read(fd, bufs, offset, length, false, -1, nd); } - static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + public static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, boolean directIO, int alignment, NativeDispatcher nd) throws IOException { diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/InetServerSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/sun/nio/ch/InetServerSocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -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 ServerSocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> 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> 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; + } + } +} diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/InetSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/sun/nio/ch/InetSocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -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 SocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> 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> 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); + } +} diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/NativeDispatcher.java --- a/src/java.base/share/classes/sun/nio/ch/NativeDispatcher.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/NativeDispatcher.java Fri Oct 25 15:56:35 2019 +0100 @@ -32,10 +32,10 @@ * for read and write operations. */ -abstract class NativeDispatcher +public abstract class NativeDispatcher { - abstract int read(FileDescriptor fd, long address, int len) + public abstract int read(FileDescriptor fd, long address, int len) throws IOException; /** @@ -55,7 +55,7 @@ abstract long readv(FileDescriptor fd, long address, int len) throws IOException; - abstract int write(FileDescriptor fd, long address, int len) + public abstract int write(FileDescriptor fd, long address, int len) throws IOException; int pwrite(FileDescriptor fd, long address, int len, long position) @@ -67,13 +67,13 @@ abstract long writev(FileDescriptor fd, long address, int len) throws IOException; - abstract void close(FileDescriptor fd) throws IOException; + public abstract void close(FileDescriptor fd) throws IOException; // Prepare the given fd for closing by duping it to a known internal fd // that's already closed. This is necessary on some operating systems // (Solaris and Linux) to prevent fd recycling. // - void preClose(FileDescriptor fd) throws IOException { + public void preClose(FileDescriptor fd) throws IOException { // Do nothing by default; this is only needed on Unix } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/Net.java --- a/src/java.base/share/classes/sun/nio/ch/Net.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/Net.java Fri Oct 25 15:56:35 2019 +0100 @@ -43,6 +43,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; @@ -53,17 +54,31 @@ import sun.net.util.IPAddressUtil; import sun.security.action.GetPropertyAction; + public class Net { - private Net() { } + public Net() { } + + private static final boolean unixDomainSupported; + //private static final boolean abstractNamesSupported; // unspecified protocol family - static final ProtocolFamily UNSPEC = new ProtocolFamily() { + public static final ProtocolFamily UNSPEC = new ProtocolFamily() { public String name() { return "UNSPEC"; } }; + static { + unixDomainSupported = unixDomainSocketSupported(); + String name = GetPropertyAction.privilegedGetProperty("os.name") + .toLowerCase(); + + // Windows claims to support it but doesn't. Disable for now + //abstractNamesSupported = name.startsWith("linux"); + // || name.startsWith("windows"); + } + // set to true if exclusive binding is on for Windows private static final boolean exclusiveBind; @@ -102,7 +117,7 @@ /** * Returns true if exclusive binding is on */ - static boolean useExclusiveBind() { + public static boolean useExclusiveBind() { return exclusiveBind; } @@ -311,13 +326,13 @@ static final ExtendedSocketOptions extendedOptions = ExtendedSocketOptions.getInstance(); - static void setSocketOption(FileDescriptor fd, SocketOption name, Object value) + public static void setSocketOption(FileDescriptor fd, SocketOption name, Object value) throws IOException { setSocketOption(fd, Net.UNSPEC, name, value); } - static void setSocketOption(FileDescriptor fd, ProtocolFamily family, + public static void setSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption name, Object value) throws IOException { @@ -379,13 +394,13 @@ setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6); } - static Object getSocketOption(FileDescriptor fd, SocketOption name) + public static Object getSocketOption(FileDescriptor fd, SocketOption name) throws IOException { return getSocketOption(fd, Net.UNSPEC, name); } - static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption name) + public static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption name) throws IOException { Class type = name.type(); @@ -444,7 +459,7 @@ return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback)); } - static FileDescriptor serverSocket(boolean stream) { + public static FileDescriptor serverSocket(boolean stream) { return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback)); } @@ -474,7 +489,7 @@ int port) throws IOException; - static native void listen(FileDescriptor fd, int backlog) throws IOException; + public static native void listen(FileDescriptor fd, int backlog) throws IOException; static int connect(FileDescriptor fd, InetAddress remote, int remotePort) throws IOException @@ -508,7 +523,7 @@ public static final int SHUT_WR = 1; public static final int SHUT_RDWR = 2; - static native void shutdown(FileDescriptor fd, int how) throws IOException; + public static native void shutdown(FileDescriptor fd, int how) throws IOException; private static native int localPort(FileDescriptor fd) throws IOException; @@ -575,14 +590,14 @@ * * @return true if connected */ - static boolean pollConnectNow(FileDescriptor fd) throws IOException { + public static boolean pollConnectNow(FileDescriptor fd) throws IOException { return pollConnect(fd, 0); } /** * Return the number of bytes in the socket input buffer. */ - static native int available(FileDescriptor fd) throws IOException; + public static native int available(FileDescriptor fd) throws IOException; /** * Send one byte of urgent data (MSG_OOB) on the socket. @@ -693,6 +708,56 @@ */ public static final short POLLIN; public static final short POLLOUT; + + public static boolean isUnixDomainSupported() { + return unixDomainSupported; + } + + public static UnixDomainSocketAddress checkUnixAddress(SocketAddress sa) { + if (sa == null) + throw new NullPointerException(); + if (!(sa instanceof UnixDomainSocketAddress)) + throw new UnsupportedAddressTypeException(); + UnixDomainSocketAddress usa = (UnixDomainSocketAddress)sa; + //if (usa.isAbstract() && !abstractNamesSupported()) + //throw new UnsupportedAddressTypeException(); + return usa; + } + + /** + * 2 methods to be implemented if fine-grained security to be used + */ + static UnixDomainSocketAddress getRevealedLocalAddress(UnixDomainSocketAddress addr) { + return addr; + } + + static String getRevealedLocalAddressAsString(UnixDomainSocketAddress addr) { + return addr.toString(); + } + + // -- Socket operations -- + + public static FileDescriptor unixDomainSocket() throws IOException { + return IOUtil.newFD(unixDomainSocket0()); + } + + public static native boolean unixDomainSocketSupported(); + + private static native int unixDomainSocket0(); + + 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; @@ -736,4 +801,6 @@ fastLoopback = isFastTcpLoopbackRequested(); } + + } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/Secrets.java --- a/src/java.base/share/classes/sun/nio/ch/Secrets.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/Secrets.java Fri Oct 25 15:56:35 2019 +0100 @@ -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); } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java --- a/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -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) { + 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) { + return new UnixDomainServerSocketChannelImpl(this); + } else + throw new UnsupportedAddressTypeException(); } } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java Fri Oct 25 15:56:35 2019 +0100 @@ -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 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 { diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -55,80 +55,57 @@ * An implementation of ServerSocketChannels */ -class ServerSocketChannelImpl +public 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 ServerSocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); - - private static Set> defaultOptions() { - HashSet> 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> 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 @@ -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 { @@ -488,7 +369,7 @@ /** * Returns the local address, or null if not bound */ - InetSocketAddress localAddress() { + SocketAddress localAddress() { synchronized (stateLock) { return localAddress; } @@ -557,11 +438,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)); } } } diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java --- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java Fri Oct 25 15:56:35 2019 +0100 @@ -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 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 { diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -64,7 +64,7 @@ * An implementation of SocketChannels */ -class SocketChannelImpl +public abstract class SocketChannelImpl extends SocketChannel implements SelChImpl { @@ -72,87 +72,64 @@ 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 // Constructor for normal connecting sockets // - SocketChannelImpl(SelectorProvider sp) throws IOException { + public SocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.socket(true); this.fdVal = IOUtil.fdVal(fd); } - SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) + public 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 SocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); - - private static Set> defaultOptions() { - HashSet> 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> 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(); @@ -586,7 +422,7 @@ /** * Returns the local address, or null if not bound */ - InetSocketAddress localAddress() { + SocketAddress localAddress() { synchronized (stateLock) { return localAddress; } @@ -595,44 +431,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); } @@ -651,7 +456,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) { @@ -668,9 +473,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 @@ -686,7 +493,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); @@ -694,7 +501,7 @@ if (completed) { synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { - localAddress = Net.localAddress(fd); + localAddress = localAddressImpl(fd); state = ST_CONNECTED; } } @@ -704,22 +511,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 { @@ -728,8 +526,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) { @@ -754,7 +552,7 @@ } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, isa); + throw SocketExceptions.of(ioe, sa); } } @@ -780,6 +578,9 @@ } } + abstract SocketAddress localAddressImpl(FileDescriptor fd) + throws IOException; + /** * Marks the end of a finishConnect operation that may have blocked. * @@ -795,7 +596,7 @@ if (completed) { synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { - localAddress = Net.localAddress(fd); + localAddress = localAddressImpl(fd); state = ST_CONNECTED; } } @@ -964,6 +765,13 @@ } } + /** + * Package private version called from InheritedChannel + */ + void localImplCloseSelectableChannel() throws IOException { + implCloseSelectableChannel(); + } + @Override public SocketChannel shutdownInput() throws IOException { synchronized (stateLock) { @@ -1034,7 +842,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 { @@ -1044,11 +852,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 @@ -1066,7 +874,7 @@ } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, isa); + throw SocketExceptions.of(ioe, sa); } } @@ -1309,6 +1117,8 @@ return fdVal; } + abstract String getRevealedLocalAddressAsString(SocketAddress sa); + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -1333,10 +1143,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="); diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/UnixDomainServerSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainServerSocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -0,0 +1,212 @@ +/* + * 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.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 ServerSocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet<>(); + set.add(StandardSocketOptions.SO_RCVBUF); + set.addAll(ExtendedSocketOptions.serverSocketOptions()); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; + } + + @Override + public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { + 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(); + } +} diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -0,0 +1,229 @@ +/* + * 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); + } + } + } + +/* + public static AbstractSocketChannelImpl create(SelectorProvider sp, FileDescriptor fd) { + try { + return new UnixDomainSocketChannelImpl(sp, fd, false); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +*/ + + // 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 SocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet<>(); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_REUSEADDR); // TODO: DELETE ME + set.add(StandardSocketOptions.SO_KEEPALIVE); + set.add(StandardSocketOptions.SO_LINGER); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> 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(); + if (local == null) + throw new NullPointerException(); // TODO: ?? + UnixDomainSocketAddress usa = Net.checkUnixAddress(local); + Net.unixDomainBind(fd, usa); + 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 + } + +} diff -r eb491334113f -r 119ac9128c1b src/java.base/share/classes/sun/nio/ch/Util.java --- a/src/java.base/share/classes/sun/nio/ch/Util.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/classes/sun/nio/ch/Util.java Fri Oct 25 15:56:35 2019 +0100 @@ -282,7 +282,7 @@ * returning to the cache then insert it at the start so that it is * likely to be returned by a subsequent call to getTemporaryDirectBuffer. */ - static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { + public static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { // If the buffer is too large for the cache we don't have to // check the cache. We'll just free it. if (isBufferTooLarge(buf)) { diff -r eb491334113f -r 119ac9128c1b src/java.base/share/native/libnet/net_util.h --- a/src/java.base/share/native/libnet/net_util.h Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/share/native/libnet/net_util.h Fri Oct 25 15:56:35 2019 +0100 @@ -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 * @@ -111,6 +114,12 @@ extern jfieldID ia6_scopeifnameID; extern jmethodID ia6_ctrID; +/* UnixDomainSocketAddress methods */ +extern jclass udsa_class; +extern jmethodID udsa_ctorID; +extern jfieldID udsa_pathID; +extern jfieldID udsa_isAbstractID; + /************************************************************************ * Utilities */ @@ -157,6 +166,12 @@ JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port); +JNIEXPORT jobject JNICALL +NET_SockaddrToUnixAddress(JNIEnv *env, SOCKETADDRESS *sa); + +JNIEXPORT jint JNICALL +NET_UnixSocketAddressToSockaddr(JNIEnv *env, jobject uaddr, SOCKETADDRESS *sa, int *len); + void platformInit(); void parseExclusiveBindProperty(JNIEnv *env); diff -r eb491334113f -r 119ac9128c1b src/java.base/share/native/libnio/ch/UnixDomainSocketAddress.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/native/libnio/ch/UnixDomainSocketAddress.c Fri Oct 25 15:56:35 2019 +0100 @@ -0,0 +1,66 @@ +/* + * 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 + +#include "java_nio_channels_UnixDomainSocketAddress.h" +#include "net_util.h" + +/************************************************************************ + * UnixDomainSocketAddress + */ + +jclass udsa_class; +jmethodID udsa_ctorID; +jfieldID udsa_pathID; +//jfieldID udsa_isAbstractID; + +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 cls) { + 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_isAbstractID = (*env)->GetFieldID(env, udsa_class, "isAbstract", "Z"); + //CHECK_NULL(udsa_isAbstractID); + + udsa_ctorID = (*env)->GetMethodID(env, udsa_class, "", "(Ljava/lang/String;)V"); + CHECK_NULL(udsa_ctorID); + + udsa_initialized = 1; + } +} diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/classes/sun/nio/ch/DatagramDispatcher.java --- a/src/java.base/unix/classes/sun/nio/ch/DatagramDispatcher.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/classes/sun/nio/ch/DatagramDispatcher.java Fri Oct 25 15:56:35 2019 +0100 @@ -39,7 +39,7 @@ IOUtil.load(); } - int read(FileDescriptor fd, long address, int len) throws IOException { + public int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); } @@ -47,7 +47,7 @@ return readv0(fd, address, len); } - int write(FileDescriptor fd, long address, int len) throws IOException { + public int write(FileDescriptor fd, long address, int len) throws IOException { return write0(fd, address, len); } @@ -55,11 +55,11 @@ return writev0(fd, address, len); } - void close(FileDescriptor fd) throws IOException { + public void close(FileDescriptor fd) throws IOException { FileDispatcherImpl.close0(fd); } - void preClose(FileDescriptor fd) throws IOException { + public void preClose(FileDescriptor fd) throws IOException { FileDispatcherImpl.preClose0(fd); } diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java --- a/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -44,7 +44,7 @@ FileDispatcherImpl() { } - int read(FileDescriptor fd, long address, int len) throws IOException { + public int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); } @@ -58,7 +58,7 @@ return readv0(fd, address, len); } - int write(FileDescriptor fd, long address, int len) throws IOException { + public int write(FileDescriptor fd, long address, int len) throws IOException { return write0(fd, address, len); } @@ -100,11 +100,11 @@ release0(fd, pos, size); } - void close(FileDescriptor fd) throws IOException { + public void close(FileDescriptor fd) throws IOException { fdAccess.close(fd); } - void preClose(FileDescriptor fd) throws IOException { + public void preClose(FileDescriptor fd) throws IOException { preClose0(fd); } diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java --- a/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java Fri Oct 25 15:56:35 2019 +0100 @@ -28,15 +28,22 @@ 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.spi.SelectorProvider; +import java.util.Set; +import java.util.function.BiFunction; -class InheritedChannel { +public class InheritedChannel { // the "types" of socket returned by soType0 private static final int UNKNOWN = -1; @@ -79,9 +86,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 +102,25 @@ } } - public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl { + public static class InheritedUnixSocketChannelImpl extends UnixDomainSocketChannelImpl { - InheritedUnixChannelImpl(FileDescriptor fd) + InheritedUnixSocketChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException { - super(fd); + super(sp, fd, true); } + @Override protected void implCloseSelectableChannel() throws IOException { - super.implCloseChannel(); + super.localImplCloseSelectableChannel(); detachIOStreams(); } } - public static class InheritedServerSocketChannelImpl extends - ServerSocketChannelImpl { + public static class InheritedInetServerSocketChannelImpl extends + InetServerSocketChannelImpl { - InheritedServerSocketChannelImpl(SelectorProvider sp, + InheritedInetServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException { @@ -206,7 +214,7 @@ return null; if (family == AF_UNIX) { if (isConnected(fdVal)) { - return new InheritedUnixChannelImpl(fd); + return new InheritedUnixSocketChannelImpl(provider, fd); } else { // listener. unsupported. return null; @@ -214,12 +222,12 @@ } InetAddress ia = peerAddress0(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); diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java --- a/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/classes/sun/nio/ch/SocketDispatcher.java Fri Oct 25 15:56:35 2019 +0100 @@ -33,8 +33,8 @@ * for read and write operations. */ -class SocketDispatcher extends NativeDispatcher { - SocketDispatcher() { } +public class SocketDispatcher extends NativeDispatcher { + public SocketDispatcher() { } /** * Reads up to len bytes from a socket with special handling for "connection @@ -43,7 +43,7 @@ * @throws sun.net.ConnectionResetException if connection reset is detected * @throws IOException if another I/O error occurs */ - int read(FileDescriptor fd, long address, int len) throws IOException { + public int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); } @@ -58,7 +58,7 @@ return readv0(fd, address, len); } - int write(FileDescriptor fd, long address, int len) throws IOException { + public int write(FileDescriptor fd, long address, int len) throws IOException { return FileDispatcherImpl.write0(fd, address, len); } @@ -66,11 +66,11 @@ return FileDispatcherImpl.writev0(fd, address, len); } - void close(FileDescriptor fd) throws IOException { + public void close(FileDescriptor fd) throws IOException { FileDispatcherImpl.close0(fd); } - void preClose(FileDescriptor fd) throws IOException { + public void preClose(FileDescriptor fd) throws IOException { FileDispatcherImpl.preClose0(fd); } diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java --- a/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java Fri Oct 25 14:50:16 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(); - } -} diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/native/libnet/net_util_md.h --- a/src/java.base/unix/native/libnet/net_util_md.h Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/native/libnet/net_util_md.h Fri Oct 25 15:56:35 2019 +0100 @@ -29,6 +29,8 @@ #include #include #include +#include +#include /************************************************************************ * Macros and constants @@ -71,6 +73,7 @@ struct sockaddr sa; struct sockaddr_in sa4; struct sockaddr_in6 sa6; + struct sockaddr_un saun; } SOCKETADDRESS; /************************************************************************ diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/native/libnio/ch/IOUtil.c --- a/src/java.base/unix/native/libnio/ch/IOUtil.c Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/native/libnio/ch/IOUtil.c Fri Oct 25 15:56:35 2019 +0100 @@ -223,13 +223,13 @@ } } -jint +JNIEXPORT jint JNICALL fdval(JNIEnv *env, jobject fdo) { return (*env)->GetIntField(env, fdo, fd_fdID); } -void +JNIEXPORT void JNICALL setfdval(JNIEnv *env, jobject fdo, jint val) { (*env)->SetIntField(env, fdo, fd_fdID, val); } diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/native/libnio/ch/Net.c --- a/src/java.base/unix/native/libnio/ch/Net.c Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/native/libnio/ch/Net.c Fri Oct 25 15:56:35 2019 +0100 @@ -46,6 +46,182 @@ #include #endif + +extern jclass udsa_class; +extern jmethodID udsa_ctorID; +extern jfieldID udsa_pathID; +extern jfieldID udsa_isAbstractID; + +JNIEXPORT jobject JNICALL +NET_SockaddrToUnixAddress(JNIEnv *env, SOCKETADDRESS *sa) { + jboolean isAbstract = 0; + + if (sa->sa.sa_family == AF_UNIX) { + char *name = sa->saun.sun_path; + +#ifdef NOTDEF + /* check for abstract name */ + if (name[0] == 0) { + isAbstract = 1; + name++; // skip the zero byte + } else + isAbstract = 0; +#endif + 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, SOCKETADDRESS *sa, int *len) +{ + jstring path = (*env)->GetObjectField(env, uaddr, udsa_pathID); + //jboolean isAbstract = (*env)->GetBooleanField(env, uaddr, udsa_isAbstractID); + jboolean isCopy; + int ret; + const char* pname = JNU_GetStringPlatformChars(env, path, &isCopy); + memset(sa, 0, sizeof(SOCKETADDRESS)); + sa->saun.sun_family = AF_UNIX; + int name_len = strlen(pname) + 1; /* includes null termination */ + if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "unix domain path too long"); + ret = 1; + goto finish; + } +#ifdef NOTDEF + if (isAbstract) { + strncpy(&sa->saun.sun_path[1], pname, name_len); + sa->saun.sun_path[0] = 0; + name_len++; + } else +#endif + { + strncpy(&sa->saun.sun_path[0], pname, name_len); + } + *len = offsetof(struct sockaddr_un, sun_path) + name_len; + ret = 0; + finish: + if (isCopy) + JNU_ReleaseStringPlatformChars(env, path, pname); + return ret; +} + +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 jboolean JNICALL +Java_sun_nio_ch_Net_unixDomainSocketSupported(JNIEnv *env, jclass cl) +{ + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + return JNI_FALSE; + } + close(fd); + return JNI_TRUE; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_unixDomainBind(JNIEnv *env, jclass clazz, jobject fdo, jobject uaddr) +{ + SOCKETADDRESS sa; + int sa_len = 0; + int rv = 0; + + if (NET_UnixSocketAddressToSockaddr(env, uaddr, &sa, &sa_len) != 0) + return; + + int fd = fdval(env, fdo); + + rv = NET_Bind(fdval(env, fdo), &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) +{ + SOCKETADDRESS sa; + int sa_len = 0; + int rv; + + if (NET_UnixSocketAddressToSockaddr(env, usa, &sa, &sa_len) != 0) { + return IOS_THROWN; + } + + rv = connect(fdval(env, fdo), &sa.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; + SOCKETADDRESS sa; + socklen_t sa_len = sizeof(SOCKETADDRESS); + jobject usa; + + /* accept connection but ignore ECONNABORTED */ + for (;;) { + newfd = accept(fd, &sa.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); + 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) +{ + SOCKETADDRESS sa; + socklen_t sa_len = sizeof(SOCKETADDRESS); + int port; + if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { + handleSocketError(env, errno); + return NULL; + } + return NET_SockaddrToUnixAddress(env, &sa); +} /** * IP_MULTICAST_ALL supported since 2.6.31 but may not be available at * build time. @@ -867,7 +1043,8 @@ /* Declared in nio_util.h */ -jint handleSocketError(JNIEnv *env, jint errorValue) +JNIEXPORT jint JNICALL +handleSocketError(JNIEnv *env, jint errorValue) { char *xn; switch (errorValue) { diff -r eb491334113f -r 119ac9128c1b src/java.base/unix/native/libnio/ch/nio_util.h --- a/src/java.base/unix/native/libnio/ch/nio_util.h Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/unix/native/libnio/ch/nio_util.h Fri Oct 25 15:56:35 2019 +0100 @@ -54,8 +54,11 @@ /* Defined in IOUtil.c */ -jint fdval(JNIEnv *env, jobject fdo); -void setfdval(JNIEnv *env, jobject fdo, jint value); +JNIEXPORT jint JNICALL +fdval(JNIEnv *env, jobject fdo); + +JNIEXPORT void JNICALL +setfdval(JNIEnv *env, jobject fdo, jint value); jint convertReturnVal(JNIEnv *env, jint n, jboolean reading); jlong convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading); @@ -63,4 +66,5 @@ /* Defined in Net.c */ -jint handleSocketError(JNIEnv *env, jint errorValue); +JNIEXPORT jint JNICALL +handleSocketError(JNIEnv *env, jint errorValue); diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java --- a/src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java Fri Oct 25 15:56:35 2019 +0100 @@ -36,7 +36,7 @@ class DatagramDispatcher extends NativeDispatcher { DatagramDispatcher() { } - int read(FileDescriptor fd, long address, int len) throws IOException { + public int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); } @@ -44,7 +44,7 @@ return readv0(fd, address, len); } - int write(FileDescriptor fd, long address, int len) throws IOException { + public int write(FileDescriptor fd, long address, int len) throws IOException { return write0(fd, address, len); } @@ -52,7 +52,7 @@ return writev0(fd, address, len); } - void close(FileDescriptor fd) throws IOException { + public void close(FileDescriptor fd) throws IOException { SocketDispatcher.invalidateAndClose(fd); } diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java --- a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -48,7 +48,7 @@ return true; } - int read(FileDescriptor fd, long address, int len) + public int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); @@ -64,7 +64,7 @@ return readv0(fd, address, len); } - int write(FileDescriptor fd, long address, int len) throws IOException { + public int write(FileDescriptor fd, long address, int len) throws IOException { return write0(fd, address, len, fdAccess.getAppend(fd)); } @@ -104,7 +104,7 @@ release0(fd, pos, size); } - void close(FileDescriptor fd) throws IOException { + public void close(FileDescriptor fd) throws IOException { fdAccess.close(fd); } diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/InheritedChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/windows/classes/sun/nio/ch/InheritedChannel.java Fri Oct 25 15:56:35 2019 +0100 @@ -0,0 +1,40 @@ +/* + * 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.util.function.BiFunction; +import java.io.FileDescriptor; +import java.nio.channels.spi.SelectorProvider; +import sun.nio.ch.AbstractSocketChannelImpl; + +public class InheritedChannel { + + public static final void register( + BiFunction supplier) + { + // operation not supported on windows + } +} diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/NativeThread.java --- a/src/java.base/windows/classes/sun/nio/ch/NativeThread.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/NativeThread.java Fri Oct 25 15:56:35 2019 +0100 @@ -29,14 +29,14 @@ // Signalling operations on native threads -class NativeThread { +public class NativeThread { - static long current() { + public static long current() { // return 0 to ensure that async close of blocking sockets will close // the underlying socket. return 0; } - static void signal(long nt) { } + public static void signal(long nt) { } } diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java --- a/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -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) { diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java --- a/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java Fri Oct 25 15:56:35 2019 +0100 @@ -36,13 +36,13 @@ * for read and write operations. */ -class SocketDispatcher extends NativeDispatcher { +public class SocketDispatcher extends NativeDispatcher { private static final JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); - SocketDispatcher() { } + public SocketDispatcher() { } - int read(FileDescriptor fd, long address, int len) throws IOException { + public int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); } @@ -50,7 +50,7 @@ return readv0(fd, address, len); } - int write(FileDescriptor fd, long address, int len) throws IOException { + public int write(FileDescriptor fd, long address, int len) throws IOException { return write0(fd, address, len); } @@ -58,11 +58,11 @@ return writev0(fd, address, len); } - void preClose(FileDescriptor fd) throws IOException { + public void preClose(FileDescriptor fd) throws IOException { throw new UnsupportedOperationException(); } - void close(FileDescriptor fd) throws IOException { + public void close(FileDescriptor fd) throws IOException { invalidateAndClose(fd); } diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java --- a/src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/SourceChannelImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -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) { diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java --- a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Fri Oct 25 15:56:35 2019 +0100 @@ -401,7 +401,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; diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/native/libnet/net_util_md.h --- a/src/java.base/windows/native/libnet/net_util_md.h Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/native/libnet/net_util_md.h Fri Oct 25 15:56:35 2019 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include /* used to disable connection reset messages on Windows XP */ #ifndef SIO_UDP_CONNRESET @@ -56,6 +57,7 @@ struct sockaddr sa; struct sockaddr_in sa4; struct sockaddr_in6 sa6; + struct sockaddr_un saun; } SOCKETADDRESS; /* diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/native/libnio/ch/IOUtil.c --- a/src/java.base/windows/native/libnio/ch/IOUtil.c Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/native/libnio/ch/IOUtil.c Fri Oct 25 15:56:35 2019 +0100 @@ -192,13 +192,13 @@ /* Note: This function returns the int fd value from file descriptor. It is mostly used for sockets which should use the int fd value. */ -jint +JNIEXPORT jint JNICALL fdval(JNIEnv *env, jobject fdo) { return (*env)->GetIntField(env, fdo, fd_fdID); } -void +JNIEXPORT void JNICALL setfdval(JNIEnv *env, jobject fdo, jint val) { (*env)->SetIntField(env, fdo, fd_fdID, val); diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/native/libnio/ch/Net.c --- a/src/java.base/windows/native/libnio/ch/Net.c Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/native/libnio/ch/Net.c Fri Oct 25 15:56:35 2019 +0100 @@ -77,7 +77,8 @@ NULL, 0, &bytesReturned, NULL, NULL); } -jint handleSocketError(JNIEnv *env, int errorValue) +JNIEXPORT jint JNICALL +handleSocketError(JNIEnv *env, int errorValue) { NET_ThrowNew(env, errorValue, NULL); return IOS_THROWN; @@ -86,6 +87,182 @@ 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; +extern jfieldID udsa_isAbstractID; + +JNIEXPORT jobject JNICALL +NET_SockaddrToUnixAddress(JNIEnv *env, SOCKETADDRESS *sa) { + jboolean isAbstract; + + if (sa->sa.sa_family == AF_UNIX) { + char *name = sa->saun.sun_path; + +#ifdef NOTDEF + /* check for abstract name */ + if (name[0] == 0) { + isAbstract = 1; + name++; // skip the zero byte + } else +#endif + isAbstract = 0; + 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, SOCKETADDRESS *sa, int *len) +{ + jstring path = (*env)->GetObjectField(env, uaddr, udsa_pathID); + jboolean isCopy; + //jboolean isAbstract = (*env)->GetBooleanField(env, uaddr, udsa_isAbstractID); + int ret; + const char* pname = JNU_GetStringPlatformChars(env, path, &isCopy); + memset(sa, 0, sizeof(SOCKETADDRESS)); + sa->saun.sun_family = AF_UNIX; + 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; + } +#ifdef NOTDEF + if (isAbstract) { + strncpy(&sa->saun.sun_path[1], pname, name_len); + sa->saun.sun_path[0] = 0; + name_len++; + } else +#endif + { + strncpy(sa->saun.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 < 0) { + 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 < 0) { + return handleSocketError(env, errno); + } + return (int)fd; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_Net_unixDomainBind(JNIEnv *env, jclass clazz, jobject fdo, jobject uaddr) +{ + SOCKETADDRESS sa; + int sa_len = 0; + int rv = 0; + + if (NET_UnixSocketAddressToSockaddr(env, uaddr, &sa, &sa_len) != 0) + return; + + int fd = fdval(env, fdo); + + rv = NET_Bind(fdval(env, fdo), &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) +{ + SOCKETADDRESS 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.saun, 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; + SOCKETADDRESS sa; + socklen_t sa_len = sizeof(SOCKETADDRESS); + jobject usa; + + /* accept connection but ignore ECONNABORTED */ + for (;;) { + newfd = (jint)accept(fd, &sa.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); + 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) +{ + SOCKETADDRESS sa; + socklen_t sa_len = sizeof(SOCKETADDRESS); + if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) { + handleSocketError(env, errno); + return NULL; + } + return NET_SockaddrToUnixAddress(env, &sa); +} + JNIEXPORT void JNICALL Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) { diff -r eb491334113f -r 119ac9128c1b src/java.base/windows/native/libnio/ch/nio_util.h --- a/src/java.base/windows/native/libnio/ch/nio_util.h Fri Oct 25 14:50:16 2019 +0100 +++ b/src/java.base/windows/native/libnio/ch/nio_util.h Fri Oct 25 15:56:35 2019 +0100 @@ -35,13 +35,16 @@ */ #define MAX_BUFFER_SIZE ((128*1024)-1) -jint fdval(JNIEnv *env, jobject fdo); -void setfdval(JNIEnv *env, jobject fdo, jint val); +JNIEXPORT jint JNICALL +fdval(JNIEnv *env, jobject fdo); +JNIEXPORT void JNICALL +setfdval(JNIEnv *env, jobject fdo, jint val); jlong handleval(JNIEnv *env, jobject fdo); jint convertReturnVal(JNIEnv *env, jint n, jboolean r); jlong convertLongReturnVal(JNIEnv *env, jlong n, jboolean r); jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd); -jint handleSocketError(JNIEnv *env, int errorValue); +JNIEXPORT jint JNICALL +handleSocketError(JNIEnv *env, int errorValue); #ifdef _WIN64