8245194: Unix domain socket channel implementation

Reviewed-by: erikj, dfuchs, alanb, chegar
This commit is contained in:
Michael McMahon 2020-10-28 17:26:26 +00:00
parent 8bde2f4e3d
commit 6bb7e45e8e
73 changed files with 5434 additions and 1116 deletions

View file

@ -66,6 +66,16 @@ import java.util.StringTokenizer;
* </tr>
*
* <tr>
* <th scope="row">accessUnixDomainSocket</th>
* <td>The ability to accept, bind, connect or get the local address
* of a <i>Unix Domain</i> socket.
* </td>
* <td>Malicious code could connect to local processes using Unix domain sockets
* or impersonate local processes, by binding to the same pathnames (assuming they
* have the required Operating System permissions.</td>
* </tr>
*
* <tr>
* <th scope="row">getCookieHandler</th>
* <td>The ability to get the cookie handler that processes highly
* security sensitive cookie information for an Http session.</td>

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2020, 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
@ -41,5 +41,11 @@ public enum StandardProtocolFamily implements ProtocolFamily {
/**
* Internet Protocol Version 6 (IPv6)
*/
INET6
INET6,
/**
* Unix domain (Local) interprocess communication.
* @since 16
*/
UNIX
}

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.net.SocketAddress;
import java.nio.channels.SocketChannel;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
/**
* A <a href="package-summary.html#unixdomain">Unix domain</a> socket address.
* A Unix domain socket address encapsulates a file-system path that Unix domain sockets
* bind or connect to.
*
* <p> An <a id="unnamed"></a><i>unnamed</i> {@code UnixDomainSocketAddress} has
* an empty path. The local address of a {@link SocketChannel} to a Unix domain socket
* that is <i>automatically</i> or <i>implicitly</i> bound will be unnamed.
*
* <p> {@link Path} objects used to create instances of this class must be obtained
* from the {@linkplain FileSystems#getDefault system-default} file system.
*
* @see java.nio.channels.SocketChannel
* @see java.nio.channels.ServerSocketChannel
* @since 16
*/
public final class UnixDomainSocketAddress extends SocketAddress {
@java.io.Serial
static final long serialVersionUID = 92902496589351288L;
private final transient Path path;
/**
* A serial proxy for all {@link UnixDomainSocketAddress} instances.
* It captures the file path name and reconstructs using the public static
* {@link #of(String) factory}.
*
* @serial include
*/
private static final class Ser implements Serializable {
@java.io.Serial
static final long serialVersionUID = -7955684448513979814L;
/**
* The path name.
* @serial
*/
private final String pathname;
Ser(String pathname) {
this.pathname = pathname;
}
/**
* Creates a {@link UnixDomainSocketAddress} instance, by an invocation
* of the {@link #of(String) factory} method passing the path name.
* @return a UnixDomainSocketAddress
*/
@java.io.Serial
private Object readResolve() {
return UnixDomainSocketAddress.of(pathname);
}
}
/**
* Returns a
* <a href="{@docRoot}/serialized-form.html#java.net.UnixDomainSocketAddress.Ser">
* Ser</a> containing the path name of this instance.
*
* @return a {@link Ser}
* representing the path name of this instance
*/
@java.io.Serial
private Object writeReplace() throws ObjectStreamException {
return new Ser(path.toString());
}
/**
* Throws InvalidObjectException, always.
* @param s the stream
* @throws java.io.InvalidObjectException always
*/
@java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.InvalidObjectException
{
throw new java.io.InvalidObjectException("Proxy required");
}
/**
* Throws InvalidObjectException, always.
* @throws java.io.InvalidObjectException always
*/
@java.io.Serial
private void readObjectNoData()
throws java.io.InvalidObjectException
{
throw new java.io.InvalidObjectException("Proxy required");
}
private UnixDomainSocketAddress(Path path) {
this.path = path;
}
/**
* Creates a UnixDomainSocketAddress from the given path string.
*
* @param pathname
* The path string, which can be empty
*
* @return A UnixDomainSocketAddress
*
* @throws InvalidPathException
* If the path cannot be converted to a Path
*
* @throws NullPointerException if pathname is {@code null}
*/
public static UnixDomainSocketAddress of(String pathname) {
return of(Path.of(pathname));
}
/**
* Creates a UnixDomainSocketAddress for the given path.
*
* @param path
* The path to the socket, which can be empty
*
* @return A UnixDomainSocketAddress
*
* @throws IllegalArgumentException
* If the path is not associated with the default file system
*
* @throws NullPointerException if path is {@code null}
*/
public static UnixDomainSocketAddress of(Path path) {
FileSystem fs = path.getFileSystem();
if (fs != FileSystems.getDefault()) {
throw new IllegalArgumentException();
}
if (fs.getClass().getModule() != Object.class.getModule()) {
throw new IllegalArgumentException();
}
return new UnixDomainSocketAddress(path);
}
/**
* Returns this address's path.
*
* @return this address's path
*/
public Path getPath() {
return path;
}
/**
* Returns the hash code of this {@code UnixDomainSocketAddress}
*/
@Override
public int hashCode() {
return path.hashCode();
}
/**
* Compares this address with another object.
*
* @return true if the path fields are equal
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof UnixDomainSocketAddress))
return false;
UnixDomainSocketAddress that = (UnixDomainSocketAddress)o;
return this.path.equals(that.path);
}
/**
* Returns a string representation of this {@code UnixDomainSocketAddress}.
*
* @return this address's path which may be empty for an unnamed address
*/
@Override
public String toString() {
return path.toString();
}
}

View file

@ -150,6 +150,9 @@ public abstract class DatagramChannel
*
* @throws IOException
* If an I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*/
public static DatagramChannel open() throws IOException {
return SelectorProvider.provider().openDatagramChannel();
@ -169,6 +172,9 @@ public abstract class DatagramChannel
* java.nio.channels.spi.SelectorProvider} object. The channel will not be
* connected.
*
* @apiNote <a href="package-summary.html#unixdomain">Unix domain</a> sockets
* are not supported by DatagramChannel.
*
* @param family
* The protocol family
*
@ -182,6 +188,9 @@ public abstract class DatagramChannel
* @throws IOException
* If an I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*
* @since 1.7
*/
public static DatagramChannel open(ProtocolFamily family) throws IOException {
@ -629,5 +638,4 @@ public abstract class DatagramChannel
*/
@Override
public abstract SocketAddress getLocalAddress() throws IOException;
}

View file

@ -26,10 +26,12 @@
package java.nio.channels;
import java.io.IOException;
import java.net.NetPermission;
import java.net.ProtocolFamily;
import java.net.ServerSocket;
import java.net.SocketOption;
import java.net.SocketAddress;
import java.net.UnixDomainSocketAddress;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.SelectorProvider;
import static java.util.Objects.requireNonNull;
@ -37,16 +39,20 @@ import static java.util.Objects.requireNonNull;
/**
* A selectable channel for stream-oriented listening sockets.
*
* <p> A server-socket channel is created by invoking the {@link #open() open}
* method of this class. It is not possible to create a channel for an arbitrary,
* 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}
* <p> A server-socket channel is created by invoking one of the {@code open}
* methods of this class. The no-arg {@link #open() open} method opens a server-socket
* channel for an <i>Internet protocol</i> socket. The {@link #open(ProtocolFamily)}
* method is used to open a server-socket channel for a socket of a specified
* protocol family. It is not possible to create a channel for an arbitrary,
* pre-existing socket. 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.
* {@link #bind(java.net.SocketAddress, int) bind} methods defined by this class.
*
* <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
* setOption} method. Server-socket channels support the following options:
* setOption} method. Server-socket channels for <i>Internet protocol</i> sockets
* support the following options:
* <blockquote>
* <table class="striped">
* <caption style="display:none">Socket options</caption>
@ -68,7 +74,27 @@ import static java.util.Objects.requireNonNull;
* </tbody>
* </table>
* </blockquote>
* Additional (implementation specific) options may also be supported.
*
* <p> Server-socket channels for <i>Unix domain</i> sockets support:
* <blockquote>
* <table class="striped">
* <caption style="display:none">Socket options</caption>
* <thead>
* <tr>
* <th scope="col">Option Name</th>
* <th scope="col">Description</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
* <td> The size of the socket receive buffer </td>
* </tr>
* </tbody>
* </table>
* </blockquote>
*
* <p> Additional (implementation specific) options may also be supported.
*
* <p> Server-socket channels are safe for use by multiple concurrent threads.
* </p>
@ -94,7 +120,7 @@ public abstract class ServerSocketChannel
}
/**
* Opens a server-socket channel.
* Opens a server-socket channel for an <i>Internet protocol</i> socket.
*
* <p> The new channel is created by invoking the {@link
* java.nio.channels.spi.SelectorProvider#openServerSocketChannel
@ -110,13 +136,16 @@ public abstract class ServerSocketChannel
*
* @throws IOException
* If an I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*/
public static ServerSocketChannel open() throws IOException {
return SelectorProvider.provider().openServerSocketChannel();
}
/**
* Opens a server-socket channel.The {@code family} parameter specifies the
* Opens a server-socket channel. The {@code family} parameter specifies the
* {@link ProtocolFamily protocol family} of the channel's socket.
*
* <p> The new channel is created by invoking the {@link
@ -137,6 +166,9 @@ public abstract class ServerSocketChannel
* @throws IOException
* If an I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*
* @since 15
*/
public static ServerSocketChannel open(ProtocolFamily family) throws IOException {
@ -180,8 +212,7 @@ public abstract class ServerSocketChannel
* @throws ClosedChannelException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException
* If a security manager has been installed and its {@link
* SecurityManager#checkListen checkListen} method denies the
* If a security manager has been installed and it denies the
* operation
*
* @since 1.7
@ -197,8 +228,8 @@ public abstract class ServerSocketChannel
* listen for connections.
*
* <p> This method is used to establish an association between the socket and
* a local address. Once an association is established then the socket remains
* bound until the channel is closed.
* a local address. For <i>Internet protocol</i> sockets, once an association
* is established then the socket remains bound until the channel is closed.
*
* <p> The {@code backlog} parameter is the maximum number of pending
* connections on the socket. Its exact semantics are implementation specific.
@ -207,9 +238,25 @@ public abstract class ServerSocketChannel
* the value {@code 0}, or a negative value, then an implementation specific
* default is used.
*
* @apiNote
* Binding a server socket channel for a <i>Unix Domain</i> socket, creates a
* file corresponding to the file path in the {@link UnixDomainSocketAddress}.
* This file persists after the channel is closed, and must be removed before
* another socket can bind to the same name. Binding to a {@code null} address
* causes the socket to be <i>automatically</i> bound to some unique file
* in a system temporary location. The associated socket file also persists
* after the channel is closed. Its name can be obtained from the channel's
* local socket address.
*
* @implNote
* Each platform enforces an implementation specific, maximum length for the
* name of a <i>Unix Domain</i> socket. This limitation is enforced when a
* channel is bound. The maximum length is typically close to and generally
* not less than 100 bytes.
*
* @param local
* The address to bind the socket, or {@code null} to bind to an
* automatically assigned socket address
* The address to bind the socket, or {@code null} to bind to
* an automatically assigned socket address
* @param backlog
* The maximum number of pending connections
*
@ -225,8 +272,10 @@ public abstract class ServerSocketChannel
* 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
* SecurityManager#checkListen checkListen} method denies
* the operation for an <i>Internet protocol</i> socket address,
* or for a <i>Unix domain</i> socket address if it denies
* {@link NetPermission}{@code("accessUnixDomainSocket")}.
*
* @since 1.7
*/
@ -251,6 +300,9 @@ public abstract class ServerSocketChannel
* declared in the {@link java.net.ServerSocket} class. </p>
*
* @return A server socket associated with this channel
*
* @throws UnsupportedOperationException
* If the channel's socket is not an <i>Internet protocol</i> socket
*/
public abstract ServerSocket socket();
@ -265,13 +317,15 @@ public abstract class ServerSocketChannel
* <p> The socket channel returned by this method, if any, will be in
* blocking mode regardless of the blocking mode of this channel.
*
* <p> This method performs exactly the same security checks as the {@link
* java.net.ServerSocket#accept accept} method of the {@link
* java.net.ServerSocket} class. That is, if a security manager has been
* installed then for each new connection this method verifies that the
* address and port number of the connection's remote endpoint are
* permitted by the security manager's {@link
* java.lang.SecurityManager#checkAccept checkAccept} method. </p>
* <p> If bound to an <i>Internet protocol</i> socket address, this method
* performs exactly the same security checks as the {@link
* java.net.ServerSocket#accept accept} method of the {@link java.net.ServerSocket}
* class. That is, if a security manager has been installed then for each
* new connection this method verifies that the address and port number
* of the connection's remote endpoint are permitted by the security
* manager's {@link java.lang.SecurityManager#checkAccept checkAccept}
* method. If bound to a <i>Unix Domain</i> socket address, this method checks
* {@link NetPermission}{@code ("accessUnixDomainSocket")}.
*
* @return The socket channel for the new connection,
* or {@code null} if this channel is in non-blocking mode
@ -305,7 +359,7 @@ public abstract class ServerSocketChannel
/**
* {@inheritDoc}
* <p>
*
* If there is a security manager set, its {@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,
@ -313,9 +367,16 @@ public abstract class ServerSocketChannel
* {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
* local port of the channel's socket is returned.
*
* <p> Where the channel is bound to a <i>Unix Domain</i> socket address, the socket
* address is a {@link UnixDomainSocketAddress}. If there is a security manager
* set, its {@link SecurityManager#checkPermission(java.security.Permission)
* checkPermission} method is called with {@link NetPermission}{@code
* ("accessUnixDomainSocket")}. If the operation is not allowed an unnamed
* {@link UnixDomainSocketAddress} is returned.
*
* @return The {@code SocketAddress} that the socket is bound to, or the
* {@code SocketAddress} representing the loopback address if
* denied by the security manager, or {@code null} if the
* {@code SocketAddress} representing the loopback address or empty
* path if denied by the security manager, or {@code null} if the
* channel's socket is not bound
*
* @throws ClosedChannelException {@inheritDoc}
@ -323,5 +384,4 @@ public abstract class ServerSocketChannel
*/
@Override
public abstract SocketAddress getLocalAddress() throws IOException;
}

View file

@ -26,10 +26,14 @@
package java.nio.channels;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.NetPermission;
import java.net.ProtocolFamily;
import java.net.StandardProtocolFamily;
import java.net.Socket;
import java.net.SocketOption;
import java.net.SocketAddress;
import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.SelectorProvider;
@ -38,15 +42,18 @@ import static java.util.Objects.requireNonNull;
/**
* A selectable channel for stream-oriented connecting sockets.
*
* <p> A socket channel is created by invoking one of the {@link #open open}
* methods of this class. It is not possible to create a channel for an arbitrary,
* 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
* socket channel can be connected by invoking its {@link #connect connect}
* method; once connected, a socket channel remains connected until it is
* closed. Whether or not a socket channel is connected may be determined by
* invoking its {@link #isConnected isConnected} method.
* <p> A socket channel is created by invoking one of the {@code open} methods of
* this class. The no-arg {@link #open() open} method opens a socket channel
* for an <i>Internet protocol</i> socket. The {@link #open(ProtocolFamily)}
* method is used to open a socket channel for a socket of a specified protocol
* family. 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 socket channel can be
* connected by invoking its {@link #connect connect} method; once connected,
* a socket channel remains connected until it is closed. Whether or not a
* socket channel is connected may be determined by invoking its {@link #isConnected()
* isConnected} method.
*
* <p> Socket channels support <i>non-blocking connection:</i>&nbsp;A socket
* channel may be created and the process of establishing the link to the
@ -55,7 +62,7 @@ import static java.util.Objects.requireNonNull;
* Whether or not a connection operation is in progress may be determined by
* invoking the {@link #isConnectionPending isConnectionPending} method.
*
* <p> Socket channels support <i>asynchronous shutdown,</i> which is similar
* <p> Socket channels support <i>asynchronous shutdown</i>, which is similar
* to the asynchronous close operation specified in the {@link Channel} class.
* If the input side of a socket is shut down by one thread while another
* thread is blocked in a read operation on the socket's channel, then the read
@ -66,7 +73,8 @@ import static java.util.Objects.requireNonNull;
* AsynchronousCloseException}.
*
* <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
* setOption} method. Socket channels support the following options:
* setOption} method. Socket channels for <i>Internet protocol</i> sockets support
* following options:
* <blockquote>
* <table class="striped">
* <caption style="display:none">Socket options</caption>
@ -105,7 +113,36 @@ import static java.util.Objects.requireNonNull;
* </tbody>
* </table>
* </blockquote>
* Additional (implementation specific) options may also be supported.
*
* <p> Socket channels for <i>Unix domain</i> sockets support:
* <blockquote>
* <table class="striped">
* <caption style="display:none">Socket options</caption>
* <thead>
* <tr>
* <th scope="col">Option Name</th>
* <th scope="col">Description</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th scope="row"> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </th>
* <td> The size of the socket send buffer </td>
* </tr>
* <tr>
* <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
* <td> The size of the socket receive buffer </td>
* </tr>
* <tr>
* <th scope="row"> {@link java.net.StandardSocketOptions#SO_LINGER SO_LINGER} </th>
* <td> Linger on close if data is present (when configured in blocking mode
* only) </td>
* </tr>
* </tbody>
* </table>
* </blockquote>
*
* <p> Additional (implementation specific) options may also be supported.
*
* <p> Socket channels are safe for use by multiple concurrent threads. They
* support concurrent reading and writing, though at most one thread may be
@ -136,7 +173,7 @@ public abstract class SocketChannel
}
/**
* Opens a socket channel.
* Opens a socket channel for an <i>Internet protocol</i> socket.
*
* <p> The new channel is created by invoking the {@link
* java.nio.channels.spi.SelectorProvider#openSocketChannel
@ -147,6 +184,9 @@ public abstract class SocketChannel
*
* @throws IOException
* If an I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*/
public static SocketChannel open() throws IOException {
return SelectorProvider.provider().openSocketChannel();
@ -174,6 +214,9 @@ public abstract class SocketChannel
* @throws IOException
* If an I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*
* @since 15
*/
public static SocketChannel open(ProtocolFamily family) throws IOException {
@ -183,10 +226,16 @@ public abstract class SocketChannel
/**
* Opens a socket channel and connects it to a remote address.
*
* <p> This convenience method works as if by invoking the {@link #open()}
* method, invoking the {@link #connect(SocketAddress) connect} method upon
* the resulting socket channel, passing it {@code remote}, and then
* returning that channel. </p>
* <p> If the remote address is an {@link InetSocketAddress} then this
* method works as if by invoking the {@link #open()} method, invoking the
* {@link #connect(SocketAddress) connect} method upon the resulting socket
* channel, passing it {@code remote}, and then returning that channel.
*
* <p> If the remote address is a {@link UnixDomainSocketAddress} then this
* works 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}, then returning that channel. </p>
*
* @param remote
* The remote address to which the new channel is to be connected
@ -204,7 +253,8 @@ public abstract class SocketChannel
* interrupt status
*
* @throws UnresolvedAddressException
* If the given remote address is not fully resolved
* If the given remote address is an InetSocketAddress that is not fully
* resolved
*
* @throws UnsupportedAddressTypeException
* If the type of the given remote address is not supported
@ -215,11 +265,22 @@ public abstract class SocketChannel
*
* @throws IOException
* If some other I/O error occurs
*
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
* java.net.preferIPv4Stack</a> system property
*/
public static SocketChannel open(SocketAddress remote)
throws IOException
{
SocketChannel sc = open();
SocketChannel sc;
requireNonNull(remote);
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) {
@ -255,6 +316,38 @@ public abstract class SocketChannel
// -- Socket-specific operations --
/**
* Binds the channel's socket to a local address.
*
* <p> This method is used to establish an association between the socket
* and a local address. For <i>Internet Protocol</i> sockets, once an
* association is established then the socket remains bound until the
* channel is closed. If the {@code local} parameter has the value {@code
* null} then the socket will be bound to an address that is assigned
* automatically.
*
* @apiNote
* Binding a socket channel to a <i>Unix Domain</i> socket creates a file
* corresponding to the file path in the {@link UnixDomainSocketAddress}. This
* file persists after the channel is closed, and must be removed before
* another socket can bind to the same name. If a socket channel to a Unix
* Domain socket is <i>implicitly</i> bound by connecting it without calling
* bind first, then its socket is
* <a href="../../java/net/UnixDomainSocketAddress.html#unnamed">unnamed</a>
* with no corresponding socket file in the file-system. If a socket channel
* to a Unix Domain socket is <i>automatically</i> bound by calling {@code
* bind(null)} this results in an unnamed socket also.
*
* @implNote
* Each platform enforces an implementation specific maximum length for the
* name of a <i>Unix Domain</i> socket. This limitation is enforced when a
* channel is bound. The maximum length is typically close to and generally
* not less than 100 bytes.
*
* @param local The address to bind the socket, or {@code null} to bind
* the socket to an automatically assigned socket address
*
* @return This channel
*
* @throws ConnectionPendingException
* If a non-blocking connect operation is already in progress on
* this channel
@ -263,9 +356,11 @@ public abstract class SocketChannel
* @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 an <i>Internet protocol</i> socket address,
* or for a <i>Unix domain</i> socket address if it denies
* {@link NetPermission}{@code("accessUnixDomainSocket")}.
*
* @since 1.7
*/
@ -329,10 +424,10 @@ public abstract class SocketChannel
/**
* Retrieves a socket associated with this channel.
*
* <p> The returned object will not declare any public methods that are not
* declared in the {@link java.net.Socket} class. </p>
*
* @return A socket associated with this channel
*
* @throws UnsupportedOperationException
* If the channel's socket is not an <i>Internet protocol</i> socket
*/
public abstract Socket socket();
@ -368,12 +463,19 @@ public abstract class SocketChannel
* method will block until the connection is established or an I/O error
* occurs.
*
* <p> This method performs exactly the same security checks as the {@link
* java.net.Socket} class. That is, if a security manager has been
* <p> For channels to <i>Internet protocol</i> sockets, this method performs
* exactly the same security checks as the {@link java.net.Socket} class.
* That is, if a security manager has been
* installed then this method verifies that its {@link
* java.lang.SecurityManager#checkConnect checkConnect} method permits
* connecting to the address and port number of the given remote endpoint.
*
* <p> For channels to <i>Unix Domain</i> sockets, this method checks
* {@link java.net.NetPermission NetPermission}{@code
* ("accessUnixDomainSocket")} with the security manager's {@link
* SecurityManager#checkPermission(java.security.Permission)
* checkPermission} method.
*
* <p> This method may be invoked at any time. If a read or write
* operation upon this channel is invoked while an invocation of this
* method is in progress then that operation will first block until this
@ -409,7 +511,7 @@ public abstract class SocketChannel
* interrupt status
*
* @throws UnresolvedAddressException
* If the given remote address is not fully resolved
* If the given remote address is an InetSocketAddress that is not fully resolved
*
* @throws UnsupportedAddressTypeException
* If the type of the given remote address is not supported
@ -477,9 +579,12 @@ public abstract class SocketChannel
/**
* Returns the remote address to which this channel's socket is connected.
*
* <p> Where the channel is bound and connected to an Internet Protocol
* socket address then the return value from this method is of type {@link
* java.net.InetSocketAddress}.
* <p> Where the channel's socket is bound and connected to an <i>Internet
* Protocol</i> socket address then the return value is of type
* {@link java.net.InetSocketAddress}.
*
* <p> Where the channel's socket is bound and connected to a <i>Unix Domain</i>
* socket address, the returned address is a {@link UnixDomainSocketAddress}.
*
* @return The remote address; {@code null} if the channel's socket is not
* connected
@ -539,7 +644,7 @@ public abstract class SocketChannel
/**
* {@inheritDoc}
* <p>
*
* If there is a security manager set, its {@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,
@ -547,9 +652,16 @@ public abstract class SocketChannel
* {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
* local port of the channel's socket is returned.
*
* <p> Where the channel is bound to a Unix Domain socket address, the socket
* address is a {@link UnixDomainSocketAddress}. If there is a security manager
* set, its {@link SecurityManager#checkPermission(java.security.Permission)
* checkPermission} method is called with {@link NetPermission}{@code
* ("accessUnixDomainSocket")}. If the operation is not allowed an unnamed
* {@link UnixDomainSocketAddress} is returned.
*
* @return The {@code SocketAddress} that the socket is bound to, or the
* {@code SocketAddress} representing the loopback address if
* denied by the security manager, or {@code null} if the
* {@code SocketAddress} representing the loopback address or empty
* path if denied by the security manager, or {@code null} if the
* channel's socket is not bound
*
* @throws ClosedChannelException {@inheritDoc}
@ -557,5 +669,4 @@ public abstract class SocketChannel
*/
@Override
public abstract SocketAddress getLocalAddress() throws IOException;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2020, 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
@ -241,6 +241,28 @@
* If a channel needs an associated socket then a socket will be created as a side
* effect of this operation.
*
* <p> {@link java.nio.channels.DatagramChannel},
* {@link java.nio.channels.SocketChannel} and
* {@link java.nio.channels.ServerSocketChannel}s can be created
* with different {@link java.net.ProtocolFamily protocol families}. The standard
* family types are specified in {@link java.net.StandardProtocolFamily}.
*
* <p> Channels for <i>Internet Protocol</i> sockets are created using the
* {@link java.net.StandardProtocolFamily#INET INET} or {@link
* java.net.StandardProtocolFamily#INET6 INET6} protocol families. <i>Internet
* Protocol</i> sockets support network communication using TCP and UDP and are
* addressed using {@link java.net.InetSocketAddress}es which encapsulate an IP
* address and port number. <i>Internet Protocol</i> sockets are also the default
* type created, when a protocol family is not specified in the channel factory
* creation method.
*
* <p> Channels for <a id="unixdomain"></a><i>Unix Domain</i> sockets are created
* using the {@link java.net.StandardProtocolFamily#UNIX UNIX} protocol family.
* <i>Unix Domain</i> sockets support local inter-process
* communication on the same host, and are addressed using {@link
* java.net.UnixDomainSocketAddress}es which encapsulate a filesystem pathname
* on the local system.
*
* <p> The implementation of selectors, selectable channels, and selection keys
* can be replaced by "plugging in" an alternative definition or instance of the
* {@link java.nio.channels.spi.SelectorProvider} class defined in the {@link

View file

@ -268,34 +268,38 @@ public abstract class SelectorProvider {
* associated network port. In this example, the process that is started,
* inherits a channel representing a network socket.
*
* <p> In cases where the inherited channel represents a network socket
* then the {@link java.nio.channels.Channel Channel} type returned
* <p> In cases where the inherited channel is for an <i>Internet protocol</i>
* socket then the {@link Channel Channel} type returned
* by this method is determined as follows:
*
* <ul>
*
* <li><p> If the inherited channel represents a stream-oriented connected
* socket then a {@link java.nio.channels.SocketChannel SocketChannel} is
* returned. The socket channel is, at least initially, in blocking
* mode, bound to a socket address, and connected to a peer.
* <li><p> If the inherited channel is for a stream-oriented connected
* socket then a {@link SocketChannel SocketChannel} is returned. The
* socket channel is, at least initially, in blocking mode, bound
* to a socket address, and connected to a peer.
* </p></li>
*
* <li><p> If the inherited channel represents a stream-oriented listening
* socket then a {@link java.nio.channels.ServerSocketChannel
* ServerSocketChannel} is returned. The server-socket channel is, at
* least initially, in blocking mode, and bound to a socket address.
* <li><p> If the inherited channel is for a stream-oriented listening
* socket then a {@link ServerSocketChannel ServerSocketChannel} is returned.
* The server-socket channel is, at least initially, in blocking mode,
* and bound to a socket address.
* </p></li>
*
* <li><p> If the inherited channel is a datagram-oriented socket
* then a {@link java.nio.channels.DatagramChannel DatagramChannel} is
* returned. The datagram channel is, at least initially, in blocking
* mode, and bound to a socket address.
* <li><p> If the inherited channel is a datagram-oriented socket then a
* {@link DatagramChannel DatagramChannel} is returned. The datagram channel
* is, at least initially, in blocking mode, and bound to a socket address.
* </p></li>
*
* </ul>
*
* <p> In addition to the network-oriented channels described, this method
* may return other kinds of channels in the future.
* <p> In cases where the inherited channel is for a <i>Unix domain</i>
* socket then the {@link Channel} type returned is the same as for
* <i>Internet protocol</i> sockets as described above, except that
* datagram-oriented sockets are not supported.
*
* <p> In addition to the two types of socket just described, this method
* may return other types in the future.
*
* <p> The first invocation of this method creates the channel that is
* returned. Subsequent invocations of this method return the same

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
@ -33,8 +33,7 @@ import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import static java.nio.file.attribute.PosixFilePermission.*;
import sun.security.action.GetPropertyAction;
import jdk.internal.util.StaticProperty;
/**
* Helper class to support creation of temporary files and directories with
@ -45,8 +44,7 @@ class TempFileHelper {
private TempFileHelper() { }
// temporary directory location
private static final Path tmpdir =
Path.of(GetPropertyAction.privilegedGetProperty("java.io.tmpdir"));
private static final Path tmpdir = Path.of(StaticProperty.javaIoTmpDir());
private static final boolean isPosix =
FileSystems.getDefault().supportedFileAttributeViews().contains("posix");

View file

@ -47,6 +47,7 @@ public final class StaticProperty {
private static final String JAVA_LIBRARY_PATH;
private static final String SUN_BOOT_LIBRARY_PATH;
private static final String JDK_SERIAL_FILTER;
private static final String JAVA_IO_TMPDIR;
private StaticProperty() {}
@ -56,6 +57,7 @@ public final class StaticProperty {
USER_HOME = getProperty(props, "user.home");
USER_DIR = getProperty(props, "user.dir");
USER_NAME = getProperty(props, "user.name");
JAVA_IO_TMPDIR = getProperty(props, "java.io.tmpdir");
JAVA_LIBRARY_PATH = getProperty(props, "java.library.path", "");
SUN_BOOT_LIBRARY_PATH = getProperty(props, "sun.boot.library.path", "");
JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null);
@ -140,6 +142,19 @@ public final class StaticProperty {
return JAVA_LIBRARY_PATH;
}
/**
* Return the {@code java.io.tmpdir} system property.
*
* <strong>{@link SecurityManager#checkPropertyAccess} is NOT checked
* in this method. The caller of this method should take care to ensure
* that the returned property is not made accessible to untrusted code.</strong>
*
* @return the {@code java.io.tmpdir} system property
*/
public static String javaIoTmpDir() {
return JAVA_IO_TMPDIR;
}
/**
* Return the {@code sun.boot.library.path} system property.
*

View file

@ -270,6 +270,8 @@ module java.base {
jdk.incubator.foreign;
exports sun.nio.cs to
jdk.charsets;
exports sun.nio.fs to
jdk.net;
exports sun.reflect.annotation to
jdk.compiler;
exports sun.reflect.generics.reflectiveObjects to

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -48,6 +48,7 @@ public abstract class ExtendedSocketOptions {
private final Set<SocketOption<?>> datagramOptions;
private final Set<SocketOption<?>> clientStreamOptions;
private final Set<SocketOption<?>> serverStreamOptions;
private final Set<SocketOption<?>> unixDomainClientOptions;
/** Tells whether or not the option is supported. */
public final boolean isOptionSupported(SocketOption<?> option) {
@ -73,6 +74,19 @@ public abstract class ExtendedSocketOptions {
return getInstance().options0(SOCK_STREAM, false);
}
/**
* Return the, possibly empty, set of extended socket options available for
* Unix domain client sockets. Note, there are no extended
* Unix domain server options.
*/
private final Set<SocketOption<?>> unixDomainClientOptions() {
return unixDomainClientOptions;
}
public static Set<SocketOption<?>> unixDomainSocketOptions() {
return getInstance().unixDomainClientOptions();
}
/**
* Returns the (possibly empty) set of extended socket options for
* datagram-oriented sockets.
@ -82,14 +96,22 @@ public abstract class ExtendedSocketOptions {
}
private static boolean isDatagramOption(SocketOption<?> option) {
return !option.name().startsWith("TCP_");
if (option.name().startsWith("TCP_") || isUnixDomainOption(option)) {
return false;
} else {
return true;
}
}
private static boolean isUnixDomainOption(SocketOption<?> option) {
return option.name().equals("SO_PEERCRED");
}
private static boolean isStreamOption(SocketOption<?> option, boolean server) {
if (server && "SO_FLOW_SLA".equals(option.name())) {
if (option.name().startsWith("UDP_") || isUnixDomainOption(option)) {
return false;
} else {
return !option.name().startsWith("UDP_");
return true;
}
}
@ -122,6 +144,7 @@ public abstract class ExtendedSocketOptions {
var datagramOptions = new HashSet<SocketOption<?>>();
var serverStreamOptions = new HashSet<SocketOption<?>>();
var clientStreamOptions = new HashSet<SocketOption<?>>();
var unixDomainClientOptions = new HashSet<SocketOption<?>>();
for (var option : options) {
if (isDatagramOption(option)) {
datagramOptions.add(option);
@ -132,10 +155,14 @@ public abstract class ExtendedSocketOptions {
if (isStreamOption(option, false)) {
clientStreamOptions.add(option);
}
if (isUnixDomainOption(option)) {
unixDomainClientOptions.add(option);
}
}
this.datagramOptions = Set.copyOf(datagramOptions);
this.serverStreamOptions = Set.copyOf(serverStreamOptions);
this.clientStreamOptions = Set.copyOf(clientStreamOptions);
this.unixDomainClientOptions = Set.copyOf(unixDomainClientOptions);
}
private static volatile ExtendedSocketOptions instance;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -28,6 +28,8 @@ package sun.net.util;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.InetSocketAddress;
import java.net.UnixDomainSocketAddress;
import java.net.SocketAddress;
import java.security.AccessController;
import java.security.PrivilegedAction;
@ -51,11 +53,22 @@ public final class SocketExceptions {
*
* Only specific IOException subtypes are supported.
*/
public static IOException of(IOException e, InetSocketAddress address) {
if (!enhancedExceptionText || address == null)
public static IOException of(IOException e, SocketAddress addr) {
if (!enhancedExceptionText || addr == null) {
return e;
int port = address.getPort();
String host = address.getHostString();
}
if (addr instanceof UnixDomainSocketAddress) {
return ofUnixDomain(e, (UnixDomainSocketAddress)addr);
} else if (addr instanceof InetSocketAddress) {
return ofInet(e, (InetSocketAddress)addr);
} else {
return e;
}
}
private static IOException ofInet(IOException e, InetSocketAddress addr) {
int port = addr.getPort();
String host = addr.getHostString();
StringBuilder sb = new StringBuilder();
sb.append(e.getMessage());
sb.append(": ");
@ -66,6 +79,16 @@ public final class SocketExceptions {
return create(e, enhancedMsg);
}
private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) {
String path = addr.getPath().toString();
StringBuilder sb = new StringBuilder();
sb.append(e.getMessage());
sb.append(": ");
sb.append(path);
String enhancedMsg = sb.toString();
return create(e, enhancedMsg);
}
// return a new instance of the same type with the given detail
// msg, or if the type doesn't support detail msgs, return given
// instance.

View file

@ -226,29 +226,31 @@ public class Net {
/**
* Returns the local address after performing a SecurityManager#checkConnect.
*/
static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
static InetSocketAddress getRevealedLocalAddress(SocketAddress sa) {
InetSocketAddress isa = (InetSocketAddress) sa;
SecurityManager sm = System.getSecurityManager();
if (addr == null || sm == null)
return addr;
try{
sm.checkConnect(addr.getAddress().getHostAddress(), -1);
// Security check passed
} catch (SecurityException e) {
// Return loopback address only if security check fails
addr = getLoopbackAddress(addr.getPort());
if (isa != null && sm != null) {
try {
sm.checkConnect(isa.getAddress().getHostAddress(), -1);
} catch (SecurityException e) {
// Return loopback address only if security check fails
isa = getLoopbackAddress(isa.getPort());
}
}
return addr;
return isa;
}
static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
return System.getSecurityManager() == null ? addr.toString() :
getLoopbackAddress(addr.getPort()).toString();
static String getRevealedLocalAddressAsString(SocketAddress sa) {
InetSocketAddress isa = (InetSocketAddress) sa;
if (System.getSecurityManager() == null) {
return isa.toString();
} else {
return getLoopbackAddress(isa.getPort()).toString();
}
}
private static InetSocketAddress getLoopbackAddress(int port) {
return new InetSocketAddress(InetAddress.getLoopbackAddress(),
port);
return new InetSocketAddress(InetAddress.getLoopbackAddress(), port);
}
private static final InetAddress anyLocalInet4Address;
@ -574,6 +576,13 @@ public class Net {
return connect0(preferIPv6, fd, remote, remotePort);
}
static int connect(ProtocolFamily family, FileDescriptor fd, SocketAddress remote)
throws IOException
{
InetSocketAddress isa = (InetSocketAddress) remote;
return connect(family, fd, isa.getAddress(), isa.getPort());
}
private static native int connect0(boolean preferIPv6,
FileDescriptor fd,
InetAddress remote,

View file

@ -1,63 +0,0 @@
/*
* Copyright (c) 2010, 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.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Provides access to implementation private constructors and methods.
*/
public final class Secrets {
private Secrets() { }
private static SelectorProvider provider() {
SelectorProvider p = SelectorProvider.provider();
if (!(p instanceof SelectorProviderImpl))
throw new UnsupportedOperationException();
return p;
}
public static SocketChannel newSocketChannel(FileDescriptor fd) {
try {
return new SocketChannelImpl(provider(), fd, false);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
try {
return new ServerSocketChannelImpl(provider(), fd, false);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
}

View file

@ -33,6 +33,10 @@ import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Objects;
import static java.net.StandardProtocolFamily.INET;
import static java.net.StandardProtocolFamily.INET6;
import static java.net.StandardProtocolFamily.UNIX;
public abstract class SelectorProviderImpl
extends SelectorProvider
@ -75,11 +79,29 @@ public abstract class SelectorProviderImpl
@Override
public SocketChannel openSocketChannel(ProtocolFamily family) throws IOException {
return new SocketChannelImpl(this, family);
Objects.requireNonNull(family, "'family' is null");
if (family == INET6 && !Net.isIPv6Available()) {
throw new UnsupportedOperationException("IPv6 not available");
} else if (family == INET || family == INET6) {
return new SocketChannelImpl(this, family);
} else if (family == UNIX && UnixDomainSockets.isSupported()) {
return new SocketChannelImpl(this, family);
} else {
throw new UnsupportedOperationException("Protocol family not supported");
}
}
@Override
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) {
return new ServerSocketChannelImpl(this, family);
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) throws IOException {
Objects.requireNonNull(family, "'family' is null");
if (family == INET6 && !Net.isIPv6Available()) {
throw new UnsupportedOperationException("IPv6 not available");
} else if (family == INET || family == INET6) {
return new ServerSocketChannelImpl(this, family);
} else if (family == UNIX && UnixDomainSockets.isSupported()) {
return new ServerSocketChannelImpl(this, family);
} else {
throw new UnsupportedOperationException("Protocol family not supported");
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, 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
@ -93,7 +93,7 @@ class ServerSocketAdaptor // package-private
@Override
public InetAddress getInetAddress() {
InetSocketAddress local = ssc.localAddress();
SocketAddress local = ssc.localAddress();
if (local == null) {
return null;
} else {
@ -103,7 +103,7 @@ class ServerSocketAdaptor // package-private
@Override
public int getLocalPort() {
InetSocketAddress local = ssc.localAddress();
InetSocketAddress local = (InetSocketAddress) ssc.localAddress();
if (local == null) {
return -1;
} else {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, 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
@ -27,14 +27,15 @@ package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.ProtocolFamily;
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.net.UnixDomainSocketAddress;
import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedChannelException;
@ -44,11 +45,15 @@ import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import static java.net.StandardProtocolFamily.INET;
import static java.net.StandardProtocolFamily.INET6;
import static java.net.StandardProtocolFamily.UNIX;
import sun.net.NetHooks;
import sun.net.ext.ExtendedSocketOptions;
@ -90,7 +95,7 @@ class ServerSocketChannelImpl
private long thread;
// Binding
private InetSocketAddress localAddress; // null => unbound
private SocketAddress localAddress; // null => unbound
// set true when exclusive binding is on and SO_REUSEADDR is emulated
private boolean isReuseAddress;
@ -100,47 +105,72 @@ class ServerSocketChannelImpl
// -- End of fields protected by stateLock
ServerSocketChannelImpl(SelectorProvider sp) {
this(sp, Net.isIPv6Available()
? StandardProtocolFamily.INET6
: StandardProtocolFamily.INET);
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
this(sp, Net.isIPv6Available() ? INET6 : INET);
}
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) {
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
throws IOException
{
super(sp);
Objects.requireNonNull(family, "'family' is null");
if ((family != StandardProtocolFamily.INET) &&
(family != StandardProtocolFamily.INET6)) {
if ((family != INET) && (family != INET6) && (family != UNIX)) {
throw new UnsupportedOperationException("Protocol family not supported");
}
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
if (family == INET6 && !Net.isIPv6Available()) {
throw new UnsupportedOperationException("IPv6 not available");
}
this.family = family;
this.fd = Net.serverSocket(family, true);
if (family == UNIX) {
this.fd = UnixDomainSockets.socket();
} else {
this.fd = Net.serverSocket(family, true);
}
this.fdVal = IOUtil.fdVal(fd);
}
ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
ServerSocketChannelImpl(SelectorProvider sp,
ProtocolFamily family,
FileDescriptor fd,
boolean bound)
throws IOException
{
super(sp);
this.family = Net.isIPv6Available()
? StandardProtocolFamily.INET6
: StandardProtocolFamily.INET;
this.fd = fd;
if (family == UNIX) {
this.family = UNIX;
} else {
this.family = Net.isIPv6Available() ? INET6 : INET;
}
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
if (bound) {
synchronized (stateLock) {
localAddress = Net.localAddress(fd);
if (family == UNIX) {
localAddress = UnixDomainSockets.localAddress(fd);
} else {
localAddress = Net.localAddress(fd);
}
}
}
}
/**
* Returns true if this channel is to a INET or INET6 socket.
*/
private boolean isNetSocket() {
return (family == INET) || (family == INET6);
}
/**
* Returns true if this channel is to a UNIX socket.
*/
boolean isUnixSocket() {
return (family == UNIX);
}
// @throws ClosedChannelException if channel is closed
private void ensureOpen() throws ClosedChannelException {
if (!isOpen())
@ -150,8 +180,13 @@ class ServerSocketChannelImpl
@Override
public ServerSocket socket() {
synchronized (stateLock) {
if (socket == null)
socket = ServerSocketAdaptor.create(this);
if (socket == null) {
if (isNetSocket()) {
socket = ServerSocketAdaptor.create(this);
} else {
throw new UnsupportedOperationException("Not supported");
}
}
return socket;
}
}
@ -160,9 +195,11 @@ class ServerSocketChannelImpl
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
ensureOpen();
return (localAddress == null)
? null
: Net.getRevealedLocalAddress(localAddress);
if (isUnixSocket()) {
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
} else {
return Net.getRevealedLocalAddress(localAddress);
}
}
}
@ -178,10 +215,11 @@ class ServerSocketChannelImpl
synchronized (stateLock) {
ensureOpen();
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
if (isNetSocket()
&& name == StandardSocketOptions.SO_REUSEADDR
&& Net.useExclusiveBind()) {
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = (Boolean)value;
isReuseAddress = (Boolean) value;
} else {
// no options that require special handling
Net.setSocketOption(fd, Net.UNSPEC, name, value);
@ -201,19 +239,23 @@ class ServerSocketChannelImpl
synchronized (stateLock) {
ensureOpen();
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
if (isNetSocket()
&& name == StandardSocketOptions.SO_REUSEADDR
&& Net.useExclusiveBind()) {
// SO_REUSEADDR emulated when using exclusive bind
return (T)Boolean.valueOf(isReuseAddress);
return (T) Boolean.valueOf(isReuseAddress);
} else {
// no options that require special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
}
// no options that require special handling
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
}
}
private static class DefaultOptionsHolder {
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
static final Set<SocketOption<?>> defaultUnixDomainOptions = defaultUnixDomainOptions();
private static Set<SocketOption<?>> defaultOptions() {
private static Set<SocketOption<?>> defaultInetOptions() {
HashSet<SocketOption<?>> set = new HashSet<>();
set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_REUSEADDR);
@ -223,11 +265,21 @@ class ServerSocketChannelImpl
set.addAll(ExtendedSocketOptions.serverSocketOptions());
return Collections.unmodifiableSet(set);
}
private static Set<SocketOption<?>> defaultUnixDomainOptions() {
HashSet<SocketOption<?>> set = new HashSet<>();
set.add(StandardSocketOptions.SO_RCVBUF);
return Collections.unmodifiableSet(set);
}
}
@Override
public final Set<SocketOption<?>> supportedOptions() {
return DefaultOptionsHolder.defaultOptions;
if (isUnixSocket()) {
return DefaultOptionsHolder.defaultUnixDomainOptions;
} else {
return DefaultOptionsHolder.defaultInetOptions;
}
}
@Override
@ -236,23 +288,56 @@ class ServerSocketChannelImpl
ensureOpen();
if (localAddress != null)
throw new AlreadyBoundException();
InetSocketAddress isa;
if (local == null) {
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
if (isUnixSocket()) {
localAddress = unixBind(local, backlog);
} else {
isa = Net.checkAddress(local, family);
localAddress = netBind(local, backlog);
}
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkListen(isa.getPort());
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(family, fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
localAddress = Net.localAddress(fd);
}
return this;
}
private SocketAddress unixBind(SocketAddress local, int backlog) throws IOException {
UnixDomainSockets.checkPermission();
if (local == null) {
// Attempt up to 10 times to find an unused name in temp directory.
// If local address supplied then bind called only once
boolean bound = false;
int attempts = 0;
while (attempts < 10 && !bound) {
try {
Path path = UnixDomainSockets.generateTempName().getPath();
UnixDomainSockets.bind(fd, path);
bound = true;
} catch (BindException e) { }
attempts++;
}
if (!bound)
throw new BindException("Could not bind to temporary name");
} else {
Path path = UnixDomainSockets.checkAddress(local).getPath();
UnixDomainSockets.bind(fd, path);
}
Net.listen(fd, backlog < 1 ? 50 : backlog);
return UnixDomainSockets.localAddress(fd);
}
private SocketAddress netBind(SocketAddress local, int backlog) throws IOException {
InetSocketAddress isa;
if (local == null) {
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
} else {
isa = Net.checkAddress(local, family);
}
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkListen(isa.getPort());
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(family, fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
return Net.localAddress(fd);
}
/**
* Marks the beginning of an I/O operation that might block.
*
@ -295,18 +380,18 @@ class ServerSocketChannelImpl
public SocketChannel accept() throws IOException {
int n = 0;
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
SocketAddress[] saa = new SocketAddress[1];
acceptLock.lock();
try {
boolean blocking = isBlocking();
try {
begin(blocking);
n = Net.accept(this.fd, newfd, isaa);
n = implAccept(this.fd, newfd, saa);
if (blocking) {
while (IOStatus.okayToRetry(n) && isOpen()) {
park(Net.POLLIN);
n = Net.accept(this.fd, newfd, isaa);
n = implAccept(this.fd, newfd, saa);
}
}
} finally {
@ -318,12 +403,31 @@ class ServerSocketChannelImpl
}
if (n > 0) {
return finishAccept(newfd, isaa[0]);
return finishAccept(newfd, saa[0]);
} else {
return null;
}
}
private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa)
throws IOException
{
if (isUnixSocket()) {
UnixDomainSockets.checkPermission();
String[] pa = new String[1];
int n = UnixDomainSockets.accept(fd, newfd, pa);
if (n > 0)
saa[0] = UnixDomainSocketAddress.of(pa[0]);
return n;
} else {
InetSocketAddress[] issa = new InetSocketAddress[1];
int n = Net.accept(fd, newfd, issa);
if (n > 0)
saa[0] = issa[0];
return n;
}
}
/**
* Accepts a new connection with a given timeout. This method requires the
* channel to be configured in blocking mode.
@ -337,7 +441,7 @@ class ServerSocketChannelImpl
SocketChannel blockingAccept(long nanos) throws IOException {
int n = 0;
FileDescriptor newfd = new FileDescriptor();
InetSocketAddress[] isaa = new InetSocketAddress[1];
SocketAddress[] saa = new SocketAddress[1];
acceptLock.lock();
try {
@ -351,14 +455,14 @@ class ServerSocketChannelImpl
lockedConfigureBlocking(false);
try {
long startNanos = System.nanoTime();
n = Net.accept(fd, newfd, isaa);
n = implAccept(fd, newfd, saa);
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, saa);
}
} finally {
// restore socket to blocking mode (if channel is open)
@ -372,10 +476,10 @@ class ServerSocketChannelImpl
}
assert n > 0;
return finishAccept(newfd, isaa[0]);
return finishAccept(newfd, saa[0]);
}
private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa)
throws IOException
{
try {
@ -383,11 +487,14 @@ class ServerSocketChannelImpl
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());
if (isNetSocket()) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
InetSocketAddress isa = (InetSocketAddress) sa;
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
}
}
return new SocketChannelImpl(provider(), family, newfd, isa);
return new SocketChannelImpl(provider(), family, newfd, sa);
} catch (Exception e) {
nd.close(newfd);
throw e;
@ -536,7 +643,7 @@ class ServerSocketChannelImpl
/**
* Returns the local address, or null if not bound
*/
InetSocketAddress localAddress() {
SocketAddress localAddress() {
synchronized (stateLock) {
return localAddress;
}
@ -605,9 +712,11 @@ class ServerSocketChannelImpl
sb.append("closed");
} else {
synchronized (stateLock) {
InetSocketAddress addr = localAddress;
SocketAddress addr = localAddress;
if (addr == null) {
sb.append("unbound");
} else if (isUnixSocket()) {
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
} else {
sb.append(Net.getRevealedLocalAddressAsString(addr));
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, 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
@ -72,6 +72,14 @@ class SocketAdaptor
}
}
private InetSocketAddress localAddress() {
return (InetSocketAddress) sc.localAddress();
}
private InetSocketAddress remoteAddress() {
return (InetSocketAddress) sc.remoteAddress();
}
@Override
public void connect(SocketAddress remote) throws IOException {
connect(remote, 0);
@ -106,7 +114,7 @@ class SocketAdaptor
@Override
public InetAddress getInetAddress() {
InetSocketAddress remote = sc.remoteAddress();
InetSocketAddress remote = remoteAddress();
if (remote == null) {
return null;
} else {
@ -117,7 +125,7 @@ class SocketAdaptor
@Override
public InetAddress getLocalAddress() {
if (sc.isOpen()) {
InetSocketAddress local = sc.localAddress();
InetSocketAddress local = localAddress();
if (local != null) {
return Net.getRevealedLocalAddress(local).getAddress();
}
@ -127,7 +135,7 @@ class SocketAdaptor
@Override
public int getPort() {
InetSocketAddress remote = sc.remoteAddress();
InetSocketAddress remote = remoteAddress();
if (remote == null) {
return 0;
} else {
@ -137,7 +145,7 @@ class SocketAdaptor
@Override
public int getLocalPort() {
InetSocketAddress local = sc.localAddress();
InetSocketAddress local = localAddress();
if (local == null) {
return -1;
} else {
@ -152,12 +160,7 @@ class SocketAdaptor
@Override
public SocketAddress getLocalSocketAddress() {
InetSocketAddress local = sc.localAddress();
if (local != null) {
return Net.getRevealedLocalAddress(local);
} else {
return null;
}
return Net.getRevealedLocalAddress(sc.localAddress());
}
@Override

View file

@ -36,7 +36,6 @@ 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;
@ -50,11 +49,15 @@ import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import static java.net.StandardProtocolFamily.INET;
import static java.net.StandardProtocolFamily.INET6;
import static java.net.StandardProtocolFamily.UNIX;
import sun.net.ConnectionResetException;
import sun.net.NetHooks;
@ -114,52 +117,35 @@ class SocketChannelImpl
private long writerThread;
// Binding
private InetSocketAddress localAddress;
private InetSocketAddress remoteAddress;
private SocketAddress localAddress;
private SocketAddress remoteAddress;
// Socket adaptor, created on demand
private Socket socket;
// -- End of fields protected by stateLock
// Constructor for normal connecting sockets
//
SocketChannelImpl(SelectorProvider sp) throws IOException {
this(sp, Net.isIPv6Available()
? StandardProtocolFamily.INET6
: StandardProtocolFamily.INET);
this(sp, Net.isIPv6Available() ? INET6 : INET);
}
SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
super(sp);
Objects.requireNonNull(family, "'family' is null");
if ((family != StandardProtocolFamily.INET) &&
(family != StandardProtocolFamily.INET6)) {
if ((family != INET) && (family != INET6) && (family != UNIX)) {
throw new UnsupportedOperationException("Protocol family not supported");
}
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
if (family == INET6 && !Net.isIPv6Available()) {
throw new UnsupportedOperationException("IPv6 not available");
}
this.family = family;
this.fd = Net.socket(family, true);
this.fdVal = IOUtil.fdVal(fd);
}
SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
throws IOException
{
super(sp);
this.family = Net.isIPv6Available()
? StandardProtocolFamily.INET6
: StandardProtocolFamily.INET;
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
if (bound) {
synchronized (stateLock) {
this.localAddress = Net.localAddress(fd);
}
if (family == UNIX) {
this.fd = UnixDomainSockets.socket();
} else {
this.fd = Net.socket(family, true);
}
this.fdVal = IOUtil.fdVal(fd);
}
// Constructor for sockets obtained from server sockets
@ -167,7 +153,7 @@ class SocketChannelImpl
SocketChannelImpl(SelectorProvider sp,
ProtocolFamily family,
FileDescriptor fd,
InetSocketAddress isa)
SocketAddress remoteAddress)
throws IOException
{
super(sp);
@ -175,12 +161,30 @@ class SocketChannelImpl
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
synchronized (stateLock) {
this.localAddress = Net.localAddress(fd);
this.remoteAddress = isa;
if (family == UNIX) {
this.localAddress = UnixDomainSockets.localAddress(fd);
} else {
this.localAddress = Net.localAddress(fd);
}
this.remoteAddress = remoteAddress;
this.state = ST_CONNECTED;
}
}
/**
* Returns true if this channel is to a INET or INET6 socket.
*/
boolean isNetSocket() {
return (family == INET) || (family == INET6);
}
/**
* Returns true if this channel is to a UNIX socket.
*/
boolean isUnixSocket() {
return (family == UNIX);
}
/**
* Checks that the channel is open.
*
@ -215,8 +219,13 @@ class SocketChannelImpl
@Override
public Socket socket() {
synchronized (stateLock) {
if (socket == null)
socket = SocketAdaptor.create(this);
if (socket == null) {
if (isNetSocket()) {
socket = SocketAdaptor.create(this);
} else {
throw new UnsupportedOperationException("Not supported");
}
}
return socket;
}
}
@ -225,7 +234,11 @@ class SocketChannelImpl
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
ensureOpen();
return Net.getRevealedLocalAddress(localAddress);
if (isUnixSocket()) {
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
} else {
return Net.getRevealedLocalAddress(localAddress);
}
}
}
@ -250,15 +263,17 @@ class SocketChannelImpl
synchronized (stateLock) {
ensureOpen();
if (name == StandardSocketOptions.IP_TOS) {
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;
if (isNetSocket()) {
if (name == StandardSocketOptions.IP_TOS) {
// special handling for IP_TOS
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
@ -279,14 +294,15 @@ class SocketChannelImpl
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
if (name == StandardSocketOptions.IP_TOS) {
return (T) Net.getSocketOption(fd, family, name);
if (isNetSocket()) {
if (name == StandardSocketOptions.IP_TOS) {
// special handling for IP_TOS
return (T) Net.getSocketOption(fd, family, name);
}
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
@ -295,9 +311,10 @@ class SocketChannelImpl
}
private static class DefaultOptionsHolder {
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
static final Set<SocketOption<?>> defaultUnixOptions = defaultUnixOptions();
private static Set<SocketOption<?>> defaultOptions() {
private static Set<SocketOption<?>> defaultInetOptions() {
HashSet<SocketOption<?>> set = new HashSet<>();
set.add(StandardSocketOptions.SO_SNDBUF);
set.add(StandardSocketOptions.SO_RCVBUF);
@ -314,11 +331,24 @@ class SocketChannelImpl
set.addAll(ExtendedSocketOptions.clientSocketOptions());
return Collections.unmodifiableSet(set);
}
private static Set<SocketOption<?>> defaultUnixOptions() {
HashSet<SocketOption<?>> set = new HashSet<>();
set.add(StandardSocketOptions.SO_SNDBUF);
set.add(StandardSocketOptions.SO_RCVBUF);
set.add(StandardSocketOptions.SO_LINGER);
set.addAll(ExtendedSocketOptions.unixDomainSocketOptions());
return Collections.unmodifiableSet(set);
}
}
@Override
public final Set<SocketOption<?>> supportedOptions() {
return DefaultOptionsHolder.defaultOptions;
if (isUnixSocket()) {
return DefaultOptionsHolder.defaultUnixOptions;
} else {
return DefaultOptionsHolder.defaultInetOptions;
}
}
/**
@ -625,7 +655,7 @@ class SocketChannelImpl
/**
* Returns the local address, or null if not bound
*/
InetSocketAddress localAddress() {
SocketAddress localAddress() {
synchronized (stateLock) {
return localAddress;
}
@ -634,7 +664,7 @@ class SocketChannelImpl
/**
* Returns the remote address, or null if not connected
*/
InetSocketAddress remoteAddress() {
SocketAddress remoteAddress() {
synchronized (stateLock) {
return remoteAddress;
}
@ -652,19 +682,11 @@ class SocketChannelImpl
throw new ConnectionPendingException();
if (localAddress != null)
throw new AlreadyBoundException();
InetSocketAddress isa;
if (local == null) {
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
if (isUnixSocket()) {
localAddress = unixBind(local);
} else {
isa = Net.checkAddress(local, family);
localAddress = netBind(local);
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkListen(isa.getPort());
}
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(family, fd, isa.getAddress(), isa.getPort());
localAddress = Net.localAddress(fd);
}
} finally {
writeLock.unlock();
@ -675,6 +697,38 @@ class SocketChannelImpl
return this;
}
private SocketAddress unixBind(SocketAddress local) throws IOException {
UnixDomainSockets.checkPermission();
if (local == null) {
return UnixDomainSockets.UNNAMED;
} else {
Path path = UnixDomainSockets.checkAddress(local).getPath();
if (path.toString().isEmpty()) {
return UnixDomainSockets.UNNAMED;
} else {
// bind to non-empty path
UnixDomainSockets.bind(fd, path);
return UnixDomainSockets.localAddress(fd);
}
}
}
private SocketAddress netBind(SocketAddress local) throws IOException {
InetSocketAddress isa;
if (local == null) {
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
} else {
isa = Net.checkAddress(local, family);
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkListen(isa.getPort());
}
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(family, fd, isa.getAddress(), isa.getPort());
return Net.localAddress(fd);
}
@Override
public boolean isConnected() {
return (state == ST_CONNECTED);
@ -694,7 +748,7 @@ class SocketChannelImpl
* @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) {
@ -711,9 +765,11 @@ class SocketChannelImpl
assert state == ST_UNCONNECTED;
this.state = ST_CONNECTIONPENDING;
if (localAddress == null)
if (isNetSocket() && (localAddress == null)) {
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
@ -737,7 +793,11 @@ class SocketChannelImpl
if (completed) {
synchronized (stateLock) {
if (state == ST_CONNECTIONPENDING) {
localAddress = Net.localAddress(fd);
if (isUnixSocket()) {
localAddress = UnixDomainSockets.localAddress(fd);
} else {
localAddress = Net.localAddress(fd);
}
state = ST_CONNECTED;
}
}
@ -747,29 +807,34 @@ class SocketChannelImpl
/**
* Checks the remote address to which this channel is to be connected.
*/
private InetSocketAddress checkRemote(SocketAddress sa) {
InetSocketAddress isa = Net.checkAddress(sa, family);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
}
InetAddress address = isa.getAddress();
if (address.isAnyLocalAddress()) {
int port = isa.getPort();
if (address instanceof Inet4Address) {
return new InetSocketAddress(Net.inet4LoopbackAddress(), port);
} else {
assert family == StandardProtocolFamily.INET6;
return new InetSocketAddress(Net.inet6LoopbackAddress(), port);
}
private SocketAddress checkRemote(SocketAddress sa) {
if (isUnixSocket()) {
UnixDomainSockets.checkPermission();
return UnixDomainSockets.checkAddress(sa);
} else {
return isa;
InetSocketAddress isa = Net.checkAddress(sa, family);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
}
InetAddress address = isa.getAddress();
if (address.isAnyLocalAddress()) {
int port = isa.getPort();
if (address instanceof Inet4Address) {
return new InetSocketAddress(Net.inet4LoopbackAddress(), port);
} else {
assert family == INET6;
return new InetSocketAddress(Net.inet6LoopbackAddress(), port);
}
} else {
return isa;
}
}
}
@Override
public boolean connect(SocketAddress remote) throws IOException {
InetSocketAddress isa = checkRemote(remote);
SocketAddress sa = checkRemote(remote);
try {
readLock.lock();
try {
@ -778,11 +843,13 @@ class SocketChannelImpl
boolean blocking = isBlocking();
boolean connected = false;
try {
beginConnect(blocking, isa);
int n = Net.connect(family,
fd,
isa.getAddress(),
isa.getPort());
beginConnect(blocking, sa);
int n;
if (isUnixSocket()) {
n = UnixDomainSockets.connect(fd, sa);
} else {
n = Net.connect(family, fd, sa);
}
if (n > 0) {
connected = true;
} else if (blocking) {
@ -807,7 +874,7 @@ class SocketChannelImpl
} catch (IOException ioe) {
// connect failed, close the channel
close();
throw SocketExceptions.of(ioe, isa);
throw SocketExceptions.of(ioe, sa);
}
}
@ -848,7 +915,11 @@ class SocketChannelImpl
if (completed) {
synchronized (stateLock) {
if (state == ST_CONNECTIONPENDING) {
localAddress = Net.localAddress(fd);
if (isUnixSocket()) {
localAddress = UnixDomainSockets.localAddress(fd);
} else {
localAddress = Net.localAddress(fd);
}
state = ST_CONNECTED;
}
}
@ -1087,7 +1158,7 @@ class SocketChannelImpl
* @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 {
@ -1097,11 +1168,16 @@ class SocketChannelImpl
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;
if (isUnixSocket()) {
n = UnixDomainSockets.connect(fd, sa);
} else {
n = Net.connect(family, fd, sa);
}
connected = (n > 0) ? true : finishTimedConnect(nanos);
} finally {
// restore socket to blocking mode (if channel is open)
@ -1119,7 +1195,7 @@ class SocketChannelImpl
} catch (IOException ioe) {
// connect failed, close the channel
close();
throw SocketExceptions.of(ioe, isa);
throw SocketExceptions.of(ioe, sa);
}
}
@ -1390,10 +1466,14 @@ class SocketChannelImpl
sb.append(" oshut");
break;
}
InetSocketAddress addr = localAddress();
SocketAddress addr = localAddress();
if (addr != null) {
sb.append(" local=");
sb.append(Net.getRevealedLocalAddressAsString(addr));
if (isUnixSocket()) {
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
} else {
sb.append(Net.getRevealedLocalAddressAsString(addr));
}
}
if (remoteAddress() != null) {
sb.append(" remote=");

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.BindException;
import java.net.NetPermission;
import java.net.SocketAddress;
import java.net.UnixDomainSocketAddress;
import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.file.FileSystems;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.spi.FileSystemProvider;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import sun.nio.fs.AbstractFileSystemProvider;
class UnixDomainSockets {
private UnixDomainSockets() { }
static final UnixDomainSocketAddress UNNAMED = UnixDomainSocketAddress.of("");
private static final boolean supported;
private static final String tempDir = UnixDomainSocketsUtil.getTempDir();
private static final NetPermission accessUnixDomainSocket =
new NetPermission("accessUnixDomainSocket");
static boolean isSupported() {
return supported;
}
static void checkPermission() {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(accessUnixDomainSocket);
}
static UnixDomainSocketAddress getRevealedLocalAddress(SocketAddress sa) {
UnixDomainSocketAddress addr = (UnixDomainSocketAddress) sa;
try {
checkPermission();
// Security check passed
} catch (SecurityException e) {
// Return unnamed address only if security check fails
addr = UNNAMED;
}
return addr;
}
static UnixDomainSocketAddress localAddress(FileDescriptor fd) throws IOException {
String path = new String(localAddress0(fd), UnixDomainSocketsUtil.getCharset());
return UnixDomainSocketAddress.of(path);
}
private static native byte[] localAddress0(FileDescriptor fd) throws IOException;
static String getRevealedLocalAddressAsString(SocketAddress sa) {
return (System.getSecurityManager() != null) ? sa.toString() : "";
}
static UnixDomainSocketAddress checkAddress(SocketAddress sa) {
if (sa == null)
throw new NullPointerException();
if (!(sa instanceof UnixDomainSocketAddress))
throw new UnsupportedAddressTypeException();
return (UnixDomainSocketAddress) sa;
}
static byte[] getPathBytes(Path path) {
FileSystemProvider provider = FileSystems.getDefault().provider();
return ((AbstractFileSystemProvider) provider).getSunPathForSocketFile(path);
}
static FileDescriptor socket() throws IOException {
return IOUtil.newFD(socket0());
}
static void bind(FileDescriptor fd, Path addr) throws IOException {
byte[] path = getPathBytes(addr);
bind0(fd, path);
}
private static Random getRandom() {
try {
return SecureRandom.getInstance("NativePRNGNonBlocking");
} catch (NoSuchAlgorithmException e) {
return new SecureRandom(); // This should not fail
}
}
private static final Random random = getRandom();
/**
* Return a possible temporary name to bind to, which is different for each call
* Name is of the form <temp dir>/socket_<random>
*/
static UnixDomainSocketAddress generateTempName() throws IOException {
String dir = UnixDomainSockets.tempDir;
if (dir == null)
throw new BindException("Could not locate temporary directory for sockets");
int rnd = random.nextInt(Integer.MAX_VALUE);
try {
Path path = Path.of(dir, "socket_" + rnd);
return UnixDomainSocketAddress.of(path);
} catch (InvalidPathException e) {
throw new BindException("Invalid temporary directory");
}
}
static int connect(FileDescriptor fd, SocketAddress sa) throws IOException {
return UnixDomainSockets.connect(fd, ((UnixDomainSocketAddress) sa).getPath());
}
static int connect(FileDescriptor fd, Path path) throws IOException {
return connect0(fd, getPathBytes(path));
}
static int accept(FileDescriptor fd, FileDescriptor newfd, String[] paths)
throws IOException
{
Object[] array = new Object[1];
int n = accept0(fd, newfd, array);
if (n > 0) {
byte[] bytes = (byte[]) array[0];
paths[0] = new String(bytes, UnixDomainSocketsUtil.getCharset());
}
return n;
}
private static native boolean socketSupported();
private static native int socket0() throws IOException;
private static native void bind0(FileDescriptor fd, byte[] path)
throws IOException;
private static native int connect0(FileDescriptor fd, byte[] path)
throws IOException;
private static native int accept0(FileDescriptor fd, FileDescriptor newfd, Object[] array)
throws IOException;
static {
// Load all required native libs
IOUtil.load();
supported = socketSupported();
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020 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
@ -154,4 +154,10 @@ public abstract class AbstractFileSystemProvider extends FileSystemProvider {
return false;
}
}
/**
* Returns a path name as bytes for a Unix domain socket.
* Different encodings may be used for these names on some platforms.
*/
public abstract byte[] getSunPathForSocketFile(Path file);
}