8245194: Unix domain socket channel implementation
Reviewed-by: erikj, dfuchs, alanb, chegar
This commit is contained in:
parent
8bde2f4e3d
commit
6bb7e45e8e
@ -182,12 +182,16 @@ endif
|
|||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
$(eval $(call SetupCopyFiles, COPY_NET_PROPERTIES, \
|
NET_PROPERTIES_SRCS := $(TOPDIR)/src/java.base/share/conf/net.properties \
|
||||||
FILES := $(TOPDIR)/src/java.base/share/conf/net.properties, \
|
$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/net.properties
|
||||||
DEST := $(CONF_DST_DIR), \
|
|
||||||
))
|
|
||||||
|
|
||||||
TARGETS += $(COPY_NET_PROPERTIES)
|
NET_PROPERTIES_DST := $(CONF_DST_DIR)/net.properties
|
||||||
|
|
||||||
|
$(NET_PROPERTIES_DST): $(NET_PROPERTIES_SRCS)
|
||||||
|
$(call MakeTargetDir)
|
||||||
|
$(CAT) $(NET_PROPERTIES_SRCS) > $@
|
||||||
|
|
||||||
|
TARGETS += $(NET_PROPERTIES_DST)
|
||||||
|
|
||||||
ifeq ($(call isTargetOs, linux), true)
|
ifeq ($(call isTargetOs, linux), true)
|
||||||
$(eval $(call SetupCopyFiles, COPY_SDP_CONF, \
|
$(eval $(call SetupCopyFiles, COPY_SDP_CONF, \
|
||||||
|
@ -66,6 +66,16 @@ import java.util.StringTokenizer;
|
|||||||
* </tr>
|
* </tr>
|
||||||
*
|
*
|
||||||
* <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>
|
* <th scope="row">getCookieHandler</th>
|
||||||
* <td>The ability to get the cookie handler that processes highly
|
* <td>The ability to get the cookie handler that processes highly
|
||||||
* security sensitive cookie information for an Http session.</td>
|
* security sensitive cookie information for an Http session.</td>
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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)
|
* Internet Protocol Version 6 (IPv6)
|
||||||
*/
|
*/
|
||||||
INET6
|
INET6,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix domain (Local) interprocess communication.
|
||||||
|
* @since 16
|
||||||
|
*/
|
||||||
|
UNIX
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -150,6 +150,9 @@ public abstract class DatagramChannel
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* 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 {
|
public static DatagramChannel open() throws IOException {
|
||||||
return SelectorProvider.provider().openDatagramChannel();
|
return SelectorProvider.provider().openDatagramChannel();
|
||||||
@ -169,6 +172,9 @@ public abstract class DatagramChannel
|
|||||||
* java.nio.channels.spi.SelectorProvider} object. The channel will not be
|
* java.nio.channels.spi.SelectorProvider} object. The channel will not be
|
||||||
* connected.
|
* connected.
|
||||||
*
|
*
|
||||||
|
* @apiNote <a href="package-summary.html#unixdomain">Unix domain</a> sockets
|
||||||
|
* are not supported by DatagramChannel.
|
||||||
|
*
|
||||||
* @param family
|
* @param family
|
||||||
* The protocol family
|
* The protocol family
|
||||||
*
|
*
|
||||||
@ -182,6 +188,9 @@ public abstract class DatagramChannel
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* 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
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
public static DatagramChannel open(ProtocolFamily family) throws IOException {
|
public static DatagramChannel open(ProtocolFamily family) throws IOException {
|
||||||
@ -629,5 +638,4 @@ public abstract class DatagramChannel
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public abstract SocketAddress getLocalAddress() throws IOException;
|
public abstract SocketAddress getLocalAddress() throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,12 @@
|
|||||||
package java.nio.channels;
|
package java.nio.channels;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.NetPermission;
|
||||||
import java.net.ProtocolFamily;
|
import java.net.ProtocolFamily;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
@ -37,16 +39,20 @@ import static java.util.Objects.requireNonNull;
|
|||||||
/**
|
/**
|
||||||
* A selectable channel for stream-oriented listening sockets.
|
* A selectable channel for stream-oriented listening sockets.
|
||||||
*
|
*
|
||||||
* <p> A server-socket channel is created by invoking the {@link #open() open}
|
* <p> A server-socket channel is created by invoking one of the {@code open}
|
||||||
* method of this class. It is not possible to create a channel for an arbitrary,
|
* methods of this class. The no-arg {@link #open() open} method opens a server-socket
|
||||||
* pre-existing {@link ServerSocket}. A newly-created server-socket channel is
|
* channel for an <i>Internet protocol</i> socket. The {@link #open(ProtocolFamily)}
|
||||||
* open but not yet bound. An attempt to invoke the {@link #accept() accept}
|
* method is used to open a server-socket channel for a socket of a specified
|
||||||
* method of an unbound server-socket channel will cause a {@link NotYetBoundException}
|
* 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
|
* 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)
|
* <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>
|
* <blockquote>
|
||||||
* <table class="striped">
|
* <table class="striped">
|
||||||
* <caption style="display:none">Socket options</caption>
|
* <caption style="display:none">Socket options</caption>
|
||||||
@ -68,7 +74,27 @@ import static java.util.Objects.requireNonNull;
|
|||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* </blockquote>
|
* </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> Server-socket channels are safe for use by multiple concurrent threads.
|
||||||
* </p>
|
* </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
|
* <p> The new channel is created by invoking the {@link
|
||||||
* java.nio.channels.spi.SelectorProvider#openServerSocketChannel
|
* java.nio.channels.spi.SelectorProvider#openServerSocketChannel
|
||||||
@ -110,13 +136,16 @@ public abstract class ServerSocketChannel
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* 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 {
|
public static ServerSocketChannel open() throws IOException {
|
||||||
return SelectorProvider.provider().openServerSocketChannel();
|
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.
|
* {@link ProtocolFamily protocol family} of the channel's socket.
|
||||||
*
|
*
|
||||||
* <p> The new channel is created by invoking the {@link
|
* <p> The new channel is created by invoking the {@link
|
||||||
@ -137,6 +166,9 @@ public abstract class ServerSocketChannel
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* If an I/O error occurs
|
||||||
*
|
*
|
||||||
|
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
|
||||||
|
* java.net.preferIPv4Stack</a> system property
|
||||||
|
*
|
||||||
* @since 15
|
* @since 15
|
||||||
*/
|
*/
|
||||||
public static ServerSocketChannel open(ProtocolFamily family) throws IOException {
|
public static ServerSocketChannel open(ProtocolFamily family) throws IOException {
|
||||||
@ -180,8 +212,7 @@ public abstract class ServerSocketChannel
|
|||||||
* @throws ClosedChannelException {@inheritDoc}
|
* @throws ClosedChannelException {@inheritDoc}
|
||||||
* @throws IOException {@inheritDoc}
|
* @throws IOException {@inheritDoc}
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
* If a security manager has been installed and its {@link
|
* If a security manager has been installed and it denies the
|
||||||
* SecurityManager#checkListen checkListen} method denies the
|
|
||||||
* operation
|
* operation
|
||||||
*
|
*
|
||||||
* @since 1.7
|
* @since 1.7
|
||||||
@ -197,8 +228,8 @@ public abstract class ServerSocketChannel
|
|||||||
* listen for connections.
|
* listen for connections.
|
||||||
*
|
*
|
||||||
* <p> This method is used to establish an association between the socket and
|
* <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
|
* a local address. For <i>Internet protocol</i> sockets, once an association
|
||||||
* bound until the channel is closed.
|
* is established then the socket remains bound until the channel is closed.
|
||||||
*
|
*
|
||||||
* <p> The {@code backlog} parameter is the maximum number of pending
|
* <p> The {@code backlog} parameter is the maximum number of pending
|
||||||
* connections on the socket. Its exact semantics are implementation specific.
|
* 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
|
* the value {@code 0}, or a negative value, then an implementation specific
|
||||||
* default is used.
|
* 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
|
* @param local
|
||||||
* The address to bind the socket, or {@code null} to bind to an
|
* The address to bind the socket, or {@code null} to bind to
|
||||||
* automatically assigned socket address
|
* an automatically assigned socket address
|
||||||
* @param backlog
|
* @param backlog
|
||||||
* The maximum number of pending connections
|
* The maximum number of pending connections
|
||||||
*
|
*
|
||||||
@ -225,8 +272,10 @@ public abstract class ServerSocketChannel
|
|||||||
* If some other I/O error occurs
|
* If some other I/O error occurs
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
* If a security manager has been installed and its {@link
|
* If a security manager has been installed and its {@link
|
||||||
* SecurityManager#checkListen checkListen} method denies the
|
* SecurityManager#checkListen checkListen} method denies
|
||||||
* operation
|
* 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
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
@ -251,6 +300,9 @@ public abstract class ServerSocketChannel
|
|||||||
* declared in the {@link java.net.ServerSocket} class. </p>
|
* declared in the {@link java.net.ServerSocket} class. </p>
|
||||||
*
|
*
|
||||||
* @return A server socket associated with this channel
|
* @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();
|
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
|
* <p> The socket channel returned by this method, if any, will be in
|
||||||
* blocking mode regardless of the blocking mode of this channel.
|
* blocking mode regardless of the blocking mode of this channel.
|
||||||
*
|
*
|
||||||
* <p> This method performs exactly the same security checks as the {@link
|
* <p> If bound to an <i>Internet protocol</i> socket address, this method
|
||||||
* java.net.ServerSocket#accept accept} method of the {@link
|
* performs exactly the same security checks as the {@link
|
||||||
* java.net.ServerSocket} class. That is, if a security manager has been
|
* java.net.ServerSocket#accept accept} method of the {@link java.net.ServerSocket}
|
||||||
* installed then for each new connection this method verifies that the
|
* class. That is, if a security manager has been installed then for each
|
||||||
* address and port number of the connection's remote endpoint are
|
* new connection this method verifies that the address and port number
|
||||||
* permitted by the security manager's {@link
|
* of the connection's remote endpoint are permitted by the security
|
||||||
* java.lang.SecurityManager#checkAccept checkAccept} method. </p>
|
* 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,
|
* @return The socket channel for the new connection,
|
||||||
* or {@code null} if this channel is in non-blocking mode
|
* or {@code null} if this channel is in non-blocking mode
|
||||||
@ -305,7 +359,7 @@ public abstract class ServerSocketChannel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
* <p>
|
*
|
||||||
* If there is a security manager set, its {@code checkConnect} method is
|
* 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
|
* called with the local address and {@code -1} as its arguments to see
|
||||||
* if the operation is allowed. If the operation is not allowed,
|
* 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
|
* {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
|
||||||
* local port of the channel's socket is returned.
|
* 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
|
* @return The {@code SocketAddress} that the socket is bound to, or the
|
||||||
* {@code SocketAddress} representing the loopback address if
|
* {@code SocketAddress} representing the loopback address or empty
|
||||||
* denied by the security manager, or {@code null} if the
|
* path if denied by the security manager, or {@code null} if the
|
||||||
* channel's socket is not bound
|
* channel's socket is not bound
|
||||||
*
|
*
|
||||||
* @throws ClosedChannelException {@inheritDoc}
|
* @throws ClosedChannelException {@inheritDoc}
|
||||||
@ -323,5 +384,4 @@ public abstract class ServerSocketChannel
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public abstract SocketAddress getLocalAddress() throws IOException;
|
public abstract SocketAddress getLocalAddress() throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,14 @@
|
|||||||
package java.nio.channels;
|
package java.nio.channels;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.NetPermission;
|
||||||
import java.net.ProtocolFamily;
|
import java.net.ProtocolFamily;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
@ -38,15 +42,18 @@ import static java.util.Objects.requireNonNull;
|
|||||||
/**
|
/**
|
||||||
* A selectable channel for stream-oriented connecting sockets.
|
* A selectable channel for stream-oriented connecting sockets.
|
||||||
*
|
*
|
||||||
* <p> A socket channel is created by invoking one of the {@link #open open}
|
* <p> A socket channel is created by invoking one of the {@code open} methods of
|
||||||
* methods of this class. It is not possible to create a channel for an arbitrary,
|
* this class. The no-arg {@link #open() open} method opens a socket channel
|
||||||
* pre-existing socket. A newly-created socket channel is open but not yet
|
* for an <i>Internet protocol</i> socket. The {@link #open(ProtocolFamily)}
|
||||||
* connected. An attempt to invoke an I/O operation upon an unconnected
|
* method is used to open a socket channel for a socket of a specified protocol
|
||||||
* channel will cause a {@link NotYetConnectedException} to be thrown. A
|
* family. It is not possible to create a channel for an arbitrary, pre-existing
|
||||||
* socket channel can be connected by invoking its {@link #connect connect}
|
* socket. A newly-created socket channel is open but not yet connected. An
|
||||||
* method; once connected, a socket channel remains connected until it is
|
* attempt to invoke an I/O operation upon an unconnected channel will cause a
|
||||||
* closed. Whether or not a socket channel is connected may be determined by
|
* {@link NotYetConnectedException} to be thrown. A socket channel can be
|
||||||
* invoking its {@link #isConnected isConnected} method.
|
* 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> A socket
|
* <p> Socket channels support <i>non-blocking connection:</i> A socket
|
||||||
* channel may be created and the process of establishing the link to the
|
* 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
|
* Whether or not a connection operation is in progress may be determined by
|
||||||
* invoking the {@link #isConnectionPending isConnectionPending} method.
|
* 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.
|
* 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
|
* 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
|
* 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}.
|
* AsynchronousCloseException}.
|
||||||
*
|
*
|
||||||
* <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
|
* <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>
|
* <blockquote>
|
||||||
* <table class="striped">
|
* <table class="striped">
|
||||||
* <caption style="display:none">Socket options</caption>
|
* <caption style="display:none">Socket options</caption>
|
||||||
@ -105,7 +113,36 @@ import static java.util.Objects.requireNonNull;
|
|||||||
* </tbody>
|
* </tbody>
|
||||||
* </table>
|
* </table>
|
||||||
* </blockquote>
|
* </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
|
* <p> Socket channels are safe for use by multiple concurrent threads. They
|
||||||
* support concurrent reading and writing, though at most one thread may be
|
* 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
|
* <p> The new channel is created by invoking the {@link
|
||||||
* java.nio.channels.spi.SelectorProvider#openSocketChannel
|
* java.nio.channels.spi.SelectorProvider#openSocketChannel
|
||||||
@ -147,6 +184,9 @@ public abstract class SocketChannel
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* 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 {
|
public static SocketChannel open() throws IOException {
|
||||||
return SelectorProvider.provider().openSocketChannel();
|
return SelectorProvider.provider().openSocketChannel();
|
||||||
@ -174,6 +214,9 @@ public abstract class SocketChannel
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If an I/O error occurs
|
* If an I/O error occurs
|
||||||
*
|
*
|
||||||
|
* @see <a href="../../net/doc-files/net-properties.html#Ipv4IPv6">
|
||||||
|
* java.net.preferIPv4Stack</a> system property
|
||||||
|
*
|
||||||
* @since 15
|
* @since 15
|
||||||
*/
|
*/
|
||||||
public static SocketChannel open(ProtocolFamily family) throws IOException {
|
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.
|
* Opens a socket channel and connects it to a remote address.
|
||||||
*
|
*
|
||||||
* <p> This convenience method works as if by invoking the {@link #open()}
|
* <p> If the remote address is an {@link InetSocketAddress} then this
|
||||||
* method, invoking the {@link #connect(SocketAddress) connect} method upon
|
* method works as if by invoking the {@link #open()} method, invoking the
|
||||||
* the resulting socket channel, passing it {@code remote}, and then
|
* {@link #connect(SocketAddress) connect} method upon the resulting socket
|
||||||
* returning that channel. </p>
|
* 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
|
* @param remote
|
||||||
* The remote address to which the new channel is to be connected
|
* The remote address to which the new channel is to be connected
|
||||||
@ -204,7 +253,8 @@ public abstract class SocketChannel
|
|||||||
* interrupt status
|
* interrupt status
|
||||||
*
|
*
|
||||||
* @throws UnresolvedAddressException
|
* @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
|
* @throws UnsupportedAddressTypeException
|
||||||
* If the type of the given remote address is not supported
|
* If the type of the given remote address is not supported
|
||||||
@ -215,11 +265,22 @@ public abstract class SocketChannel
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* If some other I/O error occurs
|
* 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)
|
public static SocketChannel open(SocketAddress remote)
|
||||||
throws IOException
|
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 {
|
try {
|
||||||
sc.connect(remote);
|
sc.connect(remote);
|
||||||
} catch (Throwable x) {
|
} catch (Throwable x) {
|
||||||
@ -255,6 +316,38 @@ public abstract class SocketChannel
|
|||||||
// -- Socket-specific operations --
|
// -- 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
|
* @throws ConnectionPendingException
|
||||||
* If a non-blocking connect operation is already in progress on
|
* If a non-blocking connect operation is already in progress on
|
||||||
* this channel
|
* this channel
|
||||||
@ -263,9 +356,11 @@ public abstract class SocketChannel
|
|||||||
* @throws ClosedChannelException {@inheritDoc}
|
* @throws ClosedChannelException {@inheritDoc}
|
||||||
* @throws IOException {@inheritDoc}
|
* @throws IOException {@inheritDoc}
|
||||||
* @throws SecurityException
|
* @throws SecurityException
|
||||||
* If a security manager has been installed and its
|
* If a security manager has been installed and its {@link
|
||||||
* {@link SecurityManager#checkListen checkListen} method denies
|
* SecurityManager#checkListen checkListen} method denies
|
||||||
* the operation
|
* 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
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
@ -329,10 +424,10 @@ public abstract class SocketChannel
|
|||||||
/**
|
/**
|
||||||
* Retrieves a socket associated with this channel.
|
* 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
|
* @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();
|
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
|
* method will block until the connection is established or an I/O error
|
||||||
* occurs.
|
* occurs.
|
||||||
*
|
*
|
||||||
* <p> This method performs exactly the same security checks as the {@link
|
* <p> For channels to <i>Internet protocol</i> sockets, this method performs
|
||||||
* java.net.Socket} class. That is, if a security manager has been
|
* 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
|
* installed then this method verifies that its {@link
|
||||||
* java.lang.SecurityManager#checkConnect checkConnect} method permits
|
* java.lang.SecurityManager#checkConnect checkConnect} method permits
|
||||||
* connecting to the address and port number of the given remote endpoint.
|
* 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
|
* <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
|
* operation upon this channel is invoked while an invocation of this
|
||||||
* method is in progress then that operation will first block until this
|
* method is in progress then that operation will first block until this
|
||||||
@ -409,7 +511,7 @@ public abstract class SocketChannel
|
|||||||
* interrupt status
|
* interrupt status
|
||||||
*
|
*
|
||||||
* @throws UnresolvedAddressException
|
* @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
|
* @throws UnsupportedAddressTypeException
|
||||||
* If the type of the given remote address is not supported
|
* 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.
|
* Returns the remote address to which this channel's socket is connected.
|
||||||
*
|
*
|
||||||
* <p> Where the channel is bound and connected to an Internet Protocol
|
* <p> Where the channel's socket is bound and connected to an <i>Internet
|
||||||
* socket address then the return value from this method is of type {@link
|
* Protocol</i> socket address then the return value is of type
|
||||||
* java.net.InetSocketAddress}.
|
* {@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
|
* @return The remote address; {@code null} if the channel's socket is not
|
||||||
* connected
|
* connected
|
||||||
@ -539,7 +644,7 @@ public abstract class SocketChannel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
* <p>
|
*
|
||||||
* If there is a security manager set, its {@code checkConnect} method is
|
* 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
|
* called with the local address and {@code -1} as its arguments to see
|
||||||
* if the operation is allowed. If the operation is not allowed,
|
* 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
|
* {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
|
||||||
* local port of the channel's socket is returned.
|
* 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
|
* @return The {@code SocketAddress} that the socket is bound to, or the
|
||||||
* {@code SocketAddress} representing the loopback address if
|
* {@code SocketAddress} representing the loopback address or empty
|
||||||
* denied by the security manager, or {@code null} if the
|
* path if denied by the security manager, or {@code null} if the
|
||||||
* channel's socket is not bound
|
* channel's socket is not bound
|
||||||
*
|
*
|
||||||
* @throws ClosedChannelException {@inheritDoc}
|
* @throws ClosedChannelException {@inheritDoc}
|
||||||
@ -557,5 +669,4 @@ public abstract class SocketChannel
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public abstract SocketAddress getLocalAddress() throws IOException;
|
public abstract SocketAddress getLocalAddress() throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* If a channel needs an associated socket then a socket will be created as a side
|
||||||
* effect of this operation.
|
* 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
|
* <p> The implementation of selectors, selectable channels, and selection keys
|
||||||
* can be replaced by "plugging in" an alternative definition or instance of the
|
* can be replaced by "plugging in" an alternative definition or instance of the
|
||||||
* {@link java.nio.channels.spi.SelectorProvider} class defined in the {@link
|
* {@link java.nio.channels.spi.SelectorProvider} class defined in the {@link
|
||||||
|
@ -268,34 +268,38 @@ public abstract class SelectorProvider {
|
|||||||
* associated network port. In this example, the process that is started,
|
* associated network port. In this example, the process that is started,
|
||||||
* inherits a channel representing a network socket.
|
* inherits a channel representing a network socket.
|
||||||
*
|
*
|
||||||
* <p> In cases where the inherited channel represents a network socket
|
* <p> In cases where the inherited channel is for an <i>Internet protocol</i>
|
||||||
* then the {@link java.nio.channels.Channel Channel} type returned
|
* socket then the {@link Channel Channel} type returned
|
||||||
* by this method is determined as follows:
|
* by this method is determined as follows:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
*
|
*
|
||||||
* <li><p> If the inherited channel represents a stream-oriented connected
|
* <li><p> If the inherited channel is for a stream-oriented connected
|
||||||
* socket then a {@link java.nio.channels.SocketChannel SocketChannel} is
|
* socket then a {@link SocketChannel SocketChannel} is returned. The
|
||||||
* returned. The socket channel is, at least initially, in blocking
|
* socket channel is, at least initially, in blocking mode, bound
|
||||||
* mode, bound to a socket address, and connected to a peer.
|
* to a socket address, and connected to a peer.
|
||||||
* </p></li>
|
* </p></li>
|
||||||
*
|
*
|
||||||
* <li><p> If the inherited channel represents a stream-oriented listening
|
* <li><p> If the inherited channel is for a stream-oriented listening
|
||||||
* socket then a {@link java.nio.channels.ServerSocketChannel
|
* socket then a {@link ServerSocketChannel ServerSocketChannel} is returned.
|
||||||
* ServerSocketChannel} is returned. The server-socket channel is, at
|
* The server-socket channel is, at least initially, in blocking mode,
|
||||||
* least initially, in blocking mode, and bound to a socket address.
|
* and bound to a socket address.
|
||||||
* </p></li>
|
* </p></li>
|
||||||
*
|
*
|
||||||
* <li><p> If the inherited channel is a datagram-oriented socket
|
* <li><p> If the inherited channel is a datagram-oriented socket then a
|
||||||
* then a {@link java.nio.channels.DatagramChannel DatagramChannel} is
|
* {@link DatagramChannel DatagramChannel} is returned. The datagram channel
|
||||||
* returned. The datagram channel is, at least initially, in blocking
|
* is, at least initially, in blocking mode, and bound to a socket address.
|
||||||
* mode, and bound to a socket address.
|
|
||||||
* </p></li>
|
* </p></li>
|
||||||
*
|
*
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p> In addition to the network-oriented channels described, this method
|
* <p> In cases where the inherited channel is for a <i>Unix domain</i>
|
||||||
* may return other kinds of channels in the future.
|
* 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
|
* <p> The first invocation of this method creates the channel that is
|
||||||
* returned. Subsequent invocations of this method return the same
|
* returned. Subsequent invocations of this method return the same
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.PosixFilePermission;
|
||||||
import java.nio.file.attribute.PosixFilePermissions;
|
import java.nio.file.attribute.PosixFilePermissions;
|
||||||
import static java.nio.file.attribute.PosixFilePermission.*;
|
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
|
* Helper class to support creation of temporary files and directories with
|
||||||
@ -45,8 +44,7 @@ class TempFileHelper {
|
|||||||
private TempFileHelper() { }
|
private TempFileHelper() { }
|
||||||
|
|
||||||
// temporary directory location
|
// temporary directory location
|
||||||
private static final Path tmpdir =
|
private static final Path tmpdir = Path.of(StaticProperty.javaIoTmpDir());
|
||||||
Path.of(GetPropertyAction.privilegedGetProperty("java.io.tmpdir"));
|
|
||||||
|
|
||||||
private static final boolean isPosix =
|
private static final boolean isPosix =
|
||||||
FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
|
||||||
|
@ -47,6 +47,7 @@ public final class StaticProperty {
|
|||||||
private static final String JAVA_LIBRARY_PATH;
|
private static final String JAVA_LIBRARY_PATH;
|
||||||
private static final String SUN_BOOT_LIBRARY_PATH;
|
private static final String SUN_BOOT_LIBRARY_PATH;
|
||||||
private static final String JDK_SERIAL_FILTER;
|
private static final String JDK_SERIAL_FILTER;
|
||||||
|
private static final String JAVA_IO_TMPDIR;
|
||||||
|
|
||||||
private StaticProperty() {}
|
private StaticProperty() {}
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ public final class StaticProperty {
|
|||||||
USER_HOME = getProperty(props, "user.home");
|
USER_HOME = getProperty(props, "user.home");
|
||||||
USER_DIR = getProperty(props, "user.dir");
|
USER_DIR = getProperty(props, "user.dir");
|
||||||
USER_NAME = getProperty(props, "user.name");
|
USER_NAME = getProperty(props, "user.name");
|
||||||
|
JAVA_IO_TMPDIR = getProperty(props, "java.io.tmpdir");
|
||||||
JAVA_LIBRARY_PATH = getProperty(props, "java.library.path", "");
|
JAVA_LIBRARY_PATH = getProperty(props, "java.library.path", "");
|
||||||
SUN_BOOT_LIBRARY_PATH = getProperty(props, "sun.boot.library.path", "");
|
SUN_BOOT_LIBRARY_PATH = getProperty(props, "sun.boot.library.path", "");
|
||||||
JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null);
|
JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null);
|
||||||
@ -140,6 +142,19 @@ public final class StaticProperty {
|
|||||||
return JAVA_LIBRARY_PATH;
|
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.
|
* Return the {@code sun.boot.library.path} system property.
|
||||||
*
|
*
|
||||||
|
@ -270,6 +270,8 @@ module java.base {
|
|||||||
jdk.incubator.foreign;
|
jdk.incubator.foreign;
|
||||||
exports sun.nio.cs to
|
exports sun.nio.cs to
|
||||||
jdk.charsets;
|
jdk.charsets;
|
||||||
|
exports sun.nio.fs to
|
||||||
|
jdk.net;
|
||||||
exports sun.reflect.annotation to
|
exports sun.reflect.annotation to
|
||||||
jdk.compiler;
|
jdk.compiler;
|
||||||
exports sun.reflect.generics.reflectiveObjects to
|
exports sun.reflect.generics.reflectiveObjects to
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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<?>> datagramOptions;
|
||||||
private final Set<SocketOption<?>> clientStreamOptions;
|
private final Set<SocketOption<?>> clientStreamOptions;
|
||||||
private final Set<SocketOption<?>> serverStreamOptions;
|
private final Set<SocketOption<?>> serverStreamOptions;
|
||||||
|
private final Set<SocketOption<?>> unixDomainClientOptions;
|
||||||
|
|
||||||
/** Tells whether or not the option is supported. */
|
/** Tells whether or not the option is supported. */
|
||||||
public final boolean isOptionSupported(SocketOption<?> option) {
|
public final boolean isOptionSupported(SocketOption<?> option) {
|
||||||
@ -73,6 +74,19 @@ public abstract class ExtendedSocketOptions {
|
|||||||
return getInstance().options0(SOCK_STREAM, false);
|
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
|
* Returns the (possibly empty) set of extended socket options for
|
||||||
* datagram-oriented sockets.
|
* datagram-oriented sockets.
|
||||||
@ -82,14 +96,22 @@ public abstract class ExtendedSocketOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDatagramOption(SocketOption<?> option) {
|
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) {
|
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;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return !option.name().startsWith("UDP_");
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +144,7 @@ public abstract class ExtendedSocketOptions {
|
|||||||
var datagramOptions = new HashSet<SocketOption<?>>();
|
var datagramOptions = new HashSet<SocketOption<?>>();
|
||||||
var serverStreamOptions = new HashSet<SocketOption<?>>();
|
var serverStreamOptions = new HashSet<SocketOption<?>>();
|
||||||
var clientStreamOptions = new HashSet<SocketOption<?>>();
|
var clientStreamOptions = new HashSet<SocketOption<?>>();
|
||||||
|
var unixDomainClientOptions = new HashSet<SocketOption<?>>();
|
||||||
for (var option : options) {
|
for (var option : options) {
|
||||||
if (isDatagramOption(option)) {
|
if (isDatagramOption(option)) {
|
||||||
datagramOptions.add(option);
|
datagramOptions.add(option);
|
||||||
@ -132,10 +155,14 @@ public abstract class ExtendedSocketOptions {
|
|||||||
if (isStreamOption(option, false)) {
|
if (isStreamOption(option, false)) {
|
||||||
clientStreamOptions.add(option);
|
clientStreamOptions.add(option);
|
||||||
}
|
}
|
||||||
|
if (isUnixDomainOption(option)) {
|
||||||
|
unixDomainClientOptions.add(option);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.datagramOptions = Set.copyOf(datagramOptions);
|
this.datagramOptions = Set.copyOf(datagramOptions);
|
||||||
this.serverStreamOptions = Set.copyOf(serverStreamOptions);
|
this.serverStreamOptions = Set.copyOf(serverStreamOptions);
|
||||||
this.clientStreamOptions = Set.copyOf(clientStreamOptions);
|
this.clientStreamOptions = Set.copyOf(clientStreamOptions);
|
||||||
|
this.unixDomainClientOptions = Set.copyOf(unixDomainClientOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static volatile ExtendedSocketOptions instance;
|
private static volatile ExtendedSocketOptions instance;
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
|
|
||||||
@ -51,11 +53,22 @@ public final class SocketExceptions {
|
|||||||
*
|
*
|
||||||
* Only specific IOException subtypes are supported.
|
* Only specific IOException subtypes are supported.
|
||||||
*/
|
*/
|
||||||
public static IOException of(IOException e, InetSocketAddress address) {
|
public static IOException of(IOException e, SocketAddress addr) {
|
||||||
if (!enhancedExceptionText || address == null)
|
if (!enhancedExceptionText || addr == null) {
|
||||||
return e;
|
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();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(e.getMessage());
|
sb.append(e.getMessage());
|
||||||
sb.append(": ");
|
sb.append(": ");
|
||||||
@ -66,6 +79,16 @@ public final class SocketExceptions {
|
|||||||
return create(e, enhancedMsg);
|
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
|
// return a new instance of the same type with the given detail
|
||||||
// msg, or if the type doesn't support detail msgs, return given
|
// msg, or if the type doesn't support detail msgs, return given
|
||||||
// instance.
|
// instance.
|
||||||
|
@ -226,29 +226,31 @@ public class Net {
|
|||||||
/**
|
/**
|
||||||
* Returns the local address after performing a SecurityManager#checkConnect.
|
* 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();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
if (addr == null || sm == null)
|
if (isa != null && sm != null) {
|
||||||
return addr;
|
try {
|
||||||
|
sm.checkConnect(isa.getAddress().getHostAddress(), -1);
|
||||||
try{
|
} catch (SecurityException e) {
|
||||||
sm.checkConnect(addr.getAddress().getHostAddress(), -1);
|
// Return loopback address only if security check fails
|
||||||
// Security check passed
|
isa = getLoopbackAddress(isa.getPort());
|
||||||
} catch (SecurityException e) {
|
}
|
||||||
// Return loopback address only if security check fails
|
|
||||||
addr = getLoopbackAddress(addr.getPort());
|
|
||||||
}
|
}
|
||||||
return addr;
|
return isa;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
|
static String getRevealedLocalAddressAsString(SocketAddress sa) {
|
||||||
return System.getSecurityManager() == null ? addr.toString() :
|
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||||
getLoopbackAddress(addr.getPort()).toString();
|
if (System.getSecurityManager() == null) {
|
||||||
|
return isa.toString();
|
||||||
|
} else {
|
||||||
|
return getLoopbackAddress(isa.getPort()).toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InetSocketAddress getLoopbackAddress(int port) {
|
private static InetSocketAddress getLoopbackAddress(int port) {
|
||||||
return new InetSocketAddress(InetAddress.getLoopbackAddress(),
|
return new InetSocketAddress(InetAddress.getLoopbackAddress(), port);
|
||||||
port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final InetAddress anyLocalInet4Address;
|
private static final InetAddress anyLocalInet4Address;
|
||||||
@ -574,6 +576,13 @@ public class Net {
|
|||||||
return connect0(preferIPv6, fd, remote, remotePort);
|
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,
|
private static native int connect0(boolean preferIPv6,
|
||||||
FileDescriptor fd,
|
FileDescriptor fd,
|
||||||
InetAddress remote,
|
InetAddress remote,
|
||||||
|
@ -33,6 +33,10 @@ import java.nio.channels.ServerSocketChannel;
|
|||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.nio.channels.spi.AbstractSelector;
|
import java.nio.channels.spi.AbstractSelector;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
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
|
public abstract class SelectorProviderImpl
|
||||||
extends SelectorProvider
|
extends SelectorProvider
|
||||||
@ -75,11 +79,29 @@ public abstract class SelectorProviderImpl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SocketChannel openSocketChannel(ProtocolFamily family) throws IOException {
|
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
|
@Override
|
||||||
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) {
|
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) throws IOException {
|
||||||
return new ServerSocketChannelImpl(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 ServerSocketChannelImpl(this, family);
|
||||||
|
} else if (family == UNIX && UnixDomainSockets.isSupported()) {
|
||||||
|
return new ServerSocketChannelImpl(this, family);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Protocol family not supported");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -93,7 +93,7 @@ class ServerSocketAdaptor // package-private
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetAddress getInetAddress() {
|
public InetAddress getInetAddress() {
|
||||||
InetSocketAddress local = ssc.localAddress();
|
SocketAddress local = ssc.localAddress();
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@ -103,7 +103,7 @@ class ServerSocketAdaptor // package-private
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLocalPort() {
|
public int getLocalPort() {
|
||||||
InetSocketAddress local = ssc.localAddress();
|
InetSocketAddress local = (InetSocketAddress) ssc.localAddress();
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.BindException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ProtocolFamily;
|
import java.net.ProtocolFamily;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.StandardProtocolFamily;
|
|
||||||
import java.net.StandardSocketOptions;
|
import java.net.StandardSocketOptions;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.channels.AlreadyBoundException;
|
import java.nio.channels.AlreadyBoundException;
|
||||||
import java.nio.channels.AsynchronousCloseException;
|
import java.nio.channels.AsynchronousCloseException;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
@ -44,11 +45,15 @@ import java.nio.channels.SelectionKey;
|
|||||||
import java.nio.channels.ServerSocketChannel;
|
import java.nio.channels.ServerSocketChannel;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
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.NetHooks;
|
||||||
import sun.net.ext.ExtendedSocketOptions;
|
import sun.net.ext.ExtendedSocketOptions;
|
||||||
@ -90,7 +95,7 @@ class ServerSocketChannelImpl
|
|||||||
private long thread;
|
private long thread;
|
||||||
|
|
||||||
// Binding
|
// Binding
|
||||||
private InetSocketAddress localAddress; // null => unbound
|
private SocketAddress localAddress; // null => unbound
|
||||||
|
|
||||||
// set true when exclusive binding is on and SO_REUSEADDR is emulated
|
// set true when exclusive binding is on and SO_REUSEADDR is emulated
|
||||||
private boolean isReuseAddress;
|
private boolean isReuseAddress;
|
||||||
@ -100,47 +105,72 @@ class ServerSocketChannelImpl
|
|||||||
|
|
||||||
// -- End of fields protected by stateLock
|
// -- End of fields protected by stateLock
|
||||||
|
|
||||||
ServerSocketChannelImpl(SelectorProvider sp) {
|
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
|
||||||
this(sp, Net.isIPv6Available()
|
this(sp, Net.isIPv6Available() ? INET6 : INET);
|
||||||
? StandardProtocolFamily.INET6
|
|
||||||
: StandardProtocolFamily.INET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) {
|
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
super(sp);
|
super(sp);
|
||||||
Objects.requireNonNull(family, "'family' is null");
|
Objects.requireNonNull(family, "'family' is null");
|
||||||
|
if ((family != INET) && (family != INET6) && (family != UNIX)) {
|
||||||
if ((family != StandardProtocolFamily.INET) &&
|
|
||||||
(family != StandardProtocolFamily.INET6)) {
|
|
||||||
throw new UnsupportedOperationException("Protocol family not supported");
|
throw new UnsupportedOperationException("Protocol family not supported");
|
||||||
}
|
}
|
||||||
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
|
if (family == INET6 && !Net.isIPv6Available()) {
|
||||||
throw new UnsupportedOperationException("IPv6 not available");
|
throw new UnsupportedOperationException("IPv6 not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.family = family;
|
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);
|
this.fdVal = IOUtil.fdVal(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
|
ServerSocketChannelImpl(SelectorProvider sp,
|
||||||
|
ProtocolFamily family,
|
||||||
|
FileDescriptor fd,
|
||||||
|
boolean bound)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(sp);
|
super(sp);
|
||||||
|
|
||||||
this.family = Net.isIPv6Available()
|
if (family == UNIX) {
|
||||||
? StandardProtocolFamily.INET6
|
this.family = UNIX;
|
||||||
: StandardProtocolFamily.INET;
|
} else {
|
||||||
this.fd = fd;
|
this.family = Net.isIPv6Available() ? INET6 : INET;
|
||||||
|
}
|
||||||
|
this.fd = fd;
|
||||||
this.fdVal = IOUtil.fdVal(fd);
|
this.fdVal = IOUtil.fdVal(fd);
|
||||||
|
|
||||||
if (bound) {
|
if (bound) {
|
||||||
synchronized (stateLock) {
|
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
|
// @throws ClosedChannelException if channel is closed
|
||||||
private void ensureOpen() throws ClosedChannelException {
|
private void ensureOpen() throws ClosedChannelException {
|
||||||
if (!isOpen())
|
if (!isOpen())
|
||||||
@ -150,8 +180,13 @@ class ServerSocketChannelImpl
|
|||||||
@Override
|
@Override
|
||||||
public ServerSocket socket() {
|
public ServerSocket socket() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
if (socket == null)
|
if (socket == null) {
|
||||||
socket = ServerSocketAdaptor.create(this);
|
if (isNetSocket()) {
|
||||||
|
socket = ServerSocketAdaptor.create(this);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,9 +195,11 @@ class ServerSocketChannelImpl
|
|||||||
public SocketAddress getLocalAddress() throws IOException {
|
public SocketAddress getLocalAddress() throws IOException {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
return (localAddress == null)
|
if (isUnixSocket()) {
|
||||||
? null
|
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
|
||||||
: Net.getRevealedLocalAddress(localAddress);
|
} else {
|
||||||
|
return Net.getRevealedLocalAddress(localAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +215,11 @@ class ServerSocketChannelImpl
|
|||||||
|
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
|
if (isNetSocket()
|
||||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
&& name == StandardSocketOptions.SO_REUSEADDR
|
||||||
|
&& Net.useExclusiveBind()) {
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
// SO_REUSEADDR emulated when using exclusive bind
|
||||||
isReuseAddress = (Boolean)value;
|
isReuseAddress = (Boolean) value;
|
||||||
} else {
|
} else {
|
||||||
// no options that require special handling
|
// no options that require special handling
|
||||||
Net.setSocketOption(fd, Net.UNSPEC, name, value);
|
Net.setSocketOption(fd, Net.UNSPEC, name, value);
|
||||||
@ -201,19 +239,23 @@ class ServerSocketChannelImpl
|
|||||||
|
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
if (isNetSocket()
|
||||||
|
&& name == StandardSocketOptions.SO_REUSEADDR
|
||||||
|
&& Net.useExclusiveBind()) {
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
// 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 {
|
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<>();
|
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
set.add(StandardSocketOptions.SO_REUSEADDR);
|
||||||
@ -223,11 +265,21 @@ class ServerSocketChannelImpl
|
|||||||
set.addAll(ExtendedSocketOptions.serverSocketOptions());
|
set.addAll(ExtendedSocketOptions.serverSocketOptions());
|
||||||
return Collections.unmodifiableSet(set);
|
return Collections.unmodifiableSet(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Set<SocketOption<?>> defaultUnixDomainOptions() {
|
||||||
|
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||||
|
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||||
|
return Collections.unmodifiableSet(set);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Set<SocketOption<?>> supportedOptions() {
|
public final Set<SocketOption<?>> supportedOptions() {
|
||||||
return DefaultOptionsHolder.defaultOptions;
|
if (isUnixSocket()) {
|
||||||
|
return DefaultOptionsHolder.defaultUnixDomainOptions;
|
||||||
|
} else {
|
||||||
|
return DefaultOptionsHolder.defaultInetOptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -236,23 +288,56 @@ class ServerSocketChannelImpl
|
|||||||
ensureOpen();
|
ensureOpen();
|
||||||
if (localAddress != null)
|
if (localAddress != null)
|
||||||
throw new AlreadyBoundException();
|
throw new AlreadyBoundException();
|
||||||
InetSocketAddress isa;
|
if (isUnixSocket()) {
|
||||||
if (local == null) {
|
localAddress = unixBind(local, backlog);
|
||||||
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
|
|
||||||
} else {
|
} 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;
|
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.
|
* Marks the beginning of an I/O operation that might block.
|
||||||
*
|
*
|
||||||
@ -295,18 +380,18 @@ class ServerSocketChannelImpl
|
|||||||
public SocketChannel accept() throws IOException {
|
public SocketChannel accept() throws IOException {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
FileDescriptor newfd = new FileDescriptor();
|
FileDescriptor newfd = new FileDescriptor();
|
||||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
SocketAddress[] saa = new SocketAddress[1];
|
||||||
|
|
||||||
acceptLock.lock();
|
acceptLock.lock();
|
||||||
try {
|
try {
|
||||||
boolean blocking = isBlocking();
|
boolean blocking = isBlocking();
|
||||||
try {
|
try {
|
||||||
begin(blocking);
|
begin(blocking);
|
||||||
n = Net.accept(this.fd, newfd, isaa);
|
n = implAccept(this.fd, newfd, saa);
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||||
park(Net.POLLIN);
|
park(Net.POLLIN);
|
||||||
n = Net.accept(this.fd, newfd, isaa);
|
n = implAccept(this.fd, newfd, saa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -318,12 +403,31 @@ class ServerSocketChannelImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
return finishAccept(newfd, isaa[0]);
|
return finishAccept(newfd, saa[0]);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
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
|
* Accepts a new connection with a given timeout. This method requires the
|
||||||
* channel to be configured in blocking mode.
|
* channel to be configured in blocking mode.
|
||||||
@ -337,7 +441,7 @@ class ServerSocketChannelImpl
|
|||||||
SocketChannel blockingAccept(long nanos) throws IOException {
|
SocketChannel blockingAccept(long nanos) throws IOException {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
FileDescriptor newfd = new FileDescriptor();
|
FileDescriptor newfd = new FileDescriptor();
|
||||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
SocketAddress[] saa = new SocketAddress[1];
|
||||||
|
|
||||||
acceptLock.lock();
|
acceptLock.lock();
|
||||||
try {
|
try {
|
||||||
@ -351,14 +455,14 @@ class ServerSocketChannelImpl
|
|||||||
lockedConfigureBlocking(false);
|
lockedConfigureBlocking(false);
|
||||||
try {
|
try {
|
||||||
long startNanos = System.nanoTime();
|
long startNanos = System.nanoTime();
|
||||||
n = Net.accept(fd, newfd, isaa);
|
n = implAccept(fd, newfd, saa);
|
||||||
while (n == IOStatus.UNAVAILABLE && isOpen()) {
|
while (n == IOStatus.UNAVAILABLE && isOpen()) {
|
||||||
long remainingNanos = nanos - (System.nanoTime() - startNanos);
|
long remainingNanos = nanos - (System.nanoTime() - startNanos);
|
||||||
if (remainingNanos <= 0) {
|
if (remainingNanos <= 0) {
|
||||||
throw new SocketTimeoutException("Accept timed out");
|
throw new SocketTimeoutException("Accept timed out");
|
||||||
}
|
}
|
||||||
park(Net.POLLIN, remainingNanos);
|
park(Net.POLLIN, remainingNanos);
|
||||||
n = Net.accept(fd, newfd, isaa);
|
n = implAccept(fd, newfd, saa);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// restore socket to blocking mode (if channel is open)
|
// restore socket to blocking mode (if channel is open)
|
||||||
@ -372,10 +476,10 @@ class ServerSocketChannelImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert n > 0;
|
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
|
throws IOException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -383,11 +487,14 @@ class ServerSocketChannelImpl
|
|||||||
IOUtil.configureBlocking(newfd, true);
|
IOUtil.configureBlocking(newfd, true);
|
||||||
|
|
||||||
// check permitted to accept connections from the remote address
|
// check permitted to accept connections from the remote address
|
||||||
SecurityManager sm = System.getSecurityManager();
|
if (isNetSocket()) {
|
||||||
if (sm != null) {
|
SecurityManager sm = System.getSecurityManager();
|
||||||
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
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) {
|
} catch (Exception e) {
|
||||||
nd.close(newfd);
|
nd.close(newfd);
|
||||||
throw e;
|
throw e;
|
||||||
@ -536,7 +643,7 @@ class ServerSocketChannelImpl
|
|||||||
/**
|
/**
|
||||||
* Returns the local address, or null if not bound
|
* Returns the local address, or null if not bound
|
||||||
*/
|
*/
|
||||||
InetSocketAddress localAddress() {
|
SocketAddress localAddress() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
return localAddress;
|
return localAddress;
|
||||||
}
|
}
|
||||||
@ -605,9 +712,11 @@ class ServerSocketChannelImpl
|
|||||||
sb.append("closed");
|
sb.append("closed");
|
||||||
} else {
|
} else {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
InetSocketAddress addr = localAddress;
|
SocketAddress addr = localAddress;
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
sb.append("unbound");
|
sb.append("unbound");
|
||||||
|
} else if (isUnixSocket()) {
|
||||||
|
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
|
||||||
} else {
|
} else {
|
||||||
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
@Override
|
||||||
public void connect(SocketAddress remote) throws IOException {
|
public void connect(SocketAddress remote) throws IOException {
|
||||||
connect(remote, 0);
|
connect(remote, 0);
|
||||||
@ -106,7 +114,7 @@ class SocketAdaptor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetAddress getInetAddress() {
|
public InetAddress getInetAddress() {
|
||||||
InetSocketAddress remote = sc.remoteAddress();
|
InetSocketAddress remote = remoteAddress();
|
||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@ -117,7 +125,7 @@ class SocketAdaptor
|
|||||||
@Override
|
@Override
|
||||||
public InetAddress getLocalAddress() {
|
public InetAddress getLocalAddress() {
|
||||||
if (sc.isOpen()) {
|
if (sc.isOpen()) {
|
||||||
InetSocketAddress local = sc.localAddress();
|
InetSocketAddress local = localAddress();
|
||||||
if (local != null) {
|
if (local != null) {
|
||||||
return Net.getRevealedLocalAddress(local).getAddress();
|
return Net.getRevealedLocalAddress(local).getAddress();
|
||||||
}
|
}
|
||||||
@ -127,7 +135,7 @@ class SocketAdaptor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
InetSocketAddress remote = sc.remoteAddress();
|
InetSocketAddress remote = remoteAddress();
|
||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -137,7 +145,7 @@ class SocketAdaptor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLocalPort() {
|
public int getLocalPort() {
|
||||||
InetSocketAddress local = sc.localAddress();
|
InetSocketAddress local = localAddress();
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
@ -152,12 +160,7 @@ class SocketAdaptor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SocketAddress getLocalSocketAddress() {
|
public SocketAddress getLocalSocketAddress() {
|
||||||
InetSocketAddress local = sc.localAddress();
|
return Net.getRevealedLocalAddress(sc.localAddress());
|
||||||
if (local != null) {
|
|
||||||
return Net.getRevealedLocalAddress(local);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -36,7 +36,6 @@ import java.net.SocketAddress;
|
|||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketOption;
|
import java.net.SocketOption;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.StandardProtocolFamily;
|
|
||||||
import java.net.StandardSocketOptions;
|
import java.net.StandardSocketOptions;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.AlreadyBoundException;
|
import java.nio.channels.AlreadyBoundException;
|
||||||
@ -50,11 +49,15 @@ import java.nio.channels.NotYetConnectedException;
|
|||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
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.ConnectionResetException;
|
||||||
import sun.net.NetHooks;
|
import sun.net.NetHooks;
|
||||||
@ -114,52 +117,35 @@ class SocketChannelImpl
|
|||||||
private long writerThread;
|
private long writerThread;
|
||||||
|
|
||||||
// Binding
|
// Binding
|
||||||
private InetSocketAddress localAddress;
|
private SocketAddress localAddress;
|
||||||
private InetSocketAddress remoteAddress;
|
private SocketAddress remoteAddress;
|
||||||
|
|
||||||
// Socket adaptor, created on demand
|
// Socket adaptor, created on demand
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
|
|
||||||
// -- End of fields protected by stateLock
|
// -- End of fields protected by stateLock
|
||||||
|
|
||||||
// Constructor for normal connecting sockets
|
|
||||||
//
|
|
||||||
SocketChannelImpl(SelectorProvider sp) throws IOException {
|
SocketChannelImpl(SelectorProvider sp) throws IOException {
|
||||||
this(sp, Net.isIPv6Available()
|
this(sp, Net.isIPv6Available() ? INET6 : INET);
|
||||||
? StandardProtocolFamily.INET6
|
|
||||||
: StandardProtocolFamily.INET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
|
SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
|
||||||
super(sp);
|
super(sp);
|
||||||
Objects.requireNonNull(family, "'family' is null");
|
Objects.requireNonNull(family, "'family' is null");
|
||||||
if ((family != StandardProtocolFamily.INET) &&
|
if ((family != INET) && (family != INET6) && (family != UNIX)) {
|
||||||
(family != StandardProtocolFamily.INET6)) {
|
|
||||||
throw new UnsupportedOperationException("Protocol family not supported");
|
throw new UnsupportedOperationException("Protocol family not supported");
|
||||||
}
|
}
|
||||||
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
|
if (family == INET6 && !Net.isIPv6Available()) {
|
||||||
throw new UnsupportedOperationException("IPv6 not available");
|
throw new UnsupportedOperationException("IPv6 not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.family = family;
|
this.family = family;
|
||||||
this.fd = Net.socket(family, true);
|
if (family == UNIX) {
|
||||||
this.fdVal = IOUtil.fdVal(fd);
|
this.fd = UnixDomainSockets.socket();
|
||||||
}
|
} else {
|
||||||
|
this.fd = Net.socket(family, true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
this.fdVal = IOUtil.fdVal(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor for sockets obtained from server sockets
|
// Constructor for sockets obtained from server sockets
|
||||||
@ -167,7 +153,7 @@ class SocketChannelImpl
|
|||||||
SocketChannelImpl(SelectorProvider sp,
|
SocketChannelImpl(SelectorProvider sp,
|
||||||
ProtocolFamily family,
|
ProtocolFamily family,
|
||||||
FileDescriptor fd,
|
FileDescriptor fd,
|
||||||
InetSocketAddress isa)
|
SocketAddress remoteAddress)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(sp);
|
super(sp);
|
||||||
@ -175,12 +161,30 @@ class SocketChannelImpl
|
|||||||
this.fd = fd;
|
this.fd = fd;
|
||||||
this.fdVal = IOUtil.fdVal(fd);
|
this.fdVal = IOUtil.fdVal(fd);
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
this.localAddress = Net.localAddress(fd);
|
if (family == UNIX) {
|
||||||
this.remoteAddress = isa;
|
this.localAddress = UnixDomainSockets.localAddress(fd);
|
||||||
|
} else {
|
||||||
|
this.localAddress = Net.localAddress(fd);
|
||||||
|
}
|
||||||
|
this.remoteAddress = remoteAddress;
|
||||||
this.state = ST_CONNECTED;
|
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.
|
* Checks that the channel is open.
|
||||||
*
|
*
|
||||||
@ -215,8 +219,13 @@ class SocketChannelImpl
|
|||||||
@Override
|
@Override
|
||||||
public Socket socket() {
|
public Socket socket() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
if (socket == null)
|
if (socket == null) {
|
||||||
socket = SocketAdaptor.create(this);
|
if (isNetSocket()) {
|
||||||
|
socket = SocketAdaptor.create(this);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +234,11 @@ class SocketChannelImpl
|
|||||||
public SocketAddress getLocalAddress() throws IOException {
|
public SocketAddress getLocalAddress() throws IOException {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
return Net.getRevealedLocalAddress(localAddress);
|
if (isUnixSocket()) {
|
||||||
|
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
|
||||||
|
} else {
|
||||||
|
return Net.getRevealedLocalAddress(localAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,15 +263,17 @@ class SocketChannelImpl
|
|||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
|
|
||||||
if (name == StandardSocketOptions.IP_TOS) {
|
if (isNetSocket()) {
|
||||||
Net.setSocketOption(fd, family, name, value);
|
if (name == StandardSocketOptions.IP_TOS) {
|
||||||
return this;
|
// 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
|
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||||
isReuseAddress = (Boolean)value;
|
// SO_REUSEADDR emulated when using exclusive bind
|
||||||
return this;
|
isReuseAddress = (Boolean) value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no options that require special handling
|
// no options that require special handling
|
||||||
@ -279,14 +294,15 @@ class SocketChannelImpl
|
|||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
|
|
||||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
if (isNetSocket()) {
|
||||||
// SO_REUSEADDR emulated when using exclusive bind
|
if (name == StandardSocketOptions.IP_TOS) {
|
||||||
return (T)Boolean.valueOf(isReuseAddress);
|
// special handling for IP_TOS
|
||||||
}
|
return (T) Net.getSocketOption(fd, family, name);
|
||||||
|
}
|
||||||
// special handling for IP_TOS
|
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||||
if (name == StandardSocketOptions.IP_TOS) {
|
// SO_REUSEADDR emulated when using exclusive bind
|
||||||
return (T) Net.getSocketOption(fd, family, name);
|
return (T) Boolean.valueOf(isReuseAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no options that require special handling
|
// no options that require special handling
|
||||||
@ -295,9 +311,10 @@ class SocketChannelImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class DefaultOptionsHolder {
|
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<>();
|
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
set.add(StandardSocketOptions.SO_SNDBUF);
|
||||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||||
@ -314,11 +331,24 @@ class SocketChannelImpl
|
|||||||
set.addAll(ExtendedSocketOptions.clientSocketOptions());
|
set.addAll(ExtendedSocketOptions.clientSocketOptions());
|
||||||
return Collections.unmodifiableSet(set);
|
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
|
@Override
|
||||||
public final Set<SocketOption<?>> supportedOptions() {
|
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
|
* Returns the local address, or null if not bound
|
||||||
*/
|
*/
|
||||||
InetSocketAddress localAddress() {
|
SocketAddress localAddress() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
return localAddress;
|
return localAddress;
|
||||||
}
|
}
|
||||||
@ -634,7 +664,7 @@ class SocketChannelImpl
|
|||||||
/**
|
/**
|
||||||
* Returns the remote address, or null if not connected
|
* Returns the remote address, or null if not connected
|
||||||
*/
|
*/
|
||||||
InetSocketAddress remoteAddress() {
|
SocketAddress remoteAddress() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
return remoteAddress;
|
return remoteAddress;
|
||||||
}
|
}
|
||||||
@ -652,19 +682,11 @@ class SocketChannelImpl
|
|||||||
throw new ConnectionPendingException();
|
throw new ConnectionPendingException();
|
||||||
if (localAddress != null)
|
if (localAddress != null)
|
||||||
throw new AlreadyBoundException();
|
throw new AlreadyBoundException();
|
||||||
InetSocketAddress isa;
|
if (isUnixSocket()) {
|
||||||
if (local == null) {
|
localAddress = unixBind(local);
|
||||||
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
|
|
||||||
} else {
|
} 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 {
|
} finally {
|
||||||
writeLock.unlock();
|
writeLock.unlock();
|
||||||
@ -675,6 +697,38 @@ class SocketChannelImpl
|
|||||||
return this;
|
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
|
@Override
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return (state == ST_CONNECTED);
|
return (state == ST_CONNECTED);
|
||||||
@ -694,7 +748,7 @@ class SocketChannelImpl
|
|||||||
* @throws ConnectionPendingException is a connection is pending
|
* @throws ConnectionPendingException is a connection is pending
|
||||||
* @throws IOException if the pre-connect hook fails
|
* @throws IOException if the pre-connect hook fails
|
||||||
*/
|
*/
|
||||||
private void beginConnect(boolean blocking, InetSocketAddress isa)
|
private void beginConnect(boolean blocking, SocketAddress sa)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
@ -711,9 +765,11 @@ class SocketChannelImpl
|
|||||||
assert state == ST_UNCONNECTED;
|
assert state == ST_UNCONNECTED;
|
||||||
this.state = ST_CONNECTIONPENDING;
|
this.state = ST_CONNECTIONPENDING;
|
||||||
|
|
||||||
if (localAddress == null)
|
if (isNetSocket() && (localAddress == null)) {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||||
NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
|
NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
|
||||||
remoteAddress = isa;
|
}
|
||||||
|
remoteAddress = sa;
|
||||||
|
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
// record thread so it can be signalled if needed
|
// record thread so it can be signalled if needed
|
||||||
@ -737,7 +793,11 @@ class SocketChannelImpl
|
|||||||
if (completed) {
|
if (completed) {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
if (state == ST_CONNECTIONPENDING) {
|
if (state == ST_CONNECTIONPENDING) {
|
||||||
localAddress = Net.localAddress(fd);
|
if (isUnixSocket()) {
|
||||||
|
localAddress = UnixDomainSockets.localAddress(fd);
|
||||||
|
} else {
|
||||||
|
localAddress = Net.localAddress(fd);
|
||||||
|
}
|
||||||
state = ST_CONNECTED;
|
state = ST_CONNECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -747,29 +807,34 @@ class SocketChannelImpl
|
|||||||
/**
|
/**
|
||||||
* Checks the remote address to which this channel is to be connected.
|
* Checks the remote address to which this channel is to be connected.
|
||||||
*/
|
*/
|
||||||
private InetSocketAddress checkRemote(SocketAddress sa) {
|
private SocketAddress checkRemote(SocketAddress sa) {
|
||||||
InetSocketAddress isa = Net.checkAddress(sa, family);
|
if (isUnixSocket()) {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
UnixDomainSockets.checkPermission();
|
||||||
if (sm != null) {
|
return UnixDomainSockets.checkAddress(sa);
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
} 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
|
@Override
|
||||||
public boolean connect(SocketAddress remote) throws IOException {
|
public boolean connect(SocketAddress remote) throws IOException {
|
||||||
InetSocketAddress isa = checkRemote(remote);
|
SocketAddress sa = checkRemote(remote);
|
||||||
try {
|
try {
|
||||||
readLock.lock();
|
readLock.lock();
|
||||||
try {
|
try {
|
||||||
@ -778,11 +843,13 @@ class SocketChannelImpl
|
|||||||
boolean blocking = isBlocking();
|
boolean blocking = isBlocking();
|
||||||
boolean connected = false;
|
boolean connected = false;
|
||||||
try {
|
try {
|
||||||
beginConnect(blocking, isa);
|
beginConnect(blocking, sa);
|
||||||
int n = Net.connect(family,
|
int n;
|
||||||
fd,
|
if (isUnixSocket()) {
|
||||||
isa.getAddress(),
|
n = UnixDomainSockets.connect(fd, sa);
|
||||||
isa.getPort());
|
} else {
|
||||||
|
n = Net.connect(family, fd, sa);
|
||||||
|
}
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
connected = true;
|
connected = true;
|
||||||
} else if (blocking) {
|
} else if (blocking) {
|
||||||
@ -807,7 +874,7 @@ class SocketChannelImpl
|
|||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// connect failed, close the channel
|
// connect failed, close the channel
|
||||||
close();
|
close();
|
||||||
throw SocketExceptions.of(ioe, isa);
|
throw SocketExceptions.of(ioe, sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +915,11 @@ class SocketChannelImpl
|
|||||||
if (completed) {
|
if (completed) {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
if (state == ST_CONNECTIONPENDING) {
|
if (state == ST_CONNECTIONPENDING) {
|
||||||
localAddress = Net.localAddress(fd);
|
if (isUnixSocket()) {
|
||||||
|
localAddress = UnixDomainSockets.localAddress(fd);
|
||||||
|
} else {
|
||||||
|
localAddress = Net.localAddress(fd);
|
||||||
|
}
|
||||||
state = ST_CONNECTED;
|
state = ST_CONNECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1087,7 +1158,7 @@ class SocketChannelImpl
|
|||||||
* @throws SocketTimeoutException if the read timeout elapses
|
* @throws SocketTimeoutException if the read timeout elapses
|
||||||
*/
|
*/
|
||||||
void blockingConnect(SocketAddress remote, long nanos) throws IOException {
|
void blockingConnect(SocketAddress remote, long nanos) throws IOException {
|
||||||
InetSocketAddress isa = checkRemote(remote);
|
SocketAddress sa = checkRemote(remote);
|
||||||
try {
|
try {
|
||||||
readLock.lock();
|
readLock.lock();
|
||||||
try {
|
try {
|
||||||
@ -1097,11 +1168,16 @@ class SocketChannelImpl
|
|||||||
throw new IllegalBlockingModeException();
|
throw new IllegalBlockingModeException();
|
||||||
boolean connected = false;
|
boolean connected = false;
|
||||||
try {
|
try {
|
||||||
beginConnect(true, isa);
|
beginConnect(true, sa);
|
||||||
// change socket to non-blocking
|
// change socket to non-blocking
|
||||||
lockedConfigureBlocking(false);
|
lockedConfigureBlocking(false);
|
||||||
try {
|
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);
|
connected = (n > 0) ? true : finishTimedConnect(nanos);
|
||||||
} finally {
|
} finally {
|
||||||
// restore socket to blocking mode (if channel is open)
|
// restore socket to blocking mode (if channel is open)
|
||||||
@ -1119,7 +1195,7 @@ class SocketChannelImpl
|
|||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// connect failed, close the channel
|
// connect failed, close the channel
|
||||||
close();
|
close();
|
||||||
throw SocketExceptions.of(ioe, isa);
|
throw SocketExceptions.of(ioe, sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1390,10 +1466,14 @@ class SocketChannelImpl
|
|||||||
sb.append(" oshut");
|
sb.append(" oshut");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
InetSocketAddress addr = localAddress();
|
SocketAddress addr = localAddress();
|
||||||
if (addr != null) {
|
if (addr != null) {
|
||||||
sb.append(" local=");
|
sb.append(" local=");
|
||||||
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
if (isUnixSocket()) {
|
||||||
|
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
|
||||||
|
} else {
|
||||||
|
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (remoteAddress() != null) {
|
if (remoteAddress() != null) {
|
||||||
sb.append(" remote=");
|
sb.append(" remote=");
|
||||||
|
176
src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java
Normal file
176
src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,13 @@ import java.net.InetAddress;
|
|||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ProtocolFamily;
|
import java.net.ProtocolFamily;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.channels.Channel;
|
import java.nio.channels.Channel;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
import static java.net.StandardProtocolFamily.INET6;
|
import static java.net.StandardProtocolFamily.INET6;
|
||||||
import static java.net.StandardProtocolFamily.INET;
|
import static java.net.StandardProtocolFamily.INET;
|
||||||
|
import static java.net.StandardProtocolFamily.UNIX;
|
||||||
|
|
||||||
class InheritedChannel {
|
class InheritedChannel {
|
||||||
|
|
||||||
@ -45,10 +48,10 @@ class InheritedChannel {
|
|||||||
private static final int SOCK_DGRAM = 2;
|
private static final int SOCK_DGRAM = 2;
|
||||||
|
|
||||||
// socket address type
|
// socket address type
|
||||||
private static final int AF_UNKNOWN = -1;
|
static final int AF_UNKNOWN = -1;
|
||||||
private static final int AF_INET = 1;
|
static final int AF_INET = 1;
|
||||||
private static final int AF_INET6 = 2;
|
static final int AF_INET6 = 2;
|
||||||
private static final int AF_UNIX = 3;
|
static final int AF_UNIX = 3;
|
||||||
|
|
||||||
// oflag values when opening a file
|
// oflag values when opening a file
|
||||||
private static final int O_RDONLY = 0;
|
private static final int O_RDONLY = 0;
|
||||||
@ -75,6 +78,24 @@ class InheritedChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ProtocolFamily protocolFamily(SocketAddress sa) {
|
||||||
|
if (sa instanceof UnixDomainSocketAddress) {
|
||||||
|
return UNIX;
|
||||||
|
} else {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||||
|
return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProtocolFamily protocolFamily(int family) {
|
||||||
|
return switch (family) {
|
||||||
|
case AF_INET -> INET;
|
||||||
|
case AF_INET6 -> INET6;
|
||||||
|
case AF_UNIX -> UNIX;
|
||||||
|
default -> throw new IllegalArgumentException();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Override the implCloseSelectableChannel for each channel type - this
|
* Override the implCloseSelectableChannel for each channel type - this
|
||||||
* allows us to "detach" the standard streams after closing and ensures
|
* allows us to "detach" the standard streams after closing and ensures
|
||||||
@ -82,16 +103,12 @@ class InheritedChannel {
|
|||||||
*/
|
*/
|
||||||
public static class InheritedSocketChannelImpl extends SocketChannelImpl {
|
public static class InheritedSocketChannelImpl extends SocketChannelImpl {
|
||||||
|
|
||||||
static ProtocolFamily family(InetSocketAddress isa) {
|
|
||||||
return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET;
|
|
||||||
}
|
|
||||||
|
|
||||||
InheritedSocketChannelImpl(SelectorProvider sp,
|
InheritedSocketChannelImpl(SelectorProvider sp,
|
||||||
FileDescriptor fd,
|
FileDescriptor fd,
|
||||||
InetSocketAddress remote)
|
SocketAddress remote)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(sp, family(remote), fd, remote);
|
super(sp, protocolFamily(remote), fd, remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void implCloseSelectableChannel() throws IOException {
|
protected void implCloseSelectableChannel() throws IOException {
|
||||||
@ -100,39 +117,24 @@ class InheritedChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl {
|
public static class InheritedServerSocketChannelImpl extends ServerSocketChannelImpl {
|
||||||
|
|
||||||
InheritedUnixChannelImpl(FileDescriptor fd)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
super(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void implCloseSelectableChannel() throws IOException {
|
|
||||||
super.implCloseChannel();
|
|
||||||
detachIOStreams();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InheritedServerSocketChannelImpl extends
|
|
||||||
ServerSocketChannelImpl {
|
|
||||||
|
|
||||||
InheritedServerSocketChannelImpl(SelectorProvider sp,
|
InheritedServerSocketChannelImpl(SelectorProvider sp,
|
||||||
|
ProtocolFamily family,
|
||||||
FileDescriptor fd)
|
FileDescriptor fd)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
super(sp, fd, true);
|
super(sp, family, fd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void implCloseSelectableChannel() throws IOException {
|
protected void implCloseSelectableChannel() throws IOException {
|
||||||
super.implCloseSelectableChannel();
|
super.implCloseSelectableChannel();
|
||||||
detachIOStreams();
|
detachIOStreams();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InheritedDatagramChannelImpl extends
|
public static class InheritedDatagramChannelImpl extends DatagramChannelImpl {
|
||||||
DatagramChannelImpl {
|
|
||||||
|
|
||||||
InheritedDatagramChannelImpl(SelectorProvider sp,
|
InheritedDatagramChannelImpl(SelectorProvider sp,
|
||||||
FileDescriptor fd)
|
FileDescriptor fd)
|
||||||
@ -151,16 +153,13 @@ class InheritedChannel {
|
|||||||
* If there's a SecurityManager then check for the appropriate
|
* If there's a SecurityManager then check for the appropriate
|
||||||
* RuntimePermission.
|
* RuntimePermission.
|
||||||
*/
|
*/
|
||||||
private static void checkAccess(Channel c) {
|
private static void checkAccess() {
|
||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
sm.checkPermission(
|
sm.checkPermission(new RuntimePermission("inheritedChannel"));
|
||||||
new RuntimePermission("inheritedChannel")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If standard inherited channel is connected to a socket then return a Channel
|
* If standard inherited channel is connected to a socket then return a Channel
|
||||||
* of the appropriate type based standard input.
|
* of the appropriate type based standard input.
|
||||||
@ -197,7 +196,7 @@ class InheritedChannel {
|
|||||||
|
|
||||||
|
|
||||||
// Now create the channel. If the socket is a streams socket then
|
// Now create the channel. If the socket is a streams socket then
|
||||||
// we see if tthere is a peer (ie: connected). If so, then we
|
// we see if there is a peer (ie: connected). If so, then we
|
||||||
// create a SocketChannel, otherwise a ServerSocketChannel.
|
// create a SocketChannel, otherwise a ServerSocketChannel.
|
||||||
// If the socket is a datagram socket then create a DatagramChannel
|
// If the socket is a datagram socket then create a DatagramChannel
|
||||||
|
|
||||||
@ -209,19 +208,21 @@ class InheritedChannel {
|
|||||||
int family = addressFamily(fdVal);
|
int family = addressFamily(fdVal);
|
||||||
if (family == AF_UNKNOWN)
|
if (family == AF_UNKNOWN)
|
||||||
return null;
|
return null;
|
||||||
|
ProtocolFamily pfamily = protocolFamily(family);
|
||||||
if (family == AF_UNIX) {
|
if (family == AF_UNIX) {
|
||||||
if (isConnected(fdVal)) {
|
if (isConnected(fdVal)) {
|
||||||
return new InheritedUnixChannelImpl(fd);
|
var sa = UnixDomainSocketAddress.of(unixPeerAddress(fdVal));
|
||||||
|
return new InheritedSocketChannelImpl(provider, fd, sa);
|
||||||
} else {
|
} else {
|
||||||
// listener. unsupported.
|
return new InheritedServerSocketChannelImpl(provider, pfamily, fd);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InetAddress ia = peerAddress0(fdVal);
|
InetAddress ia = inetPeerAddress0(fdVal);
|
||||||
if (ia == null) {
|
if (ia == null) {
|
||||||
c = new InheritedServerSocketChannelImpl(provider, fd);
|
c = new InheritedServerSocketChannelImpl(provider, pfamily, fd);
|
||||||
} else {
|
} else {
|
||||||
int port = peerPort0(fdVal);
|
int port = peerPort0(fdVal);
|
||||||
|
|
||||||
assert port > 0;
|
assert port > 0;
|
||||||
InetSocketAddress isa = new InetSocketAddress(ia, port);
|
InetSocketAddress isa = new InetSocketAddress(ia, port);
|
||||||
c = new InheritedSocketChannelImpl(provider, fd, isa);
|
c = new InheritedSocketChannelImpl(provider, fd, isa);
|
||||||
@ -253,11 +254,15 @@ class InheritedChannel {
|
|||||||
// if there is a channel then do the security check before
|
// if there is a channel then do the security check before
|
||||||
// returning it.
|
// returning it.
|
||||||
if (channel != null) {
|
if (channel != null) {
|
||||||
checkAccess(channel);
|
checkAccess();
|
||||||
}
|
}
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String unixPeerAddress(int fd) throws IOException {
|
||||||
|
byte[] bytes = unixPeerAddress0(fd);
|
||||||
|
return new String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
// -- Native methods --
|
// -- Native methods --
|
||||||
|
|
||||||
@ -268,7 +273,8 @@ class InheritedChannel {
|
|||||||
private static native void close0(int fd) throws IOException;
|
private static native void close0(int fd) throws IOException;
|
||||||
private static native int soType0(int fd);
|
private static native int soType0(int fd);
|
||||||
private static native int addressFamily(int fd);
|
private static native int addressFamily(int fd);
|
||||||
private static native InetAddress peerAddress0(int fd);
|
private static native InetAddress inetPeerAddress0(int fd);
|
||||||
|
private static native byte[] unixPeerAddress0(int fd);
|
||||||
private static native int peerPort0(int fd);
|
private static native int peerPort0(int fd);
|
||||||
|
|
||||||
// return true if socket is connected to a peer
|
// return true if socket is connected to a peer
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,39 +25,41 @@
|
|||||||
|
|
||||||
package sun.nio.ch;
|
package sun.nio.ch;
|
||||||
|
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.channels.ServerSocketChannel;
|
import java.security.AccessController;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.security.PrivilegedAction;
|
||||||
import java.io.FileDescriptor;
|
import sun.net.NetProperties;
|
||||||
import java.io.IOException;
|
import jdk.internal.util.StaticProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to implementation private constructors and methods.
|
* Platform specific utility functions
|
||||||
*/
|
*/
|
||||||
|
class UnixDomainSocketsUtil {
|
||||||
|
private UnixDomainSocketsUtil() { }
|
||||||
|
|
||||||
public final class Secrets {
|
static Charset getCharset() {
|
||||||
private Secrets() { }
|
return Charset.defaultCharset();
|
||||||
|
|
||||||
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 the temp directory for storing automatically bound
|
||||||
return new SocketChannelImpl(provider(), fd, false);
|
* server sockets.
|
||||||
} catch (IOException ioe) {
|
*
|
||||||
throw new AssertionError(ioe);
|
* On UNIX we search the following directories in sequence:
|
||||||
}
|
*
|
||||||
}
|
* 1. ${jdk.net.unixdomain.tmpdir} if set as system property
|
||||||
|
* 2. ${jdk.net.unixdomain.tmpdir} if set as net property
|
||||||
public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
|
* 3. ${java.io.tmpdir} system property
|
||||||
try {
|
*/
|
||||||
return new ServerSocketChannelImpl(provider(), fd, false);
|
static String getTempDir() {
|
||||||
} catch (IOException ioe) {
|
PrivilegedAction<String> action = () -> {
|
||||||
throw new AssertionError(ioe);
|
String s = NetProperties.get("jdk.net.unixdomain.tmpdir");
|
||||||
}
|
if (s != null && s.length() > 0) {
|
||||||
|
return s;
|
||||||
|
} else {
|
||||||
|
return StaticProperty.javaIoTmpDir();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return AccessController.doPrivileged(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -557,4 +557,10 @@ public abstract class UnixFileSystemProvider
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getSunPathForSocketFile(Path obj) {
|
||||||
|
UnixPath file = UnixPath.toUnixPath(obj);
|
||||||
|
return file.getByteArrayForSysCalls();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,7 +33,7 @@ import static sun.nio.fs.UnixNativeDispatcher.*;
|
|||||||
* Unix implementation of java.nio.file.attribute.UserPrincipal
|
* Unix implementation of java.nio.file.attribute.UserPrincipal
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class UnixUserPrincipals {
|
public class UnixUserPrincipals {
|
||||||
private static User createSpecial(String name) { return new User(-1, name); }
|
private static User createSpecial(String name) { return new User(-1, name); }
|
||||||
|
|
||||||
static final User SPECIAL_OWNER = createSpecial("OWNER@");
|
static final User SPECIAL_OWNER = createSpecial("OWNER@");
|
||||||
@ -108,7 +108,7 @@ class UnixUserPrincipals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return UserPrincipal representing given uid
|
// return UserPrincipal representing given uid
|
||||||
static User fromUid(int uid) {
|
public static User fromUid(int uid) {
|
||||||
String name;
|
String name;
|
||||||
try {
|
try {
|
||||||
name = Util.toString(getpwuid(uid));
|
name = Util.toString(getpwuid(uid));
|
||||||
@ -119,7 +119,7 @@ class UnixUserPrincipals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return GroupPrincipal representing given gid
|
// return GroupPrincipal representing given gid
|
||||||
static Group fromGid(int gid) {
|
public static Group fromGid(int gid) {
|
||||||
String name;
|
String name;
|
||||||
try {
|
try {
|
||||||
name = Util.toString(getgrgid(gid));
|
name = Util.toString(getgrgid(gid));
|
||||||
|
15
src/java.base/unix/conf/net.properties
Normal file
15
src/java.base/unix/conf/net.properties
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#
|
||||||
|
# Default directory where automatically bound Unix domain server
|
||||||
|
# sockets are stored. Sockets are automatically bound when bound
|
||||||
|
# with a null address.
|
||||||
|
#
|
||||||
|
# On Unix the search order to determine this directory is:
|
||||||
|
#
|
||||||
|
# 1. System property jdk.net.unixdomain.tmpdir
|
||||||
|
#
|
||||||
|
# 2. Networking property jdk.net.unixdomain.tmpdir specified
|
||||||
|
# in this file (effective default)
|
||||||
|
#
|
||||||
|
# 3. System property java.io.tmpdir
|
||||||
|
#
|
||||||
|
jdk.net.unixdomain.tmpdir=/tmp
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -34,10 +34,11 @@
|
|||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
#include "jni_util.h"
|
#include "jni_util.h"
|
||||||
#include "net_util.h"
|
#include "net_util.h"
|
||||||
|
#include "nio_util.h"
|
||||||
|
|
||||||
#include "sun_nio_ch_InheritedChannel.h"
|
#include "sun_nio_ch_InheritedChannel.h"
|
||||||
|
|
||||||
static int matchFamily(SOCKETADDRESS *sa) {
|
static int toInetFamily(SOCKETADDRESS *sa) {
|
||||||
return (sa->sa.sa_family == (ipv6_available() ? AF_INET6 : AF_INET));
|
return (sa->sa.sa_family == (ipv6_available() ? AF_INET6 : AF_INET));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +50,7 @@ Java_sun_nio_ch_InheritedChannel_initIDs(JNIEnv *env, jclass cla)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jobject JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
|
Java_sun_nio_ch_InheritedChannel_inetPeerAddress0(JNIEnv *env, jclass cla, jint fd)
|
||||||
{
|
{
|
||||||
SOCKETADDRESS sa;
|
SOCKETADDRESS sa;
|
||||||
socklen_t len = sizeof(SOCKETADDRESS);
|
socklen_t len = sizeof(SOCKETADDRESS);
|
||||||
@ -57,7 +58,7 @@ Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
|
|||||||
jint remote_port;
|
jint remote_port;
|
||||||
|
|
||||||
if (getpeername(fd, &sa.sa, &len) == 0) {
|
if (getpeername(fd, &sa.sa, &len) == 0) {
|
||||||
if (matchFamily(&sa)) {
|
if (toInetFamily(&sa)) {
|
||||||
remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
|
remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,6 +66,21 @@ Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
|
|||||||
return remote_ia;
|
return remote_ia;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jbyteArray JNICALL
|
||||||
|
Java_sun_nio_ch_InheritedChannel_unixPeerAddress0(JNIEnv *env, jclass cla, jint fd)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
socklen_t len = sizeof(struct sockaddr_un);
|
||||||
|
jobject remote_sa = NULL;
|
||||||
|
|
||||||
|
if (getpeername(fd, (struct sockaddr *)&sa, &len) == 0) {
|
||||||
|
if (sa.sun_family == AF_UNIX) {
|
||||||
|
remote_sa = sockaddrToUnixAddressBytes(env, &sa, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return remote_sa;
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd)
|
Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd)
|
||||||
{
|
{
|
||||||
@ -72,8 +88,8 @@ Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd)
|
|||||||
socklen_t len = sizeof(SOCKETADDRESS);
|
socklen_t len = sizeof(SOCKETADDRESS);
|
||||||
jint remote_port = -1;
|
jint remote_port = -1;
|
||||||
|
|
||||||
if (getpeername(fd, &sa.sa, &len) == 0) {
|
if (getpeername(fd, (struct sockaddr *)&sa.sa, &len) == 0) {
|
||||||
if (matchFamily(&sa)) {
|
if (toInetFamily(&sa)) {
|
||||||
NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
|
NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
194
src/java.base/unix/native/libnio/ch/UnixDomainSockets.c
Normal file
194
src/java.base/unix/native/libnio/ch/UnixDomainSockets.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "jni.h"
|
||||||
|
#include "java_props.h"
|
||||||
|
#include "jni_util.h"
|
||||||
|
#include "jvm.h"
|
||||||
|
#include "jlong.h"
|
||||||
|
#include "sun_nio_ch_Net.h"
|
||||||
|
#include "nio_util.h"
|
||||||
|
#include "nio.h"
|
||||||
|
|
||||||
|
/* Subtle platform differences in how unnamed sockets (empty path)
|
||||||
|
* are returned from getsockname()
|
||||||
|
*/
|
||||||
|
#ifdef MACOSX
|
||||||
|
#define ZERO_PATHLEN(len) (JNI_FALSE)
|
||||||
|
#else
|
||||||
|
#define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)
|
||||||
|
{
|
||||||
|
if (sa->sun_family == AF_UNIX) {
|
||||||
|
int namelen;
|
||||||
|
if (ZERO_PATHLEN(len)) {
|
||||||
|
namelen = 0;
|
||||||
|
} else {
|
||||||
|
namelen = strlen(sa->sun_path);
|
||||||
|
}
|
||||||
|
jbyteArray name = (*env)->NewByteArray(env, namelen);
|
||||||
|
if (namelen != 0) {
|
||||||
|
(*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);
|
||||||
|
if ((*env)->ExceptionOccurred(env)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray path, struct sockaddr_un *sa, int *len)
|
||||||
|
{
|
||||||
|
memset(sa, 0, sizeof(struct sockaddr_un));
|
||||||
|
sa->sun_family = AF_UNIX;
|
||||||
|
int ret;
|
||||||
|
const char* pname = (const char *)(*env)->GetByteArrayElements(env, path, NULL);
|
||||||
|
if (pname == NULL) {
|
||||||
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t name_len = (*env)->GetArrayLength(env, path);
|
||||||
|
if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
|
||||||
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
|
memcpy(sa->sun_path, pname, name_len);
|
||||||
|
*len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len + 1);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
(*env)->ReleaseByteArrayElements(env, path, (jbyte *)pname, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_socketSupported(JNIEnv *env, jclass cl)
|
||||||
|
{
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)
|
||||||
|
{
|
||||||
|
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
return handleSocketError(env, errno);
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int sa_len = 0;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
||||||
|
if (rv != 0) {
|
||||||
|
handleSocketError(env, errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int sa_len = 0;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) {
|
||||||
|
return IOS_THROWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
||||||
|
if (rv != 0) {
|
||||||
|
if (errno == EINPROGRESS) {
|
||||||
|
return IOS_UNAVAILABLE;
|
||||||
|
} else if (errno == EINTR) {
|
||||||
|
return IOS_INTERRUPTED;
|
||||||
|
}
|
||||||
|
return handleSocketError(env, errno);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
|
||||||
|
jobjectArray array)
|
||||||
|
{
|
||||||
|
jint fd = fdval(env, fdo);
|
||||||
|
jint newfd;
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
socklen_t sa_len = sizeof(struct sockaddr_un);
|
||||||
|
jbyteArray address;
|
||||||
|
|
||||||
|
newfd = accept(fd, (struct sockaddr *)&sa, &sa_len);
|
||||||
|
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);
|
||||||
|
|
||||||
|
address = sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
||||||
|
CHECK_NULL_RETURN(address, IOS_THROWN);
|
||||||
|
|
||||||
|
(*env)->SetObjectArrayElement(env, array, 0, address);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jbyteArray JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
socklen_t sa_len = sizeof(struct sockaddr_un);
|
||||||
|
int port;
|
||||||
|
if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
|
||||||
|
handleSocketError(env, errno);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@
|
|||||||
#include "jlong.h"
|
#include "jlong.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
#define RESTARTABLE(_cmd, _result) do { \
|
#define RESTARTABLE(_cmd, _result) do { \
|
||||||
do { \
|
do { \
|
||||||
@ -47,6 +48,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
|
||||||
/* NIO utility procedures */
|
/* NIO utility procedures */
|
||||||
|
|
||||||
|
|
||||||
@ -62,3 +69,15 @@ jlong convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading);
|
|||||||
/* Defined in Net.c */
|
/* Defined in Net.c */
|
||||||
|
|
||||||
jint handleSocketError(JNIEnv *env, jint errorValue);
|
jint handleSocketError(JNIEnv *env, jint errorValue);
|
||||||
|
|
||||||
|
/* Defined in UnixDomainSockets.c */
|
||||||
|
|
||||||
|
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env,
|
||||||
|
struct sockaddr_un *sa,
|
||||||
|
socklen_t len);
|
||||||
|
|
||||||
|
jint unixSocketAddressToSockaddr(JNIEnv *env,
|
||||||
|
jbyteArray uaddr,
|
||||||
|
struct sockaddr_un *sa,
|
||||||
|
int *len);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,8 +31,14 @@ package sun.nio.ch;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
|
import java.net.StandardSocketOptions;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.nio.channels.spi.*;
|
import java.nio.channels.spi.*;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
@ -55,16 +61,17 @@ class PipeImpl
|
|||||||
private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom();
|
private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom();
|
||||||
|
|
||||||
// Source and sink channels
|
// Source and sink channels
|
||||||
private SourceChannel source;
|
private final SourceChannel source;
|
||||||
private SinkChannel sink;
|
private final SinkChannel sink;
|
||||||
|
|
||||||
private class Initializer
|
private class Initializer
|
||||||
implements PrivilegedExceptionAction<Void>
|
implements PrivilegedExceptionAction<Void>
|
||||||
{
|
{
|
||||||
|
|
||||||
private final SelectorProvider sp;
|
private final SelectorProvider sp;
|
||||||
|
private IOException ioe;
|
||||||
private IOException ioe = null;
|
SourceChannelImpl source;
|
||||||
|
SinkChannelImpl sink;
|
||||||
|
|
||||||
private Initializer(SelectorProvider sp) {
|
private Initializer(SelectorProvider sp) {
|
||||||
this.sp = sp;
|
this.sp = sp;
|
||||||
@ -103,23 +110,20 @@ class PipeImpl
|
|||||||
ServerSocketChannel ssc = null;
|
ServerSocketChannel ssc = null;
|
||||||
SocketChannel sc1 = null;
|
SocketChannel sc1 = null;
|
||||||
SocketChannel sc2 = null;
|
SocketChannel sc2 = null;
|
||||||
|
// Loopback address
|
||||||
|
SocketAddress sa = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create secret with a backing array.
|
// Create secret with a backing array.
|
||||||
ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES);
|
ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES);
|
||||||
ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);
|
ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);
|
||||||
|
|
||||||
// Loopback address
|
|
||||||
InetAddress lb = InetAddress.getLoopbackAddress();
|
|
||||||
assert(lb.isLoopbackAddress());
|
|
||||||
InetSocketAddress sa = null;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Bind ServerSocketChannel to a port on the loopback
|
// Bind ServerSocketChannel to a port on the loopback
|
||||||
// address
|
// address
|
||||||
if (ssc == null || !ssc.isOpen()) {
|
if (ssc == null || !ssc.isOpen()) {
|
||||||
ssc = ServerSocketChannel.open();
|
ssc = createListener();
|
||||||
ssc.socket().bind(new InetSocketAddress(lb, 0));
|
sa = ssc.getLocalAddress();
|
||||||
sa = new InetSocketAddress(lb, ssc.socket().getLocalPort());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establish connection (assume connections are eagerly
|
// Establish connection (assume connections are eagerly
|
||||||
@ -160,18 +164,43 @@ class PipeImpl
|
|||||||
try {
|
try {
|
||||||
if (ssc != null)
|
if (ssc != null)
|
||||||
ssc.close();
|
ssc.close();
|
||||||
|
if (sa instanceof UnixDomainSocketAddress) {
|
||||||
|
Path path = ((UnixDomainSocketAddress) sa).getPath();
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
}
|
||||||
} catch (IOException e2) {}
|
} catch (IOException e2) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PipeImpl(final SelectorProvider sp) throws IOException {
|
/**
|
||||||
|
* Creates a Pipe implementation that supports buffering.
|
||||||
|
*/
|
||||||
|
PipeImpl(SelectorProvider sp) throws IOException {
|
||||||
|
this(sp, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates Pipe implementation that supports optionally buffering.
|
||||||
|
*
|
||||||
|
* @implNote The pipe uses Unix domain sockets where possible. It uses a
|
||||||
|
* loopback connection on older editions of Windows. When buffering is
|
||||||
|
* disabled then it sets TCP_NODELAY on the sink channel.
|
||||||
|
*/
|
||||||
|
PipeImpl(SelectorProvider sp, boolean buffering) throws IOException {
|
||||||
|
Initializer initializer = new Initializer(sp);
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new Initializer(sp));
|
AccessController.doPrivileged(initializer);
|
||||||
} catch (PrivilegedActionException x) {
|
SinkChannelImpl sink = initializer.sink;
|
||||||
throw (IOException)x.getCause();
|
if (sink.isNetSocket() && !buffering) {
|
||||||
|
sink.setOption(StandardSocketOptions.TCP_NODELAY, true);
|
||||||
|
}
|
||||||
|
} catch (PrivilegedActionException pae) {
|
||||||
|
throw (IOException) pae.getCause();
|
||||||
}
|
}
|
||||||
|
this.source = initializer.source;
|
||||||
|
this.sink = initializer.sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceChannel source() {
|
public SourceChannel source() {
|
||||||
@ -182,4 +211,25 @@ class PipeImpl
|
|||||||
return sink;
|
return sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static volatile boolean noUnixDomainSockets;
|
||||||
|
|
||||||
|
private static ServerSocketChannel createListener() throws IOException {
|
||||||
|
ServerSocketChannel listener = null;
|
||||||
|
if (!noUnixDomainSockets) {
|
||||||
|
try {
|
||||||
|
listener = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
return listener.bind(null);
|
||||||
|
} catch (UnsupportedOperationException | IOException e) {
|
||||||
|
// IOException is most likely to be caused by the temporary directory
|
||||||
|
// name being too long. Possibly should log this.
|
||||||
|
noUnixDomainSockets = true;
|
||||||
|
if (listener != null)
|
||||||
|
listener.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listener = ServerSocketChannel.open();
|
||||||
|
InetAddress lb = InetAddress.getLoopbackAddress();
|
||||||
|
listener.bind(new InetSocketAddress(lb, 0));
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,6 +30,7 @@ package sun.nio.ch;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.net.SocketOption;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.nio.channels.spi.*;
|
import java.nio.channels.spi.*;
|
||||||
@ -44,19 +45,27 @@ class SinkChannelImpl
|
|||||||
implements SelChImpl
|
implements SelChImpl
|
||||||
{
|
{
|
||||||
// The SocketChannel assoicated with this pipe
|
// The SocketChannel assoicated with this pipe
|
||||||
final SocketChannel sc;
|
private final SocketChannelImpl sc;
|
||||||
|
|
||||||
public FileDescriptor getFD() {
|
public FileDescriptor getFD() {
|
||||||
return ((SocketChannelImpl)sc).getFD();
|
return sc.getFD();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFDVal() {
|
public int getFDVal() {
|
||||||
return ((SocketChannelImpl)sc).getFDVal();
|
return sc.getFDVal();
|
||||||
}
|
}
|
||||||
|
|
||||||
SinkChannelImpl(SelectorProvider sp, SocketChannel sc) {
|
SinkChannelImpl(SelectorProvider sp, SocketChannel sc) {
|
||||||
super(sp);
|
super(sp);
|
||||||
this.sc = sc;
|
this.sc = (SocketChannelImpl) sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isNetSocket() {
|
||||||
|
return sc.isNetSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
<T> void setOption(SocketOption<T> name, T value) throws IOException {
|
||||||
|
sc.setOption(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void implCloseSelectableChannel() throws IOException {
|
protected void implCloseSelectableChannel() throws IOException {
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.nio.ch;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import sun.net.NetProperties;
|
||||||
|
import jdk.internal.util.StaticProperty;
|
||||||
|
|
||||||
|
class UnixDomainSocketsUtil {
|
||||||
|
private UnixDomainSocketsUtil() { }
|
||||||
|
|
||||||
|
static Charset getCharset() {
|
||||||
|
return StandardCharsets.UTF_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the temp directory for storing automatically bound
|
||||||
|
* server sockets.
|
||||||
|
*
|
||||||
|
* On Windows we search the following directories in sequence:
|
||||||
|
*
|
||||||
|
* 1. ${jdk.net.unixdomain.tmpdir} if set as system property
|
||||||
|
* 2. ${jdk.net.unixdomain.tmpdir} if set as net property
|
||||||
|
* 3. %TEMP%
|
||||||
|
* 4. ${java.io.tmpdir}
|
||||||
|
*/
|
||||||
|
static String getTempDir() {
|
||||||
|
PrivilegedAction<String> action = () -> {
|
||||||
|
String s = NetProperties.get("jdk.net.unixdomain.tmpdir");
|
||||||
|
if (s != null) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
String temp = System.getenv("TEMP");
|
||||||
|
if (temp != null) {
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
return StaticProperty.javaIoTmpDir();
|
||||||
|
};
|
||||||
|
return AccessController.doPrivileged(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,6 +30,7 @@ import java.nio.channels.ClosedSelectorException;
|
|||||||
import java.nio.channels.Pipe;
|
import java.nio.channels.Pipe;
|
||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.Selector;
|
import java.nio.channels.Selector;
|
||||||
|
import java.nio.channels.SelectableChannel;
|
||||||
import java.nio.channels.spi.SelectorProvider;
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -139,14 +140,9 @@ class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
WindowsSelectorImpl(SelectorProvider sp) throws IOException {
|
WindowsSelectorImpl(SelectorProvider sp) throws IOException {
|
||||||
super(sp);
|
super(sp);
|
||||||
pollWrapper = new PollArrayWrapper(INIT_CAP);
|
pollWrapper = new PollArrayWrapper(INIT_CAP);
|
||||||
wakeupPipe = Pipe.open();
|
wakeupPipe = new PipeImpl(sp, false);
|
||||||
wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();
|
wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal();
|
||||||
|
wakeupSinkFd = ((SelChImpl)wakeupPipe.sink()).getFDVal();
|
||||||
// Disable the Nagle algorithm so that the wakeup is more immediate
|
|
||||||
SinkChannelImpl sink = (SinkChannelImpl)wakeupPipe.sink();
|
|
||||||
(sink.sc).socket().setTcpNoDelay(true);
|
|
||||||
wakeupSinkFd = ((SelChImpl)sink).getFDVal();
|
|
||||||
|
|
||||||
pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
|
pollWrapper.addWakeupSocket(wakeupSourceFd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,19 +409,19 @@ class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
// processDeregisterQueue.
|
// processDeregisterQueue.
|
||||||
if (me == null)
|
if (me == null)
|
||||||
continue;
|
continue;
|
||||||
SelectionKeyImpl sk = me.ski;
|
SelectionKeyImpl ski = me.ski;
|
||||||
|
|
||||||
// The descriptor may be in the exceptfds set because there is
|
// The descriptor may be in the exceptfds set because there is
|
||||||
// OOB data queued to the socket. If there is OOB data then it
|
// 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.
|
// is discarded and the key is not added to the selected set.
|
||||||
if (isExceptFds &&
|
SelectableChannel sc = ski.channel();
|
||||||
(sk.channel() instanceof SocketChannelImpl) &&
|
if (isExceptFds && (sc instanceof SocketChannelImpl)
|
||||||
discardUrgentData(desc))
|
&& ((SocketChannelImpl) sc).isNetSocket()
|
||||||
{
|
&& discardUrgentData(desc)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int updated = processReadyEvents(rOps, sk, action);
|
int updated = processReadyEvents(rOps, ski, action);
|
||||||
if (updated > 0 && me.updateCount != updateCount) {
|
if (updated > 0 && me.updateCount != updateCount) {
|
||||||
me.updateCount = updateCount;
|
me.updateCount = updateCount;
|
||||||
numKeysUpdated++;
|
numKeysUpdated++;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -28,6 +28,7 @@ package sun.nio.fs;
|
|||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.*;
|
import java.nio.file.attribute.*;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -622,4 +623,12 @@ class WindowsFileSystemProvider
|
|||||||
String target = WindowsLinkSupport.readLink(link);
|
String target = WindowsLinkSupport.readLink(link);
|
||||||
return WindowsPath.createFromNormalizedPath(fs, target);
|
return WindowsPath.createFromNormalizedPath(fs, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getSunPathForSocketFile(Path obj) {
|
||||||
|
WindowsPath file = WindowsPath.toWindowsPath(obj);
|
||||||
|
String s = file.toString();
|
||||||
|
return s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
19
src/java.base/windows/conf/net.properties
Normal file
19
src/java.base/windows/conf/net.properties
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#
|
||||||
|
# Default directory where automatically bound Unix domain server
|
||||||
|
# sockets are stored. Sockets are automatically bound when bound
|
||||||
|
# with a null address.
|
||||||
|
#
|
||||||
|
# The search order for the directory on Windows is:
|
||||||
|
#
|
||||||
|
# 1. System property "jdk.net.unixdomain.tmpdir"
|
||||||
|
#
|
||||||
|
# 2. Networking property "jdk.net.unixdomain.tmpdir" specified
|
||||||
|
# in this file (not set by default)
|
||||||
|
#
|
||||||
|
# 3. The TEMP environment variable (the effective default)
|
||||||
|
#
|
||||||
|
# 4. The java.io.tmpdir system property
|
||||||
|
#
|
||||||
|
#jdk.net.unixdomain.tmpdir=
|
||||||
|
#
|
||||||
|
|
196
src/java.base/windows/native/libnio/ch/UnixDomainSockets.c
Normal file
196
src/java.base/windows/native/libnio/ch/UnixDomainSockets.c
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#include "jni.h"
|
||||||
|
#include "jni_util.h"
|
||||||
|
#include "jvm.h"
|
||||||
|
#include "jlong.h"
|
||||||
|
#include "nio.h"
|
||||||
|
#include "nio_util.h"
|
||||||
|
#include "net_util.h"
|
||||||
|
|
||||||
|
#include "java_net_InetAddress.h"
|
||||||
|
#include "sun_nio_ch_Net.h"
|
||||||
|
#include "sun_nio_ch_PollArrayWrapper.h"
|
||||||
|
|
||||||
|
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)
|
||||||
|
{
|
||||||
|
if (sa->sun_family == AF_UNIX) {
|
||||||
|
int namelen = (int)strlen(sa->sun_path);
|
||||||
|
jbyteArray name = (*env)->NewByteArray(env, namelen);
|
||||||
|
if (name != NULL) {
|
||||||
|
(*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);
|
||||||
|
if ((*env)->ExceptionOccurred(env)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray addr, struct sockaddr_un *sa, int *len)
|
||||||
|
{
|
||||||
|
memset(sa, 0, sizeof(struct sockaddr_un));
|
||||||
|
sa->sun_family = AF_UNIX;
|
||||||
|
if (addr == 0L) {
|
||||||
|
/* Do explicit bind on Windows */
|
||||||
|
*len = (int)(offsetof(struct sockaddr_un, sun_path));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int ret;
|
||||||
|
jboolean isCopy;
|
||||||
|
char *pname = (*env)->GetByteArrayElements(env, addr, &isCopy);
|
||||||
|
if (pname == NULL) {
|
||||||
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t name_len = (size_t)(*env)->GetArrayLength(env, addr);
|
||||||
|
if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
|
||||||
|
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
|
strncpy(sa->sun_path, pname, name_len);
|
||||||
|
*len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
(*env)->ReleaseByteArrayElements(env, addr, pname, JNI_ABORT);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_socketSupported(JNIEnv *env, jclass cl)
|
||||||
|
{
|
||||||
|
SOCKET s = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (s == INVALID_SOCKET) {
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
closesocket(s);
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)
|
||||||
|
{
|
||||||
|
SOCKET s = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (s == INVALID_SOCKET) {
|
||||||
|
return handleSocketError(env, WSAGetLastError());
|
||||||
|
}
|
||||||
|
SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
return (int)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Windows does not support auto bind. So, the windows version of unixSocketAddressToSockaddr
|
||||||
|
* looks out for a null 'uaddr' and handles it specially
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int sa_len = 0;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
||||||
|
if (rv == SOCKET_ERROR) {
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
NET_ThrowNew(env, err, "bind");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int sa_len = 0;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0) {
|
||||||
|
return IOS_THROWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = connect(fdval(env, fdo), (const struct sockaddr *)&sa, sa_len);
|
||||||
|
if (rv != 0) {
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {
|
||||||
|
return IOS_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
NET_ThrowNew(env, err, "connect");
|
||||||
|
return IOS_THROWN;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
|
||||||
|
jobjectArray array)
|
||||||
|
{
|
||||||
|
jint fd = fdval(env, fdo);
|
||||||
|
jint newfd;
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
socklen_t sa_len = sizeof(sa);
|
||||||
|
jbyteArray address;
|
||||||
|
|
||||||
|
memset((char *)&sa, 0, sizeof(sa));
|
||||||
|
newfd = (jint) accept(fd, (struct sockaddr *)&sa, &sa_len);
|
||||||
|
if (newfd == INVALID_SOCKET) {
|
||||||
|
int theErr = (jint)WSAGetLastError();
|
||||||
|
if (theErr == WSAEWOULDBLOCK) {
|
||||||
|
return IOS_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
|
||||||
|
return IOS_THROWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
setfdval(env, newfdo, newfd);
|
||||||
|
|
||||||
|
address = sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
||||||
|
CHECK_NULL_RETURN(address, IOS_THROWN);
|
||||||
|
(*env)->SetObjectArrayElement(env, array, 0, address);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jbyteArray JNICALL
|
||||||
|
Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int sa_len = sizeof(sa);
|
||||||
|
|
||||||
|
if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) == SOCKET_ERROR) {
|
||||||
|
JNU_ThrowIOExceptionWithLastError(env, "getsockname");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2019, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -24,6 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <afunix.h>
|
||||||
|
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
|
|
||||||
@ -35,6 +37,9 @@
|
|||||||
*/
|
*/
|
||||||
#define MAX_BUFFER_SIZE ((128*1024)-1)
|
#define MAX_BUFFER_SIZE ((128*1024)-1)
|
||||||
|
|
||||||
|
#define MAX_UNIX_DOMAIN_PATH_LEN \
|
||||||
|
(int)(sizeof(((struct sockaddr_un *)0)->sun_path)-2)
|
||||||
|
|
||||||
jint fdval(JNIEnv *env, jobject fdo);
|
jint fdval(JNIEnv *env, jobject fdo);
|
||||||
void setfdval(JNIEnv *env, jobject fdo, jint val);
|
void setfdval(JNIEnv *env, jobject fdo, jint val);
|
||||||
jlong handleval(JNIEnv *env, jobject fdo);
|
jlong handleval(JNIEnv *env, jobject fdo);
|
||||||
@ -74,3 +79,11 @@ struct iovec {
|
|||||||
/* POLLCONN must not equal any of the other constants (see winsock2.h). */
|
/* POLLCONN must not equal any of the other constants (see winsock2.h). */
|
||||||
#define POLLCONN 0x2000
|
#define POLLCONN 0x2000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Defined in UnixDomainSockets.c */
|
||||||
|
|
||||||
|
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len);
|
||||||
|
|
||||||
|
jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray uaddr,
|
||||||
|
struct sockaddr_un *sa, int *len);
|
||||||
|
|
||||||
|
@ -27,8 +27,9 @@ package jdk.jfr.internal.instrument;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import jdk.jfr.events.Handlers;
|
import jdk.jfr.events.Handlers;
|
||||||
import jdk.jfr.internal.handlers.EventHandler;
|
import jdk.jfr.internal.handlers.EventHandler;
|
||||||
|
|
||||||
@ -41,8 +42,6 @@ final class SocketChannelImplInstrumentor {
|
|||||||
private SocketChannelImplInstrumentor() {
|
private SocketChannelImplInstrumentor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private InetSocketAddress remoteAddress;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@JIInstrumentationMethod
|
@JIInstrumentationMethod
|
||||||
public int read(ByteBuffer dst) throws IOException {
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
@ -58,16 +57,28 @@ final class SocketChannelImplInstrumentor {
|
|||||||
} finally {
|
} finally {
|
||||||
long duration = EventHandler.timestamp() - start;
|
long duration = EventHandler.timestamp() - start;
|
||||||
if (handler.shouldCommit(duration)) {
|
if (handler.shouldCommit(duration)) {
|
||||||
String hostString = remoteAddress.getAddress().toString();
|
SocketAddress remoteAddress = getRemoteAddress();
|
||||||
int delimiterIndex = hostString.lastIndexOf('/');
|
if (remoteAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) remoteAddress;
|
||||||
|
String hostString = isa.getAddress().toString();
|
||||||
|
int delimiterIndex = hostString.lastIndexOf('/');
|
||||||
|
|
||||||
String host = hostString.substring(0, delimiterIndex);
|
String host = hostString.substring(0, delimiterIndex);
|
||||||
String address = hostString.substring(delimiterIndex + 1);
|
String address = hostString.substring(delimiterIndex + 1);
|
||||||
int port = remoteAddress.getPort();
|
int port = isa.getPort();
|
||||||
if (bytesRead < 0) {
|
if (bytesRead < 0) {
|
||||||
handler.write(start, duration, host, address, port, 0, 0L, true);
|
handler.write(start, duration, host, address, port, 0, 0L, true);
|
||||||
|
} else {
|
||||||
|
handler.write(start, duration, host, address, port, 0, bytesRead, false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handler.write(start, duration, host, address, port, 0, bytesRead, false);
|
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
|
||||||
|
String path = "[" + udsa.getPath().toString() + "]";
|
||||||
|
if (bytesRead < 0) {
|
||||||
|
handler.write(start, duration, "Unix domain socket", path, 0, 0, 0L, true);
|
||||||
|
} else {
|
||||||
|
handler.write(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +92,6 @@ final class SocketChannelImplInstrumentor {
|
|||||||
if (!handler.isEnabled()) {
|
if (!handler.isEnabled()) {
|
||||||
return read(dsts, offset, length);
|
return read(dsts, offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
long bytesRead = 0;
|
long bytesRead = 0;
|
||||||
long start = 0;
|
long start = 0;
|
||||||
try {
|
try {
|
||||||
@ -90,16 +100,28 @@ final class SocketChannelImplInstrumentor {
|
|||||||
} finally {
|
} finally {
|
||||||
long duration = EventHandler.timestamp() - start;
|
long duration = EventHandler.timestamp() - start;
|
||||||
if (handler.shouldCommit(duration)) {
|
if (handler.shouldCommit(duration)) {
|
||||||
String hostString = remoteAddress.getAddress().toString();
|
SocketAddress remoteAddress = getRemoteAddress();
|
||||||
int delimiterIndex = hostString.lastIndexOf('/');
|
if (remoteAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) remoteAddress;
|
||||||
|
String hostString = isa.getAddress().toString();
|
||||||
|
int delimiterIndex = hostString.lastIndexOf('/');
|
||||||
|
|
||||||
String host = hostString.substring(0, delimiterIndex);
|
String host = hostString.substring(0, delimiterIndex);
|
||||||
String address = hostString.substring(delimiterIndex + 1);
|
String address = hostString.substring(delimiterIndex + 1);
|
||||||
int port = remoteAddress.getPort();
|
int port = isa.getPort();
|
||||||
if (bytesRead < 0) {
|
if (bytesRead < 0) {
|
||||||
handler.write(start, duration, host, address, port, 0, 0L, true);
|
handler.write(start, duration, host, address, port, 0, 0L, true);
|
||||||
|
} else {
|
||||||
|
handler.write(start, duration, host, address, port, 0, bytesRead, false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handler.write(start, duration, host, address, port, 0, bytesRead, false);
|
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
|
||||||
|
String path = "[" + udsa.getPath().toString() + "]";
|
||||||
|
if (bytesRead < 0) {
|
||||||
|
handler.write(start, duration, "Unix domain socket", path, 0, 0, 0L, true);
|
||||||
|
} else {
|
||||||
|
handler.write(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,19 +143,32 @@ final class SocketChannelImplInstrumentor {
|
|||||||
} finally {
|
} finally {
|
||||||
long duration = EventHandler.timestamp() - start;
|
long duration = EventHandler.timestamp() - start;
|
||||||
if (handler.shouldCommit(duration)) {
|
if (handler.shouldCommit(duration)) {
|
||||||
String hostString = remoteAddress.getAddress().toString();
|
|
||||||
int delimiterIndex = hostString.lastIndexOf('/');
|
|
||||||
|
|
||||||
String host = hostString.substring(0, delimiterIndex);
|
|
||||||
String address = hostString.substring(delimiterIndex + 1);
|
|
||||||
int port = remoteAddress.getPort();
|
|
||||||
long bytes = bytesWritten < 0 ? 0 : bytesWritten;
|
long bytes = bytesWritten < 0 ? 0 : bytesWritten;
|
||||||
handler.write(start, duration, host, address, port, bytes);
|
SocketAddress remoteAddress = getRemoteAddress();
|
||||||
|
if (remoteAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) remoteAddress;
|
||||||
|
String hostString = isa.getAddress().toString();
|
||||||
|
int delimiterIndex = hostString.lastIndexOf('/');
|
||||||
|
|
||||||
|
String host = hostString.substring(0, delimiterIndex);
|
||||||
|
String address = hostString.substring(delimiterIndex + 1);
|
||||||
|
int port = isa.getPort();
|
||||||
|
handler.write(start, duration, host, address, port, bytes);
|
||||||
|
} else {
|
||||||
|
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
|
||||||
|
String path = "[" + udsa.getPath().toString() + "]";
|
||||||
|
handler.write(start, duration, "Unix domain socket", path, 0, bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SocketAddress getRemoteAddress() throws IOException {
|
||||||
|
// gets replaced by call to instrumented class
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@JIInstrumentationMethod
|
@JIInstrumentationMethod
|
||||||
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
||||||
@ -149,14 +184,22 @@ final class SocketChannelImplInstrumentor {
|
|||||||
} finally {
|
} finally {
|
||||||
long duration = EventHandler.timestamp() - start;
|
long duration = EventHandler.timestamp() - start;
|
||||||
if (handler.shouldCommit(duration)) {
|
if (handler.shouldCommit(duration)) {
|
||||||
String hostString = remoteAddress.getAddress().toString();
|
|
||||||
int delimiterIndex = hostString.lastIndexOf('/');
|
|
||||||
|
|
||||||
String host = hostString.substring(0, delimiterIndex);
|
|
||||||
String address = hostString.substring(delimiterIndex + 1);
|
|
||||||
int port = remoteAddress.getPort();
|
|
||||||
long bytes = bytesWritten < 0 ? 0 : bytesWritten;
|
long bytes = bytesWritten < 0 ? 0 : bytesWritten;
|
||||||
handler.write(start, duration, host, address, port, bytes);
|
SocketAddress remoteAddress = getRemoteAddress();
|
||||||
|
if (remoteAddress instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress isa = (InetSocketAddress) remoteAddress;
|
||||||
|
String hostString = isa.getAddress().toString();
|
||||||
|
int delimiterIndex = hostString.lastIndexOf('/');
|
||||||
|
|
||||||
|
String host = hostString.substring(0, delimiterIndex);
|
||||||
|
String address = hostString.substring(delimiterIndex + 1);
|
||||||
|
int port = isa.getPort();
|
||||||
|
handler.write(start, duration, host, address, port, bytes);
|
||||||
|
} else {
|
||||||
|
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
|
||||||
|
String path = "[" + udsa.getPath().toString() + "]";
|
||||||
|
handler.write(start, duration, "Unix domain socket", path, 0, bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,9 +25,12 @@
|
|||||||
package jdk.net;
|
package jdk.net;
|
||||||
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.nio.file.attribute.UserPrincipal;
|
||||||
|
import java.nio.file.attribute.GroupPrincipal;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
|
import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
|
||||||
|
import sun.nio.fs.UnixUserPrincipals;
|
||||||
|
|
||||||
class LinuxSocketOptions extends PlatformSocketOptions {
|
class LinuxSocketOptions extends PlatformSocketOptions {
|
||||||
|
|
||||||
@ -54,6 +57,10 @@ class LinuxSocketOptions extends PlatformSocketOptions {
|
|||||||
return keepAliveOptionsSupported0();
|
return keepAliveOptionsSupported0();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean peerCredentialsSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setTcpkeepAliveProbes(int fd, final int value) throws SocketException {
|
void setTcpkeepAliveProbes(int fd, final int value) throws SocketException {
|
||||||
setTcpkeepAliveProbes0(fd, value);
|
setTcpkeepAliveProbes0(fd, value);
|
||||||
@ -94,6 +101,16 @@ class LinuxSocketOptions extends PlatformSocketOptions {
|
|||||||
return getIncomingNapiId0(fd);
|
return getIncomingNapiId0(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
|
||||||
|
long l = getSoPeerCred0(fd);
|
||||||
|
int uid = (int)(l >> 32);
|
||||||
|
int gid = (int)l;
|
||||||
|
UserPrincipal user = UnixUserPrincipals.fromUid(uid);
|
||||||
|
GroupPrincipal group = UnixUserPrincipals.fromGid(gid);
|
||||||
|
return new UnixDomainPrincipal(user, group);
|
||||||
|
}
|
||||||
|
|
||||||
private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
|
private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
|
||||||
private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
|
private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
|
||||||
private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
|
private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
|
||||||
@ -102,6 +119,7 @@ class LinuxSocketOptions extends PlatformSocketOptions {
|
|||||||
private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
|
private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
|
||||||
private static native void setQuickAck0(int fd, boolean on) throws SocketException;
|
private static native void setQuickAck0(int fd, boolean on) throws SocketException;
|
||||||
private static native boolean getQuickAck0(int fd) throws SocketException;
|
private static native boolean getQuickAck0(int fd) throws SocketException;
|
||||||
|
private static native long getSoPeerCred0(int fd) throws SocketException;
|
||||||
private static native boolean keepAliveOptionsSupported0();
|
private static native boolean keepAliveOptionsSupported0();
|
||||||
private static native boolean quickAckSupported0();
|
private static native boolean quickAckSupported0();
|
||||||
private static native boolean incomingNapiIdSupported0();
|
private static native boolean incomingNapiIdSupported0();
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -109,6 +111,29 @@ JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_quickAckSupported0
|
|||||||
return socketOptionSupported(SOL_SOCKET, TCP_QUICKACK);
|
return socketOptionSupported(SOL_SOCKET, TCP_QUICKACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: jdk_net_LinuxSocketOptions
|
||||||
|
* Method: getSoPeerCred0
|
||||||
|
* Signature: (I)L
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_jdk_net_LinuxSocketOptions_getSoPeerCred0
|
||||||
|
(JNIEnv *env, jclass clazz, jint fd) {
|
||||||
|
|
||||||
|
int rv;
|
||||||
|
struct ucred cred;
|
||||||
|
socklen_t len = sizeof(cred);
|
||||||
|
|
||||||
|
if ((rv=getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) < 0) {
|
||||||
|
handleError(env, rv, "get SO_PEERCRED failed");
|
||||||
|
} else {
|
||||||
|
if ((int)cred.uid == -1) {
|
||||||
|
handleError(env, -1, "get SO_PEERCRED failed");
|
||||||
|
cred.uid = cred.gid = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (((jlong)cred.uid) << 32) | (cred.gid & 0xffffffffL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: jdk_net_LinuxSocketOptions
|
* Class: jdk_net_LinuxSocketOptions
|
||||||
* Method: keepAliveOptionsSupported0
|
* Method: keepAliveOptionsSupported0
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2019, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,9 +25,12 @@
|
|||||||
package jdk.net;
|
package jdk.net;
|
||||||
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.nio.file.attribute.UserPrincipal;
|
||||||
|
import java.nio.file.attribute.GroupPrincipal;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
|
import jdk.net.ExtendedSocketOptions.PlatformSocketOptions;
|
||||||
|
import sun.nio.fs.UnixUserPrincipals;
|
||||||
|
|
||||||
class MacOSXSocketOptions extends PlatformSocketOptions {
|
class MacOSXSocketOptions extends PlatformSocketOptions {
|
||||||
|
|
||||||
@ -49,6 +52,11 @@ class MacOSXSocketOptions extends PlatformSocketOptions {
|
|||||||
setTcpKeepAliveTime0(fd, value);
|
setTcpKeepAliveTime0(fd, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean peerCredentialsSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setTcpKeepAliveIntvl(int fd, final int value) throws SocketException {
|
void setTcpKeepAliveIntvl(int fd, final int value) throws SocketException {
|
||||||
setTcpKeepAliveIntvl0(fd, value);
|
setTcpKeepAliveIntvl0(fd, value);
|
||||||
@ -69,12 +77,23 @@ class MacOSXSocketOptions extends PlatformSocketOptions {
|
|||||||
return getTcpKeepAliveIntvl0(fd);
|
return getTcpKeepAliveIntvl0(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
|
||||||
|
long l = getSoPeerCred0(fd);
|
||||||
|
int uid = (int)(l >> 32);
|
||||||
|
int gid = (int)l;
|
||||||
|
UserPrincipal user = UnixUserPrincipals.fromUid(uid);
|
||||||
|
GroupPrincipal group = UnixUserPrincipals.fromGid(gid);
|
||||||
|
return new UnixDomainPrincipal(user, group);
|
||||||
|
}
|
||||||
|
|
||||||
private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
|
private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException;
|
||||||
private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
|
private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException;
|
||||||
private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
|
private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException;
|
||||||
private static native int getTcpkeepAliveProbes0(int fd) throws SocketException;
|
private static native int getTcpkeepAliveProbes0(int fd) throws SocketException;
|
||||||
private static native int getTcpKeepAliveTime0(int fd) throws SocketException;
|
private static native int getTcpKeepAliveTime0(int fd) throws SocketException;
|
||||||
private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
|
private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException;
|
||||||
|
private static native long getSoPeerCred0(int fd) throws SocketException;
|
||||||
private static native boolean keepAliveOptionsSupported0();
|
private static native boolean keepAliveOptionsSupported0();
|
||||||
static {
|
static {
|
||||||
if (System.getSecurityManager() == null) {
|
if (System.getSecurityManager() == null) {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,6 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -123,6 +124,25 @@ JNIEXPORT jint JNICALL Java_jdk_net_MacOSXSocketOptions_getTcpkeepAliveProbes0
|
|||||||
return optval;
|
return optval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: jdk_net_MacOSXSocketOptions
|
||||||
|
* Method: getSoPeerCred0
|
||||||
|
* Signature: (I)L
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_jdk_net_MacOSXSocketOptions_getSoPeerCred0
|
||||||
|
(JNIEnv *env, jclass clazz, jint fd) {
|
||||||
|
|
||||||
|
jint rv;
|
||||||
|
int uid, gid;
|
||||||
|
rv = getpeereid(fd, (uid_t *)&uid, (gid_t *)&gid);
|
||||||
|
handleError(env, rv, "get peer eid failed");
|
||||||
|
if (rv == -1) {
|
||||||
|
uid = gid = -1;
|
||||||
|
}
|
||||||
|
return (((long)uid) << 32) | (gid & 0xffffffffL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: jdk_net_MacOSXSocketOptions
|
* Class: jdk_net_MacOSXSocketOptions
|
||||||
* Method: getTcpKeepAliveTime0
|
* Method: getTcpKeepAliveTime0
|
||||||
|
@ -180,6 +180,25 @@ public final class ExtendedSocketOptions {
|
|||||||
public static final SocketOption<Integer> SO_INCOMING_NAPI_ID
|
public static final SocketOption<Integer> SO_INCOMING_NAPI_ID
|
||||||
= new ExtSocketOption<Integer>("SO_INCOMING_NAPI_ID", Integer.class);
|
= new ExtSocketOption<Integer>("SO_INCOMING_NAPI_ID", Integer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unix Domain peer credentials.
|
||||||
|
*
|
||||||
|
* <p> The value of this socket option is a {@link UnixDomainPrincipal} that
|
||||||
|
* represents the credentials of a peer connected to a Unix Domain socket.
|
||||||
|
* The credentials are those that applied at the time the socket was first
|
||||||
|
* connected or accepted.
|
||||||
|
*
|
||||||
|
* <p> The socket option is read-only and an attempt to set the socket option
|
||||||
|
* will throw {@code SocketException}. {@code SocketException} is also thrown
|
||||||
|
* when attempting to get the value of the socket option on an unconnected Unix
|
||||||
|
* Domain socket.
|
||||||
|
*
|
||||||
|
* @since 16
|
||||||
|
*/
|
||||||
|
public static final SocketOption<UnixDomainPrincipal> SO_PEERCRED
|
||||||
|
= new ExtSocketOption<UnixDomainPrincipal>
|
||||||
|
("SO_PEERCRED", UnixDomainPrincipal.class);
|
||||||
|
|
||||||
private static final PlatformSocketOptions platformSocketOptions =
|
private static final PlatformSocketOptions platformSocketOptions =
|
||||||
PlatformSocketOptions.get();
|
PlatformSocketOptions.get();
|
||||||
|
|
||||||
@ -187,6 +206,8 @@ public final class ExtendedSocketOptions {
|
|||||||
platformSocketOptions.quickAckSupported();
|
platformSocketOptions.quickAckSupported();
|
||||||
private static final boolean keepAliveOptSupported =
|
private static final boolean keepAliveOptSupported =
|
||||||
platformSocketOptions.keepAliveOptionsSupported();
|
platformSocketOptions.keepAliveOptionsSupported();
|
||||||
|
private static final boolean peerCredentialsSupported =
|
||||||
|
platformSocketOptions.peerCredentialsSupported();
|
||||||
private static final boolean incomingNapiIdOptSupported =
|
private static final boolean incomingNapiIdOptSupported =
|
||||||
platformSocketOptions.incomingNapiIdSupported();
|
platformSocketOptions.incomingNapiIdSupported();
|
||||||
private static final Set<SocketOption<?>> extendedOptions = options();
|
private static final Set<SocketOption<?>> extendedOptions = options();
|
||||||
@ -202,6 +223,9 @@ public final class ExtendedSocketOptions {
|
|||||||
if (keepAliveOptSupported) {
|
if (keepAliveOptSupported) {
|
||||||
options.addAll(Set.of(TCP_KEEPCOUNT, TCP_KEEPIDLE, TCP_KEEPINTERVAL));
|
options.addAll(Set.of(TCP_KEEPCOUNT, TCP_KEEPIDLE, TCP_KEEPINTERVAL));
|
||||||
}
|
}
|
||||||
|
if (peerCredentialsSupported) {
|
||||||
|
options.add(SO_PEERCRED);
|
||||||
|
}
|
||||||
return Collections.unmodifiableSet(options);
|
return Collections.unmodifiableSet(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,6 +257,8 @@ public final class ExtendedSocketOptions {
|
|||||||
throw new UnsupportedOperationException("Attempt to set unsupported option " + option);
|
throw new UnsupportedOperationException("Attempt to set unsupported option " + option);
|
||||||
else
|
else
|
||||||
throw new SocketException("Attempt to set read only option " + option);
|
throw new SocketException("Attempt to set read only option " + option);
|
||||||
|
} else if (option == SO_PEERCRED) {
|
||||||
|
throw new SocketException("SO_PEERCRED cannot be set ");
|
||||||
} else {
|
} else {
|
||||||
throw new InternalError("Unexpected option " + option);
|
throw new InternalError("Unexpected option " + option);
|
||||||
}
|
}
|
||||||
@ -255,6 +281,8 @@ public final class ExtendedSocketOptions {
|
|||||||
return getTcpKeepAliveTime(fd);
|
return getTcpKeepAliveTime(fd);
|
||||||
} else if (option == TCP_KEEPINTERVAL) {
|
} else if (option == TCP_KEEPINTERVAL) {
|
||||||
return getTcpKeepAliveIntvl(fd);
|
return getTcpKeepAliveIntvl(fd);
|
||||||
|
} else if (option == SO_PEERCRED) {
|
||||||
|
return getSoPeerCred(fd);
|
||||||
} else if (option == SO_INCOMING_NAPI_ID) {
|
} else if (option == SO_INCOMING_NAPI_ID) {
|
||||||
return getIncomingNapiId(fd);
|
return getIncomingNapiId(fd);
|
||||||
} else {
|
} else {
|
||||||
@ -272,6 +300,11 @@ public final class ExtendedSocketOptions {
|
|||||||
platformSocketOptions.setQuickAck(fdAccess.get(fd), enable);
|
platformSocketOptions.setQuickAck(fdAccess.get(fd), enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object getSoPeerCred(FileDescriptor fd)
|
||||||
|
throws SocketException {
|
||||||
|
return platformSocketOptions.getSoPeerCred(fdAccess.get(fd));
|
||||||
|
}
|
||||||
|
|
||||||
private static Object getQuickAckOption(FileDescriptor fd)
|
private static Object getQuickAckOption(FileDescriptor fd)
|
||||||
throws SocketException {
|
throws SocketException {
|
||||||
return platformSocketOptions.getQuickAck(fdAccess.get(fd));
|
return platformSocketOptions.getQuickAck(fdAccess.get(fd));
|
||||||
@ -345,6 +378,10 @@ public final class ExtendedSocketOptions {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean peerCredentialsSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void setQuickAck(int fd, boolean on) throws SocketException {
|
void setQuickAck(int fd, boolean on) throws SocketException {
|
||||||
throw new UnsupportedOperationException("unsupported TCP_QUICKACK option");
|
throw new UnsupportedOperationException("unsupported TCP_QUICKACK option");
|
||||||
}
|
}
|
||||||
@ -369,6 +406,10 @@ public final class ExtendedSocketOptions {
|
|||||||
throw new UnsupportedOperationException("unsupported TCP_KEEPIDLE option");
|
throw new UnsupportedOperationException("unsupported TCP_KEEPIDLE option");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException {
|
||||||
|
throw new UnsupportedOperationException("unsupported SO_PEERCRED option");
|
||||||
|
}
|
||||||
|
|
||||||
void setTcpKeepAliveIntvl(int fd, final int value) throws SocketException {
|
void setTcpKeepAliveIntvl(int fd, final int value) throws SocketException {
|
||||||
throw new UnsupportedOperationException("unsupported TCP_KEEPINTVL option");
|
throw new UnsupportedOperationException("unsupported TCP_KEEPINTVL option");
|
||||||
}
|
}
|
||||||
|
98
src/jdk.net/share/classes/jdk/net/UnixDomainPrincipal.java
Normal file
98
src/jdk.net/share/classes/jdk/net/UnixDomainPrincipal.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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 jdk.net;
|
||||||
|
|
||||||
|
import java.nio.file.attribute.UserPrincipal;
|
||||||
|
import java.nio.file.attribute.GroupPrincipal;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the credentials of a peer connected to a
|
||||||
|
* <a href="../../../java.base/java/nio/channels/package-summary.html#unixdomain">
|
||||||
|
* Unix domain</a> socket.
|
||||||
|
*
|
||||||
|
* @since 16
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class UnixDomainPrincipal {
|
||||||
|
private final UserPrincipal user;
|
||||||
|
private final GroupPrincipal group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a UnixDomainPrincipal.
|
||||||
|
*
|
||||||
|
* @param user the user identity
|
||||||
|
*
|
||||||
|
* @param group the group identity
|
||||||
|
*
|
||||||
|
* @throws NullPointerException if {@code user} or {@code group} are {@code null}.
|
||||||
|
*/
|
||||||
|
public UnixDomainPrincipal(UserPrincipal user, GroupPrincipal group) {
|
||||||
|
this.user = Objects.requireNonNull(user);
|
||||||
|
this.group = Objects.requireNonNull(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if {@code obj} is a {@code UnixDomainPrincipal}
|
||||||
|
* and its user and group are equal to this user and group.
|
||||||
|
*
|
||||||
|
* @param obj the object to compare with
|
||||||
|
* @return true if this equal to obj
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof UnixDomainPrincipal) {
|
||||||
|
UnixDomainPrincipal that = (UnixDomainPrincipal) obj;
|
||||||
|
return Objects.equals(this.user, that.user)
|
||||||
|
&& Objects.equals(this.group, that.group);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hashcode calculated from the user and group
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(user, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this object's {@link UserPrincipal}
|
||||||
|
*
|
||||||
|
* @return this object's user
|
||||||
|
*/
|
||||||
|
public UserPrincipal user() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this object's {@link GroupPrincipal}
|
||||||
|
*
|
||||||
|
* @return this object's user
|
||||||
|
*/
|
||||||
|
public GroupPrincipal group() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
}
|
58
test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java
Normal file
58
test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8231358
|
||||||
|
* @compile ../../nio/file/spi/TestProvider.java AddressTest.java
|
||||||
|
* @run testng/othervm AddressTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.spi.FileSystemProvider;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertThrows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that UnixDomainSocketAddress.of(path) throws IAE
|
||||||
|
* if given a Path that does not originate from system default
|
||||||
|
* file system.
|
||||||
|
*/
|
||||||
|
public class AddressTest {
|
||||||
|
|
||||||
|
// Expected exception
|
||||||
|
private static final Class<IllegalArgumentException> IAE =
|
||||||
|
IllegalArgumentException.class;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public static void runTest() throws Exception {
|
||||||
|
TestProvider prov = new TestProvider(FileSystems.getDefault().provider());
|
||||||
|
Path path = prov.getPath(URI.create("file:/"));
|
||||||
|
assertThrows(IAE, () -> UnixDomainSocketAddress.of(path));
|
||||||
|
}
|
||||||
|
}
|
85
test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java
Normal file
85
test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @summary Test UnixDomainSocketAddress constructor
|
||||||
|
* @library /test/lib
|
||||||
|
* @run testng/othervm LengthTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.testng.annotations.DataProvider;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static java.lang.System.out;
|
||||||
|
import static java.net.StandardProtocolFamily.UNIX;
|
||||||
|
import static jdk.test.lib.Asserts.assertTrue;
|
||||||
|
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class LengthTest {
|
||||||
|
final int namelen = 100; // length close to max
|
||||||
|
|
||||||
|
@DataProvider(name = "strings")
|
||||||
|
public Object[][] strings() {
|
||||||
|
if (namelen == -1)
|
||||||
|
return new Object[][] {new String[]{""}};
|
||||||
|
|
||||||
|
return new Object[][]{
|
||||||
|
{""},
|
||||||
|
{new String(new char[100]).replaceAll("\0", "x")},
|
||||||
|
{new String(new char[namelen]).replaceAll("\0", "x")},
|
||||||
|
{new String(new char[namelen-1]).replaceAll("\0", "x")},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "strings")
|
||||||
|
public void expectPass(String s) {
|
||||||
|
var addr = UnixDomainSocketAddress.of(s);
|
||||||
|
assertTrue(addr.getPath().toString().equals(s), "getPathName.equals(s)");
|
||||||
|
var p = Path.of(s);
|
||||||
|
addr = UnixDomainSocketAddress.of(p);
|
||||||
|
assertTrue(addr.getPath().equals(p), "getPath.equals(p)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void expectNPE() {
|
||||||
|
try {
|
||||||
|
String s = null;
|
||||||
|
UnixDomainSocketAddress.of(s);
|
||||||
|
throw new RuntimeException("Expected NPE");
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
out.println("\tCaught expected exception: " + npe);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Path p = null;
|
||||||
|
UnixDomainSocketAddress.of(p);
|
||||||
|
throw new RuntimeException("Expected NPE");
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
out.println("\tCaught expected exception: " + npe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InvalidObjectException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.ObjectStreamClass;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import static java.io.ObjectStreamConstants.*;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
import static org.testng.Assert.expectThrows;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @summary UnixDomainSocketAddress serialization test
|
||||||
|
* @run testng/othervm UnixDomainSocketAddressSerializationTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public class UnixDomainSocketAddressSerializationTest {
|
||||||
|
private static final UnixDomainSocketAddress addr =
|
||||||
|
UnixDomainSocketAddress.of(Path.of("test.sock"));
|
||||||
|
|
||||||
|
public static void test() throws Exception {
|
||||||
|
assertTrue(addr instanceof Serializable);
|
||||||
|
|
||||||
|
byte[] serialized = serialize(addr);
|
||||||
|
assertTrue(serialized.length > 0);
|
||||||
|
|
||||||
|
UnixDomainSocketAddress deserialized =
|
||||||
|
deserialize(serialized, UnixDomainSocketAddress.class);
|
||||||
|
assertEquals(deserialized.getPath(), addr.getPath());
|
||||||
|
assertEquals(deserialized.toString(), addr.toString());
|
||||||
|
assertEquals(deserialized.hashCode(), addr.hashCode());
|
||||||
|
assertEquals(deserialized, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final Class<InvalidObjectException> IOE = InvalidObjectException.class;
|
||||||
|
static final Class<NullPointerException> NPE = NullPointerException.class;
|
||||||
|
|
||||||
|
/** Tests that UnixDomainSocketAddress in the byte-stream is disallowed. */
|
||||||
|
public static void testUnixDomainSocketAddressInStream() throws Exception {
|
||||||
|
long suid = ObjectStreamClass.lookup(UnixDomainSocketAddress.class).getSerialVersionUID();
|
||||||
|
byte[] bytes = byteStreamFor(UnixDomainSocketAddress.class.getName(), suid);
|
||||||
|
expectThrows(IOE, () -> deserialize(bytes, UnixDomainSocketAddress.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tests that SerialProxy with a null/absent path value in the byte-stream is disallowed. */
|
||||||
|
public static void testSerialProxyNoStreamValues() throws Exception {
|
||||||
|
Class<?> c = Class.forName("java.net.UnixDomainSocketAddress$Ser");
|
||||||
|
long suid = ObjectStreamClass.lookup(c).getSerialVersionUID();
|
||||||
|
byte[] bytes = byteStreamFor(c.getName(), suid);
|
||||||
|
expectThrows(NPE, () -> deserialize(bytes, UnixDomainSocketAddress.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Serializable> byte[] serialize(T t)
|
||||||
|
throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||||
|
oos.writeObject(t);
|
||||||
|
oos.flush();
|
||||||
|
oos.close();
|
||||||
|
return bos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Serializable> T deserialize(byte[] b, Class<T> cl)
|
||||||
|
throws IOException, ClassNotFoundException {
|
||||||
|
try (ObjectInputStream ois =
|
||||||
|
new ObjectInputStream(new ByteArrayInputStream(b))) {
|
||||||
|
Object o = ois.readObject();
|
||||||
|
return cl.cast(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a stream with the given classname and suid. The stream will have
|
||||||
|
* no stream field values.
|
||||||
|
*/
|
||||||
|
static byte[] byteStreamFor(String classname, long suid) throws Exception {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dos = new DataOutputStream(baos);
|
||||||
|
dos.writeShort(STREAM_MAGIC);
|
||||||
|
dos.writeShort(STREAM_VERSION);
|
||||||
|
dos.writeByte(TC_OBJECT);
|
||||||
|
dos.writeByte(TC_CLASSDESC);
|
||||||
|
dos.writeUTF(classname);
|
||||||
|
dos.writeLong(suid);
|
||||||
|
dos.writeByte(SC_SERIALIZABLE);
|
||||||
|
dos.writeShort(0); // number of stream fields
|
||||||
|
dos.writeByte(TC_ENDBLOCKDATA); // no annotations
|
||||||
|
dos.writeByte(TC_NULL); // no superclasses
|
||||||
|
dos.write(TC_ENDBLOCKDATA); // end block - for SC_WRITE_METHOD
|
||||||
|
dos.close();
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ import static java.lang.System.out;
|
|||||||
import static java.net.StandardProtocolFamily.INET;
|
import static java.net.StandardProtocolFamily.INET;
|
||||||
import static java.net.StandardProtocolFamily.INET6;
|
import static java.net.StandardProtocolFamily.INET6;
|
||||||
import static jdk.test.lib.net.IPSupport.*;
|
import static jdk.test.lib.net.IPSupport.*;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertThrows;
|
import static org.testng.Assert.assertThrows;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -305,26 +306,30 @@ public class ProtocolFamilies {
|
|||||||
|
|
||||||
private static SocketChannel openSC(StandardProtocolFamily family)
|
private static SocketChannel openSC(StandardProtocolFamily family)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return family == null ? SocketChannel.open()
|
SocketChannel sc = family == null ? SocketChannel.open()
|
||||||
: SocketChannel.open(family);
|
: SocketChannel.open(family);
|
||||||
|
return sc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ServerSocketChannel openSSC(StandardProtocolFamily family)
|
private static ServerSocketChannel openSSC(StandardProtocolFamily family)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return family == null ? ServerSocketChannel.open()
|
ServerSocketChannel ssc = family == null ? ServerSocketChannel.open()
|
||||||
: ServerSocketChannel.open(family);
|
: ServerSocketChannel.open(family);
|
||||||
|
return ssc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DatagramChannel openDC(StandardProtocolFamily family)
|
private static DatagramChannel openDC(StandardProtocolFamily family)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return family == null ? DatagramChannel.open()
|
DatagramChannel dc = family == null ? DatagramChannel.open()
|
||||||
: DatagramChannel.open(family);
|
: DatagramChannel.open(family);
|
||||||
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SocketAddress getSocketAddress(StandardProtocolFamily family) {
|
private static SocketAddress getSocketAddress(StandardProtocolFamily family) {
|
||||||
return family == null ? null : switch (family) {
|
return family == null ? null : switch (family) {
|
||||||
case INET -> new InetSocketAddress(ia4, 0);
|
case INET -> new InetSocketAddress(ia4, 0);
|
||||||
case INET6 -> new InetSocketAddress(ia6, 0);
|
case INET6 -> new InetSocketAddress(ia6, 0);
|
||||||
|
default -> throw new RuntimeException("Unexpected protocol family");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -29,7 +29,7 @@
|
|||||||
*
|
*
|
||||||
* The test launches the "echo service" with arguments to instruct the
|
* The test launches the "echo service" with arguments to instruct the
|
||||||
* service to close the channel after it receives a small message. The
|
* service to close the channel after it receives a small message. The
|
||||||
* service then delays/lingers for 15 seconds before shuting down. To
|
* service then delays/lingers for 15 seconds before shutting down. To
|
||||||
* prove that the close works we check that we see EOF (meaning the
|
* prove that the close works we check that we see EOF (meaning the
|
||||||
* peer has closed the connection) in less than 15 seconds.
|
* peer has closed the connection) in less than 15 seconds.
|
||||||
*/
|
*/
|
||||||
@ -54,8 +54,7 @@ public class CloseTest {
|
|||||||
service_args[0] = String.valueOf(msg.length());
|
service_args[0] = String.valueOf(msg.length());
|
||||||
service_args[1] = String.valueOf( Utils.adjustTimeout(15*1000) );
|
service_args[1] = String.valueOf( Utils.adjustTimeout(15*1000) );
|
||||||
|
|
||||||
|
SocketChannel sc = Launcher.launchWithInetSocketChannel("EchoService", null, service_args);
|
||||||
SocketChannel sc = Launcher.launchWithSocketChannel("EchoService", service_args);
|
|
||||||
|
|
||||||
// send message - service will echo the message and close the connection.
|
// send message - service will echo the message and close the connection.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -58,7 +58,7 @@ public class EchoTest {
|
|||||||
* that it matches the original message.
|
* that it matches the original message.
|
||||||
*/
|
*/
|
||||||
private static void TCPEchoTest() throws IOException {
|
private static void TCPEchoTest() throws IOException {
|
||||||
SocketChannel sc = Launcher.launchWithSocketChannel(ECHO_SERVICE, null);
|
SocketChannel sc = Launcher.launchWithInetSocketChannel(ECHO_SERVICE, null);
|
||||||
|
|
||||||
String msg = "Where's that damn torpedo?";
|
String msg = "Where's that damn torpedo?";
|
||||||
int repeat = 100;
|
int repeat = 100;
|
||||||
|
@ -85,6 +85,7 @@ public class InheritedChannelTest {
|
|||||||
// These system properties are passed to the launched service as options:
|
// These system properties are passed to the launched service as options:
|
||||||
// java [-options] class [args...]
|
// java [-options] class [args...]
|
||||||
|
|
||||||
|
|
||||||
{ "StateTest run with " + POLICY_PASS, List.of(StateTest.class.getName(),
|
{ "StateTest run with " + POLICY_PASS, List.of(StateTest.class.getName(),
|
||||||
"-Djava.security.manager",
|
"-Djava.security.manager",
|
||||||
"-Djava.security.policy="
|
"-Djava.security.policy="
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -29,9 +28,15 @@
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
import java.nio.channels.ServerSocketChannel;
|
import java.nio.channels.ServerSocketChannel;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import static java.net.StandardProtocolFamily.UNIX;
|
||||||
|
|
||||||
public class Launcher {
|
public class Launcher {
|
||||||
|
|
||||||
@ -63,81 +68,101 @@ public class Launcher {
|
|||||||
launch0(cmdarray, fd);
|
launch0(cmdarray, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch 'java' with specified class using a UnixDomainSocket pair linking calling
|
* Launch 'java' with specified class. The launched process will inherit
|
||||||
* process to the child VM. UnixDomainSocket is a simplified interface to PF_UNIX sockets
|
* a connected Unix Domain socket. The remote endpoint will be the
|
||||||
* which supports byte a time reads and writes.
|
* SocketChannel returned by this method.
|
||||||
*/
|
*/
|
||||||
public static UnixDomainSocket launchWithUnixDomainSocket(String className) throws IOException {
|
public static SocketChannel launchWithUnixSocketChannel(String className)
|
||||||
UnixDomainSocket[] socks = UnixDomainSocket.socketpair();
|
throws IOException
|
||||||
launch(className, null, null, socks[0].fd());
|
{
|
||||||
socks[0].close();
|
UnixDomainSocketAddress addr = null;
|
||||||
return socks[1];
|
try (ServerSocketChannel ssc = ServerSocketChannel.open(UNIX)) {
|
||||||
|
addr = (UnixDomainSocketAddress)ssc.bind(null).getLocalAddress();
|
||||||
|
SocketChannel sc1 = SocketChannel.open(addr);
|
||||||
|
try (SocketChannel sc2 = ssc.accept()) {
|
||||||
|
launch(className, null, null, Util.getFD(sc2));
|
||||||
|
}
|
||||||
|
return sc1;
|
||||||
|
} finally {
|
||||||
|
if (addr != null)
|
||||||
|
Files.delete(addr.getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch specified class with an AF_UNIX socket created externally, and one String arg to child VM
|
|
||||||
*/
|
|
||||||
public static void launchWithUnixDomainSocket(String className, UnixDomainSocket socket, String arg) throws IOException {
|
|
||||||
String[] args = new String[1];
|
|
||||||
args[0] = arg;
|
|
||||||
launch(className, null, args, socket.fd());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Launch 'java' with specified class with the specified arguments (may be null).
|
* Launch 'java' with specified class with the specified arguments (may be null).
|
||||||
* The launched process will inherit a connected TCP socket. The remote endpoint
|
* The launched process will inherit a connected TCP socket. The remote endpoint
|
||||||
* will be the SocketChannel returned by this method.
|
* will be the SocketChannel returned by this method.
|
||||||
*/
|
*/
|
||||||
public static SocketChannel launchWithSocketChannel(String className, String options[], String args[]) throws IOException {
|
public static SocketChannel launchWithInetSocketChannel(String className,
|
||||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
String options[],
|
||||||
ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
|
String... args)
|
||||||
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(),
|
throws IOException
|
||||||
|
{
|
||||||
|
try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
|
||||||
|
ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
|
||||||
|
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(),
|
||||||
ssc.socket().getLocalPort());
|
ssc.socket().getLocalPort());
|
||||||
SocketChannel sc1 = SocketChannel.open(isa);
|
SocketChannel sc1 = SocketChannel.open(isa);
|
||||||
SocketChannel sc2 = ssc.accept();
|
try (SocketChannel sc2 = ssc.accept()) {
|
||||||
launch(className, options, args, Util.getFD(sc2));
|
launch(className, options, args, Util.getFD(sc2));
|
||||||
sc2.close();
|
}
|
||||||
ssc.close();
|
return sc1;
|
||||||
return sc1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SocketChannel launchWithSocketChannel(String className, String args[]) throws IOException {
|
/**
|
||||||
return launchWithSocketChannel(className, null, args);
|
* Launch specified class with a SocketChannel created externally.
|
||||||
|
*/
|
||||||
|
public static void launchWithSocketChannel(String className,
|
||||||
|
SocketChannel sc,
|
||||||
|
String[] options,
|
||||||
|
String... args) throws Exception {
|
||||||
|
launch(className, options, args, Util.getFD(sc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SocketChannel launchWithSocketChannel(String className) throws IOException {
|
/**
|
||||||
return launchWithSocketChannel(className, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Launch 'java' with specified class with the specified arguments (may be null).
|
* Launch 'java' with specified class with the specified arguments (may be null).
|
||||||
* The launched process will inherited a TCP listener socket.
|
* The launched process will inherited a TCP listener socket.
|
||||||
* Once launched this method tries to connect to service. If a connection
|
* Once launched this method tries to connect to service. If a connection
|
||||||
* can be established a SocketChannel, connected to the service, is returned.
|
* can be established a SocketChannel, connected to the service, is returned.
|
||||||
*/
|
*/
|
||||||
public static SocketChannel launchWithServerSocketChannel(String className, String options[], String args[])
|
public static SocketChannel launchWithInetServerSocketChannel(String className,
|
||||||
throws IOException
|
String[] options,
|
||||||
|
String... args)
|
||||||
|
throws IOException
|
||||||
{
|
{
|
||||||
ServerSocketChannel ssc = ServerSocketChannel.open();
|
try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
|
||||||
ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
|
ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
|
||||||
int port = ssc.socket().getLocalPort();
|
int port = ssc.socket().getLocalPort();
|
||||||
launch(className, options, args, Util.getFD(ssc));
|
launch(className, options, args, Util.getFD(ssc));
|
||||||
|
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port);
|
||||||
|
return SocketChannel.open(isa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SocketChannel launchWithUnixServerSocketChannel(String className) throws IOException {
|
||||||
|
ServerSocketChannel ssc = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
ssc.bind(null);
|
||||||
|
var addr = ssc.getLocalAddress();
|
||||||
|
launch(className, null, null, Util.getFD(ssc));
|
||||||
ssc.close();
|
ssc.close();
|
||||||
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port);
|
return SocketChannel.open(addr);
|
||||||
return SocketChannel.open(isa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SocketChannel launchWithServerSocketChannel(String className, String args[]) throws IOException {
|
/**
|
||||||
return launchWithServerSocketChannel(className, null, args);
|
* Launch specified class with a ServerSocketChannel created externally.
|
||||||
|
*/
|
||||||
|
public static void launchWithServerSocketChannel(String className,
|
||||||
|
ServerSocketChannel ssc,
|
||||||
|
String[] options,
|
||||||
|
String... args)
|
||||||
|
throws Exception {
|
||||||
|
launch(className, options, args, Util.getFD(ssc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SocketChannel launchWithServerSocketChannel(String className) throws IOException {
|
/**
|
||||||
return launchWithServerSocketChannel(className, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Launch 'java' with specified class with the specified arguments (may be null).
|
* Launch 'java' with specified class with the specified arguments (may be null).
|
||||||
* The launch process will inherited a bound UDP socket.
|
* The launch process will inherited a bound UDP socket.
|
||||||
* Once launched this method creates a DatagramChannel and "connects
|
* Once launched this method creates a DatagramChannel and "connects
|
||||||
@ -145,9 +170,10 @@ public class Launcher {
|
|||||||
* As it is connected any packets sent from the socket will be
|
* As it is connected any packets sent from the socket will be
|
||||||
* sent to the service.
|
* sent to the service.
|
||||||
*/
|
*/
|
||||||
public static DatagramChannel launchWithDatagramChannel(String className, String options[], String args[])
|
public static DatagramChannel launchWithDatagramChannel(String className,
|
||||||
throws IOException
|
String[] options,
|
||||||
{
|
String... args)
|
||||||
|
throws IOException {
|
||||||
InetAddress address = InetAddress.getLocalHost();
|
InetAddress address = InetAddress.getLocalHost();
|
||||||
if (address.isLoopbackAddress()) {
|
if (address.isLoopbackAddress()) {
|
||||||
address = InetAddress.getLoopbackAddress();
|
address = InetAddress.getLoopbackAddress();
|
||||||
@ -165,12 +191,4 @@ public class Launcher {
|
|||||||
dc.connect(isa);
|
dc.connect(isa);
|
||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DatagramChannel launchWithDatagramChannel(String className, String args[]) throws IOException {
|
|
||||||
return launchWithDatagramChannel(className, null, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DatagramChannel launchWithDatagramChannel(String className) throws IOException {
|
|
||||||
return launchWithDatagramChannel(className, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -170,8 +170,8 @@ public class StateTest {
|
|||||||
/*
|
/*
|
||||||
* Launch service with a SocketChannel (tcp nowait)
|
* Launch service with a SocketChannel (tcp nowait)
|
||||||
*/
|
*/
|
||||||
System.err.println("launchWithSocketChannel");
|
System.err.println("launchWithInetSocketChannel");
|
||||||
SocketChannel sc = Launcher.launchWithSocketChannel(TEST_SERVICE, options, arg);
|
SocketChannel sc = Launcher.launchWithInetSocketChannel(TEST_SERVICE, options, arg);
|
||||||
System.err.println("Waiting for test results");
|
System.err.println("Waiting for test results");
|
||||||
waitForTestResult(ssc, expectFail);
|
waitForTestResult(ssc, expectFail);
|
||||||
sc.close();
|
sc.close();
|
||||||
@ -181,8 +181,8 @@ public class StateTest {
|
|||||||
* launchWithServerSocketChannel establishes a connection to the service
|
* launchWithServerSocketChannel establishes a connection to the service
|
||||||
* and the returned SocketChannel is connected to the service.
|
* and the returned SocketChannel is connected to the service.
|
||||||
*/
|
*/
|
||||||
System.err.println("launchWithServerSocketChannel");
|
System.err.println("launchWithInetServerSocketChannel");
|
||||||
sc = Launcher.launchWithServerSocketChannel(TEST_SERVICE, options, arg);
|
sc = Launcher.launchWithInetServerSocketChannel(TEST_SERVICE, options, arg);
|
||||||
waitForTestResult(ssc, expectFail);
|
waitForTestResult(ssc, expectFail);
|
||||||
sc.close();
|
sc.close();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,7 +27,7 @@
|
|||||||
* A test service for use in the inetd/System.inheritedChannel unit
|
* A test service for use in the inetd/System.inheritedChannel unit
|
||||||
* tests.
|
* tests.
|
||||||
*
|
*
|
||||||
* The test checks that the channel returned by System.inheritiedChannel
|
* The test checks that the channel returned by System.inheritedChannel
|
||||||
* is in blocking mode and is bound. In addition, in the case of a
|
* is in blocking mode and is bound. In addition, in the case of a
|
||||||
* SocketChannel checks that the socket is connected.
|
* SocketChannel checks that the socket is connected.
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,41 +21,50 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
import java.nio.channels.*;
|
import java.nio.channels.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.io.IOException;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static java.net.StandardProtocolFamily.UNIX;
|
||||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure that System.inheritedChannel returns null when given a UNIX domain socket
|
* Make sure that System.inheritedChannel returns the correct type
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class UnixDomainChannelTest {
|
public class UnixDomainChannelTest {
|
||||||
|
private static final UnixDomainSocketAddress SOCK_ADDR =
|
||||||
|
UnixDomainSocketAddress.of(Path.of("foo.socket"));
|
||||||
|
|
||||||
|
private static boolean passed = true;
|
||||||
|
|
||||||
public static class Child {
|
public static class Child {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// we just want to make sure that System.inheritedChannel either
|
// we want to make sure that System.inheritedChannel either
|
||||||
// returns a connected channel, or null if it is given a listener
|
// returns a ServerSocketChannel or a SocketChannel
|
||||||
Channel channel = System.inheritedChannel();
|
Channel channel = System.inheritedChannel();
|
||||||
String result = channel == null ? "N" : "Y";
|
String result = channel == null ? "N" : "Y";
|
||||||
if (args[0].equals("test1") || args[0].equals("test2")) {
|
if (args[0].equals("test1") || args[0].equals("test2")) {
|
||||||
// socket is writeable
|
if (channel instanceof SocketChannel) {
|
||||||
ByteChannel bc = (ByteChannel)channel;
|
SocketChannel sc = (SocketChannel) channel;
|
||||||
ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1));
|
ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1));
|
||||||
bc.write(buf);
|
sc.write(buf);
|
||||||
|
}
|
||||||
} else { // test3
|
} else { // test3
|
||||||
// in this case the socket is a listener
|
if (channel instanceof ServerSocketChannel) {
|
||||||
// we can't write to it. So, use UnixDatagramSocket
|
ServerSocketChannel server = (ServerSocketChannel) channel;
|
||||||
// to accept a writeable socket
|
SocketChannel sc = server.accept();
|
||||||
UnixDomainSocket listener = new UnixDomainSocket(0); // fd 0
|
ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1));
|
||||||
UnixDomainSocket sock = listener.accept();
|
sc.write(buf);
|
||||||
sock.write((int)result.charAt(0));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean passed = true;
|
|
||||||
|
|
||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
||||||
@ -64,54 +73,92 @@ public class UnixDomainChannelTest {
|
|||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void closeAll(UnixDomainSocket... sockets) {
|
|
||||||
for (UnixDomainSocket sock : sockets) {
|
|
||||||
sock.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with a named connected socket
|
// Test with a named connected socket
|
||||||
private static void test1() throws Exception {
|
private static void test1() throws Exception {
|
||||||
UnixDomainSocket listener = new UnixDomainSocket();
|
ServerSocketChannel listener = ServerSocketChannel.open(UNIX);
|
||||||
listener.bind("foo.socket");
|
listener.bind(SOCK_ADDR);
|
||||||
UnixDomainSocket sock1 = new UnixDomainSocket();
|
SocketChannel sock1 = SocketChannel.open(SOCK_ADDR);
|
||||||
sock1.connect("foo.socket");
|
SocketChannel sock2 = listener.accept();
|
||||||
UnixDomainSocket sock2 = listener.accept();
|
System.out.println("test1: launching child");
|
||||||
|
Launcher.launchWithSocketChannel(
|
||||||
Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", sock2, "test1");
|
"UnixDomainChannelTest$Child", sock2, null, "test1");
|
||||||
int c = sock1.read();
|
ByteBuffer bb = ByteBuffer.allocate(10);
|
||||||
if (c != 'Y') {
|
int c = sock1.read(bb);
|
||||||
System.err.printf("test1: failed %d d\n", c );
|
if (c != 1) {
|
||||||
|
System.err.printf("test1: failed " +
|
||||||
|
"- unexpected number of bytes read %d d\n", c);
|
||||||
|
passed = false;
|
||||||
|
}
|
||||||
|
byte b = bb.get(0);
|
||||||
|
if (b != 'Y') {
|
||||||
|
System.err.printf("test1: failed " +
|
||||||
|
"- unexpected byte read %d d\n", b);
|
||||||
passed = false;
|
passed = false;
|
||||||
}
|
}
|
||||||
closeAll(listener, sock1, sock2);
|
closeAll(listener, sock1, sock2);
|
||||||
|
Files.deleteIfExists(SOCK_ADDR.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with unnamed socketpair
|
// Test with unnamed socketpair
|
||||||
private static void test2() throws Exception {
|
private static void test2() throws Exception {
|
||||||
UnixDomainSocket[] pair = UnixDomainSocket.socketpair();
|
ServerSocketChannel listener = ServerSocketChannel.open(UNIX);
|
||||||
|
SocketAddress addr = listener.bind(null).getLocalAddress();
|
||||||
|
SocketChannel sock1 = SocketChannel.open(addr);
|
||||||
|
SocketChannel sock2 = listener.accept();
|
||||||
System.out.println("test2: launching child");
|
System.out.println("test2: launching child");
|
||||||
Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", pair[0], "test2");
|
Launcher.launchWithSocketChannel(
|
||||||
if (pair[1].read() != 'Y') {
|
"UnixDomainChannelTest$Child", sock2, null, "test2");
|
||||||
System.err.println("test2: failed");
|
ByteBuffer bb = ByteBuffer.allocate(10);
|
||||||
|
int c = sock1.read(bb);
|
||||||
|
if (c != 1) {
|
||||||
|
System.err.printf("test3: failed " +
|
||||||
|
"- unexpected number of bytes read %d d\n", c);
|
||||||
passed = false;
|
passed = false;
|
||||||
}
|
}
|
||||||
closeAll(pair[0], pair[1]);
|
byte b = bb.get(0);
|
||||||
|
if (b != 'Y') {
|
||||||
|
System.err.printf("test3: failed " +
|
||||||
|
"- unexpected byte read %d d\n", b);
|
||||||
|
passed = false;
|
||||||
|
}
|
||||||
|
closeAll(listener, sock1, sock2);
|
||||||
|
Files.deleteIfExists(((UnixDomainSocketAddress)addr).getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with a named listener
|
// Test with a named listener
|
||||||
private static void test3() throws Exception {
|
private static void test3() throws Exception {
|
||||||
UnixDomainSocket listener = new UnixDomainSocket();
|
ServerSocketChannel listener = ServerSocketChannel.open(UNIX);
|
||||||
listener.bind("foo.socket");
|
listener.bind(SOCK_ADDR);
|
||||||
UnixDomainSocket sock1 = new UnixDomainSocket();
|
SocketChannel sock1 = SocketChannel.open(UNIX);
|
||||||
System.out.println("test3: launching child");
|
System.out.println("test3: launching child");
|
||||||
Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", listener, "test3");
|
Launcher.launchWithServerSocketChannel(
|
||||||
sock1.connect("foo.socket");
|
"UnixDomainChannelTest$Child", listener, null, "test3");
|
||||||
if (sock1.read() != 'N') {
|
sock1.connect(SOCK_ADDR);
|
||||||
System.err.println("test3: failed");
|
ByteBuffer bb = ByteBuffer.allocate(10);
|
||||||
|
int c = sock1.read(bb);
|
||||||
|
if (c != 1) {
|
||||||
|
System.err.printf("test3: failed " +
|
||||||
|
"- unexpected number of bytes read %d d\n", c);
|
||||||
|
passed = false;
|
||||||
|
}
|
||||||
|
byte b = bb.get(0);
|
||||||
|
if (b != 'Y') {
|
||||||
|
System.err.printf("test3: failed " +
|
||||||
|
"- unexpected byte read %d d\n", b);
|
||||||
passed = false;
|
passed = false;
|
||||||
}
|
}
|
||||||
closeAll(listener, sock1);
|
closeAll(listener, sock1);
|
||||||
|
Files.deleteIfExists(SOCK_ADDR.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void closeAll(Channel... channels) {
|
||||||
|
for (Channel c : channels) {
|
||||||
|
try {
|
||||||
|
if (c != null)
|
||||||
|
c.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Could not close channel " + c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simplified Unix domain socket which can read and write bytes at a time
|
|
||||||
* used for simulating external launchers which use UNIX sockets to talk
|
|
||||||
* the VM.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class UnixDomainSocket {
|
|
||||||
|
|
||||||
static {
|
|
||||||
System.loadLibrary("InheritedChannel");
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final int fd;
|
|
||||||
private volatile String name;
|
|
||||||
|
|
||||||
public UnixDomainSocket() throws IOException {
|
|
||||||
this.fd = create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bind(String name) throws IOException {
|
|
||||||
bind0(fd, name);
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDomainSocket accept() throws IOException {
|
|
||||||
int newsock = accept0(fd);
|
|
||||||
return new UnixDomainSocket(newsock);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDomainSocket(int fd) {
|
|
||||||
this.fd = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void connect(String dest) throws IOException {
|
|
||||||
connect0(fd, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read() throws IOException {
|
|
||||||
return read0(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String name() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int w) throws IOException {
|
|
||||||
write0(fd, w);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
close0(fd, name); // close0 will unlink name if non-null
|
|
||||||
}
|
|
||||||
|
|
||||||
public int fd() {
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "UnixDomainSocket: fd=" + Integer.toString(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native int create() throws IOException;
|
|
||||||
private static native void bind0(int fd, String name) throws IOException;
|
|
||||||
private static native int accept0(int fd) throws IOException;
|
|
||||||
private static native int connect0(int fd, String name) throws IOException;
|
|
||||||
|
|
||||||
/* read and write bytes with UNIX domain sockets */
|
|
||||||
|
|
||||||
private static native int read0(int fd) throws IOException;
|
|
||||||
private static native void write0(int fd, int w) throws IOException;
|
|
||||||
private static native void close0(int fd, String name);
|
|
||||||
private static native void init();
|
|
||||||
public static native UnixDomainSocket[] socketpair();
|
|
||||||
}
|
|
||||||
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,56 +21,68 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* If the platform has IPv6 we spawn a child process simulating the
|
|
||||||
* effect of being launched from node.js. We check that IPv6 is available in the child
|
|
||||||
* and report back as appropriate.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import jdk.test.lib.Utils;
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
import static java.net.StandardProtocolFamily.UNIX;
|
||||||
|
|
||||||
public class UnixSocketTest {
|
public class UnixSocketTest {
|
||||||
|
|
||||||
static boolean hasIPv6() throws Exception {
|
public static class Child1 {
|
||||||
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
|
public static void main(String[] args) throws Exception {
|
||||||
for (NetworkInterface netint : Collections.list(nets)) {
|
SocketChannel chan = (SocketChannel)System.inheritedChannel();
|
||||||
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
|
ByteBuffer bb = ByteBuffer.allocate(2);
|
||||||
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
|
bb.put((byte)'X');
|
||||||
if (inetAddress instanceof Inet6Address) {
|
bb.put((byte)'Y');
|
||||||
return true;
|
bb.flip();
|
||||||
}
|
chan.write(bb);
|
||||||
}
|
chan.close();
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Child {
|
public static class Child2 {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
System.out.write('X');
|
ServerSocketChannel server = (ServerSocketChannel)System.inheritedChannel();
|
||||||
System.out.flush();
|
SocketChannel chan = server.accept();
|
||||||
if (hasIPv6()) {
|
UnixDomainSocketAddress sa = (UnixDomainSocketAddress)server.getLocalAddress();
|
||||||
System.out.println("Y"); // GOOD
|
Files.delete(sa.getPath());
|
||||||
} else
|
server.close();
|
||||||
System.out.println("N"); // BAD
|
ByteBuffer bb = ByteBuffer.allocate(2);
|
||||||
|
bb.put((byte)'X');
|
||||||
|
bb.put((byte)'Y');
|
||||||
|
bb.flip();
|
||||||
|
chan.write(bb);
|
||||||
|
chan.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
|
SocketChannel sc = Launcher.launchWithUnixSocketChannel("UnixSocketTest$Child1");
|
||||||
if (!hasIPv6()) {
|
ByteBuffer bb = ByteBuffer.allocate(10);
|
||||||
return; // can only test if IPv6 is present
|
sc.read(bb);
|
||||||
}
|
if (bb.get(0) != 'X') {
|
||||||
UnixDomainSocket sock = Launcher.launchWithUnixDomainSocket("UnixSocketTest$Child");
|
|
||||||
if (sock.read() != 'X') {
|
|
||||||
System.exit(-2);
|
System.exit(-2);
|
||||||
}
|
}
|
||||||
if (sock.read() != 'Y') {
|
if (bb.get(1) != 'Y') {
|
||||||
|
System.exit(-2);
|
||||||
|
}
|
||||||
|
sc.close();
|
||||||
|
|
||||||
|
sc = Launcher.launchWithUnixServerSocketChannel("UnixSocketTest$Child2");
|
||||||
|
bb.clear();
|
||||||
|
sc.read(bb);
|
||||||
|
if (bb.get(0) != 'X') {
|
||||||
|
System.exit(-2);
|
||||||
|
}
|
||||||
|
if (bb.get(1) != 'Y') {
|
||||||
System.exit(-2);
|
System.exit(-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -40,9 +39,6 @@
|
|||||||
|
|
||||||
#define CHECK(X) if ((X) == 0) {printf("JNI init error line %d\n", __LINE__); _exit(1);}
|
#define CHECK(X) if ((X) == 0) {printf("JNI init error line %d\n", __LINE__); _exit(1);}
|
||||||
|
|
||||||
static jclass unixSocketClass;
|
|
||||||
static jmethodID unixSocketCtor;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Throws the exception of the given class name and detail message
|
* Throws the exception of the given class name and detail message
|
||||||
*/
|
*/
|
||||||
@ -85,7 +81,6 @@ static char* getString8859_1Chars(JNIEnv *env, jstring jstr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: Launcher
|
* Class: Launcher
|
||||||
* Method: launch0
|
* Method: launch0
|
||||||
@ -145,7 +140,7 @@ JNIEXPORT void JNICALL Java_Launcher_launch0
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to close all file descriptors except for serviceFd. To
|
* We need to close all file descriptors except for serviceFd. To
|
||||||
* get the list of open file descriptos we read through /proc/self/fd (/dev/fd)
|
* get the list of open file descriptors we read through /proc/self/fd (/dev/fd)
|
||||||
* but to open this requires a file descriptor. We could use a specific
|
* but to open this requires a file descriptor. We could use a specific
|
||||||
* file descriptor and fdopendir but Linux doesn't seem to support
|
* file descriptor and fdopendir but Linux doesn't seem to support
|
||||||
* fdopendir. Instead we use opendir and make an assumption on the
|
* fdopendir. Instead we use opendir and make an assumption on the
|
||||||
@ -184,131 +179,3 @@ JNIEXPORT void JNICALL Java_Launcher_launch0
|
|||||||
execvp(cmdv[0], cmdv);
|
execvp(cmdv[0], cmdv);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_init(JNIEnv *env, jclass cls) {
|
|
||||||
CHECK(unixSocketClass = (*env)->FindClass(env, "UnixDomainSocket"));
|
|
||||||
CHECK(unixSocketClass = (*env)->NewGlobalRef(env, unixSocketClass));
|
|
||||||
CHECK(unixSocketCtor = (*env)->GetMethodID(env, unixSocketClass, "<init>", "(I)V"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: UnixDomainSocket
|
|
||||||
* Method: socketpair
|
|
||||||
* Signature: ()[LUnixDomainSocket
|
|
||||||
*/
|
|
||||||
JNIEXPORT jobjectArray JNICALL Java_UnixDomainSocket_socketpair
|
|
||||||
(JNIEnv *env, jclass cls)
|
|
||||||
{
|
|
||||||
int fds[2];
|
|
||||||
jobject socket;
|
|
||||||
jobjectArray result = (*env)->NewObjectArray(env, 2, unixSocketClass, 0);
|
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
|
|
||||||
perror("socketpair");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
socket = (*env)->NewObject(env, unixSocketClass, unixSocketCtor, fds[0]);
|
|
||||||
(*env)->SetObjectArrayElement(env, result, 0, socket);
|
|
||||||
socket = (*env)->NewObject(env, unixSocketClass, unixSocketCtor, fds[1]);
|
|
||||||
(*env)->SetObjectArrayElement(env, result, 1, socket);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_UnixDomainSocket_create
|
|
||||||
(JNIEnv *env, jclass cls)
|
|
||||||
{
|
|
||||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (sock == -1) {
|
|
||||||
ThrowException(env, "java/io/IOException", "socket create error");
|
|
||||||
}
|
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_bind0
|
|
||||||
(JNIEnv *env, jclass cls, jint sock, jstring name)
|
|
||||||
{
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL);
|
|
||||||
int ret = -1;
|
|
||||||
int length = sizeof(addr.sun_path);
|
|
||||||
unlink(nameUtf);
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strncpy(addr.sun_path, nameUtf, length);
|
|
||||||
addr.sun_path[length - 1] = '\0';
|
|
||||||
ret = bind(sock, (const struct sockaddr*)&addr, sizeof(addr));
|
|
||||||
if (ret == -1) {
|
|
||||||
ThrowException(env, "java/io/IOException", "socket bind error");
|
|
||||||
}
|
|
||||||
ret = listen(sock, 5);
|
|
||||||
if (ret == -1) {
|
|
||||||
ThrowException(env, "java/io/IOException", "socket bind error");
|
|
||||||
}
|
|
||||||
(*env)->ReleaseStringUTFChars(env, name, nameUtf);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_UnixDomainSocket_accept0
|
|
||||||
(JNIEnv *env, jclass cls, jint sock)
|
|
||||||
{
|
|
||||||
struct sockaddr_storage addr;
|
|
||||||
socklen_t len = sizeof(addr);
|
|
||||||
int ret = accept(sock, (struct sockaddr *)&addr, &len);
|
|
||||||
if (ret == -1)
|
|
||||||
ThrowException(env, "java/io/IOException", "socket accept error");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_connect0
|
|
||||||
(JNIEnv *env, jclass cls, jint fd, jstring name)
|
|
||||||
{
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL);
|
|
||||||
int ret = -1;
|
|
||||||
int length = sizeof(addr.sun_path);
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strncpy(addr.sun_path, nameUtf, length);
|
|
||||||
addr.sun_path[length - 1] = '\0';
|
|
||||||
ret = connect(fd, (const struct sockaddr*)&addr, sizeof(addr));
|
|
||||||
if (ret == -1) {
|
|
||||||
ThrowException(env, "java/io/IOException", "socket connect error");
|
|
||||||
}
|
|
||||||
(*env)->ReleaseStringUTFChars(env, name, nameUtf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_UnixDomainSocket_read0
|
|
||||||
(JNIEnv *env, jclass cls, jint fd)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned char res;
|
|
||||||
ret = read(fd, &res, 1);
|
|
||||||
if (ret == 0)
|
|
||||||
return -1; /* EOF */
|
|
||||||
else if (ret < 0) {
|
|
||||||
ThrowException(env, "java/io/IOException", "read error");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_write0
|
|
||||||
(JNIEnv *env, jclass cls, jint fd, jint byte)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned char w = (unsigned char)byte;
|
|
||||||
ret = write(fd, &w, 1);
|
|
||||||
if (ret < 0) {
|
|
||||||
ThrowException(env, "java/io/IOException", "write error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_UnixDomainSocket_close0
|
|
||||||
(JNIEnv *env, jclass cls, jint fd, jstring name)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
if (name != NULL) {
|
|
||||||
const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL);
|
|
||||||
unlink(nameUtf);
|
|
||||||
(*env)->ReleaseStringUTFChars(env, name, nameUtf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
329
test/jdk/java/nio/channels/unixdomain/Bind.java
Normal file
329
test/jdk/java/nio/channels/unixdomain/Bind.java
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8245194
|
||||||
|
* @library /test/lib
|
||||||
|
* @run main/othervm Bind
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import jtreg.SkippedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that all bind variations work
|
||||||
|
*/
|
||||||
|
public class Bind {
|
||||||
|
|
||||||
|
static Path spath, cpath;
|
||||||
|
|
||||||
|
static UnixDomainSocketAddress sAddr, cAddr, UNNAMED, nullAddr;
|
||||||
|
static ServerSocketChannel server;
|
||||||
|
static SocketChannel client, accept1;
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
checkSupported();
|
||||||
|
spath = Path.of("server.sock");
|
||||||
|
cpath = Path.of("client.sock");
|
||||||
|
sAddr = UnixDomainSocketAddress.of(spath);
|
||||||
|
cAddr = UnixDomainSocketAddress.of(cpath);
|
||||||
|
nullAddr = UnixDomainSocketAddress.of("");
|
||||||
|
UNNAMED = nullAddr;
|
||||||
|
runTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkSupported() {
|
||||||
|
try {
|
||||||
|
SocketChannel.open(StandardProtocolFamily.UNIX).close();
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
throw new SkippedException("Unix domain channels not supported");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// continue test to see what problem is
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface ThrowingRunnable {
|
||||||
|
public void run() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init() throws IOException {
|
||||||
|
Files.deleteIfExists(cpath);
|
||||||
|
Files.deleteIfExists(spath);
|
||||||
|
client = null; server = null; accept1 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkNormal(ThrowingRunnable r) {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
r.run();
|
||||||
|
System.out.println("PASS:");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkException(Class<? extends Exception> expected, ThrowingRunnable r) {
|
||||||
|
try {
|
||||||
|
init();
|
||||||
|
r.run();
|
||||||
|
throw new RuntimeException("Exception expected");
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (!expected.isAssignableFrom(e.getClass())) {
|
||||||
|
String msg = "Expected: " + expected + " Got: " + e.getClass();
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
System.out.println("PASS: Got " + e);
|
||||||
|
} finally {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup() {
|
||||||
|
try {
|
||||||
|
if (server != null)
|
||||||
|
server.close();
|
||||||
|
if (client != null)
|
||||||
|
client.close();
|
||||||
|
if (accept1 != null)
|
||||||
|
accept1.close();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertClientAddress(SocketAddress a) {
|
||||||
|
assertAddress(a, cAddr, "client");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertServerAddress(SocketAddress a) {
|
||||||
|
assertAddress(a, sAddr, "server");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertAddress(SocketAddress a, UnixDomainSocketAddress a1, String s) {
|
||||||
|
if (!(a instanceof UnixDomainSocketAddress)) {
|
||||||
|
throw new RuntimeException("wrong address type");
|
||||||
|
}
|
||||||
|
UnixDomainSocketAddress ua = (UnixDomainSocketAddress)a;
|
||||||
|
if (!a.equals(a1))
|
||||||
|
throw new RuntimeException("this is not the " + s + " address");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertEquals(Object a, Object b) {
|
||||||
|
if (!a.equals(b))
|
||||||
|
throw new RuntimeException("identity check failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void runTests() throws IOException {
|
||||||
|
checkNormal(() -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(cAddr);
|
||||||
|
});
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(sAddr);
|
||||||
|
});
|
||||||
|
// Repeat first two to make sure they are repeatable
|
||||||
|
checkNormal(() -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(cAddr);
|
||||||
|
});
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(sAddr);
|
||||||
|
});
|
||||||
|
// address with space should work
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
UnixDomainSocketAddress usa = UnixDomainSocketAddress.of("with space"); // relative to CWD
|
||||||
|
Files.deleteIfExists(usa.getPath());
|
||||||
|
server.bind(usa);
|
||||||
|
client = SocketChannel.open(usa);
|
||||||
|
Files.delete(usa.getPath());
|
||||||
|
assertAddress(client.getRemoteAddress(), usa, "address");
|
||||||
|
});
|
||||||
|
// client bind to null: allowed
|
||||||
|
checkNormal(() -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(null);
|
||||||
|
SocketAddress a = client.getLocalAddress();
|
||||||
|
assertAddress(a, nullAddr, "null address");
|
||||||
|
assertEquals(a, UNNAMED);
|
||||||
|
});
|
||||||
|
// client bind to UNNAMED: allowed
|
||||||
|
checkNormal(() -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(UNNAMED);
|
||||||
|
SocketAddress a = client.getLocalAddress();
|
||||||
|
assertAddress(a, nullAddr, "null address");
|
||||||
|
assertEquals(a, UNNAMED);
|
||||||
|
});
|
||||||
|
// server bind to null: should bind to a local address
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(null);
|
||||||
|
UnixDomainSocketAddress usa = (UnixDomainSocketAddress)server.getLocalAddress();
|
||||||
|
if (usa.getPath().toString().isEmpty())
|
||||||
|
throw new RuntimeException("expected non zero address length");
|
||||||
|
System.out.println("Null server address: " + server.getLocalAddress());
|
||||||
|
});
|
||||||
|
// server no bind : not allowed
|
||||||
|
checkException(
|
||||||
|
NotYetBoundException.class, () -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.accept();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// client implicit bind and connect
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(sAddr);
|
||||||
|
client.connect(sAddr);
|
||||||
|
SocketAddress cAddr = client.getLocalAddress();
|
||||||
|
assertAddress(cAddr, nullAddr, "null address");
|
||||||
|
assertEquals(cAddr, UNNAMED);
|
||||||
|
assertServerAddress(server.getLocalAddress());
|
||||||
|
});
|
||||||
|
// client null bind and connect (check all addresses)
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(sAddr);
|
||||||
|
client.bind(null);
|
||||||
|
client.connect(sAddr);
|
||||||
|
assertAddress(client.getLocalAddress(), UNNAMED, "unnamed address");
|
||||||
|
assertServerAddress(server.getLocalAddress());
|
||||||
|
});
|
||||||
|
// client explicit bind and connect (check all addresses)
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(sAddr);
|
||||||
|
client.bind(cAddr);
|
||||||
|
client.connect(sAddr);
|
||||||
|
accept1 = server.accept();
|
||||||
|
assertClientAddress(client.getLocalAddress());
|
||||||
|
assertServerAddress(server.getLocalAddress());
|
||||||
|
assertAddress(client.getRemoteAddress(), sAddr, "client's remote server address");
|
||||||
|
assertAddress(accept1.getLocalAddress(), sAddr, "accepted local address (server)");
|
||||||
|
assertAddress(accept1.getRemoteAddress(), cAddr, "accepted remote address (client)");
|
||||||
|
});
|
||||||
|
// server multiple bind : not allowed
|
||||||
|
checkException(
|
||||||
|
AlreadyBoundException.class, () -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(sAddr);
|
||||||
|
server.bind(sAddr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// client multiple bind : not allowed
|
||||||
|
checkException(
|
||||||
|
AlreadyBoundException.class, () -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(cAddr);
|
||||||
|
client.bind(cAddr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// client multiple bind to different addresses: not allowed
|
||||||
|
checkException(
|
||||||
|
AlreadyBoundException.class, () -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(cAddr);
|
||||||
|
client.bind(sAddr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// client multiple bind to differnt addresses, incl null: not allowed
|
||||||
|
checkException(
|
||||||
|
AlreadyBoundException.class, () -> {
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
client.bind(null);
|
||||||
|
client.bind(cAddr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// server bind to existing name: not allowed
|
||||||
|
|
||||||
|
checkException(
|
||||||
|
BindException.class, () -> {
|
||||||
|
var path = Files.createFile(Path.of("moo.sock"));
|
||||||
|
var addr = UnixDomainSocketAddress.of(path);
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
try {
|
||||||
|
server.bind(addr);
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// client bind to existing name: not allowed
|
||||||
|
checkException(
|
||||||
|
BindException.class, () -> {
|
||||||
|
var path = Path.of("temp.sock");
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
Files.createFile(path);
|
||||||
|
var addr = UnixDomainSocketAddress.of(path);
|
||||||
|
client = SocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
try {
|
||||||
|
client.bind(addr);
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// bind and connect to name of close to max size
|
||||||
|
checkNormal(() -> {
|
||||||
|
int len = 100;
|
||||||
|
char[] chars = new char[len];
|
||||||
|
Arrays.fill(chars, 'x');
|
||||||
|
String name = new String(chars);
|
||||||
|
UnixDomainSocketAddress address = UnixDomainSocketAddress.of(name);
|
||||||
|
ServerSocketChannel server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(address);
|
||||||
|
SocketChannel client = SocketChannel.open(address);
|
||||||
|
assertAddress(server.getLocalAddress(), address, "server");
|
||||||
|
assertAddress(client.getRemoteAddress(), address, "client");
|
||||||
|
Files.delete(address.getPath());
|
||||||
|
});
|
||||||
|
|
||||||
|
// implicit server bind
|
||||||
|
checkNormal(() -> {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(null);
|
||||||
|
UnixDomainSocketAddress usa = (UnixDomainSocketAddress)server.getLocalAddress();
|
||||||
|
client = SocketChannel.open(usa);
|
||||||
|
accept1 = server.accept();
|
||||||
|
assertAddress(client.getRemoteAddress(), usa, "server");
|
||||||
|
Files.delete(usa.getPath());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
1243
test/jdk/java/nio/channels/unixdomain/IOExchanges.java
Normal file
1243
test/jdk/java/nio/channels/unixdomain/IOExchanges.java
Normal file
File diff suppressed because it is too large
Load Diff
65
test/jdk/java/nio/channels/unixdomain/NonBlockingAccept.java
Normal file
65
test/jdk/java/nio/channels/unixdomain/NonBlockingAccept.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8245194
|
||||||
|
* @library /test/lib
|
||||||
|
* @run main/othervm NonBlockingAccept
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import jtreg.SkippedException;
|
||||||
|
|
||||||
|
public class NonBlockingAccept {
|
||||||
|
|
||||||
|
static void checkSupported() {
|
||||||
|
try {
|
||||||
|
SocketChannel.open(StandardProtocolFamily.UNIX).close();
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
throw new SkippedException("Unix domain sockets not supported");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
checkSupported();
|
||||||
|
|
||||||
|
try (ServerSocketChannel serverSocketChannel =
|
||||||
|
ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
|
||||||
|
//non blocking mode
|
||||||
|
serverSocketChannel.configureBlocking(false);
|
||||||
|
serverSocketChannel.bind(null);
|
||||||
|
SocketChannel socketChannel = serverSocketChannel.accept();
|
||||||
|
System.out.println("The socketChannel is : expected Null " + socketChannel);
|
||||||
|
if (socketChannel != null)
|
||||||
|
throw new RuntimeException("expected null");
|
||||||
|
// or exception could be thrown otherwise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
56
test/jdk/java/nio/channels/unixdomain/NullTest.java
Normal file
56
test/jdk/java/nio/channels/unixdomain/NullTest.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8245194
|
||||||
|
* @run testng NullTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.ProtocolFamily;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.assertThrows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for NPE
|
||||||
|
*/
|
||||||
|
public class NullTest {
|
||||||
|
|
||||||
|
// Expected exception
|
||||||
|
private static final Class<NullPointerException> NPE =
|
||||||
|
NullPointerException.class;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public static void runTest() throws Exception {
|
||||||
|
assertThrows(NPE, () -> SocketChannel.open((ProtocolFamily)null));
|
||||||
|
assertThrows(NPE, () -> SocketChannel.open((SocketAddress)null));
|
||||||
|
assertThrows(NPE, () -> ServerSocketChannel.open((ProtocolFamily)null));
|
||||||
|
assertThrows(NPE, () -> UnixDomainSocketAddress.of((Path)null));
|
||||||
|
assertThrows(NPE, () -> UnixDomainSocketAddress.of((String)null));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
196
test/jdk/java/nio/channels/unixdomain/Security.java
Normal file
196
test/jdk/java/nio/channels/unixdomain/Security.java
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8245194
|
||||||
|
* @run main/othervm/java.security.policy=policy1 Security policy1
|
||||||
|
* @run main/othervm/java.security.policy=policy2 Security policy2
|
||||||
|
* @run main/othervm Security policy3
|
||||||
|
* @summary Security test for Unix Domain socket and server socket channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import static java.net.StandardProtocolFamily.UNIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests required all with security manager
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Security {
|
||||||
|
|
||||||
|
static interface Command {
|
||||||
|
public void run() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T extends Exception> void call(Command r, Class<? extends Exception> expectedException) {
|
||||||
|
boolean threw = false;
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
if (expectedException == null) {
|
||||||
|
t.printStackTrace();
|
||||||
|
throw new RuntimeException("an exception was thrown but was not expected");
|
||||||
|
}
|
||||||
|
threw = true;
|
||||||
|
if (!(expectedException.isAssignableFrom(t.getClass()))) {
|
||||||
|
throw new RuntimeException("wrong exception type thrown " + t.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expectedException != null && !threw) {
|
||||||
|
// should have thrown
|
||||||
|
throw new RuntimeException("% was expected".formatted(expectedException.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
try {
|
||||||
|
SocketChannel.open(UNIX);
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
System.out.println("Unix domain not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String policy = args[0];
|
||||||
|
switch (policy) {
|
||||||
|
case "policy1":
|
||||||
|
testPolicy1();
|
||||||
|
break;
|
||||||
|
case "policy2":
|
||||||
|
testPolicy2();
|
||||||
|
break;
|
||||||
|
case "policy3":
|
||||||
|
testPolicy3();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setSecurityManager(String policy) {
|
||||||
|
String testSrc = System.getProperty("test.src");
|
||||||
|
// Three /// required for Windows below
|
||||||
|
String policyURL = "file:///" + testSrc + File.separator + policy;
|
||||||
|
System.out.println("POLICY: " + policyURL);
|
||||||
|
System.setProperty("java.security.policy", policyURL);
|
||||||
|
System.setSecurityManager(new SecurityManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close(NetworkChannel... channels) {
|
||||||
|
|
||||||
|
for (NetworkChannel chan : channels) {
|
||||||
|
try {
|
||||||
|
chan.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Class<SecurityException> SE = SecurityException.class;
|
||||||
|
private static final Class<IOException> IOE = IOException.class;
|
||||||
|
|
||||||
|
// No permission
|
||||||
|
|
||||||
|
public static void testPolicy1() throws Exception {
|
||||||
|
Path servername = Path.of("sock");
|
||||||
|
Files.deleteIfExists(servername);
|
||||||
|
// Permission exists to bind a ServerSocketChannel
|
||||||
|
final UnixDomainSocketAddress saddr = UnixDomainSocketAddress.of(servername);
|
||||||
|
try (final ServerSocketChannel server = ServerSocketChannel.open(UNIX)) {
|
||||||
|
try (final SocketChannel client = SocketChannel.open(UNIX)) {
|
||||||
|
call(() -> {
|
||||||
|
server.bind(saddr);
|
||||||
|
}, SE);
|
||||||
|
call(() -> {
|
||||||
|
client.connect(saddr);
|
||||||
|
}, SE);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(servername);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All permissions
|
||||||
|
|
||||||
|
public static void testPolicy2() throws Exception {
|
||||||
|
Path servername = Path.of("sock");
|
||||||
|
Files.deleteIfExists(servername);
|
||||||
|
final UnixDomainSocketAddress saddr = UnixDomainSocketAddress.of(servername);
|
||||||
|
try (final ServerSocketChannel server = ServerSocketChannel.open(UNIX)) {
|
||||||
|
try (final SocketChannel client = SocketChannel.open(UNIX)) {
|
||||||
|
call(() -> {
|
||||||
|
server.bind(saddr);
|
||||||
|
}, null);
|
||||||
|
call(() -> {
|
||||||
|
client.connect(saddr);
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(servername);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testPolicy3() throws Exception {
|
||||||
|
Path sock1 = Path.of("sock3");
|
||||||
|
Files.deleteIfExists(sock1);
|
||||||
|
final UnixDomainSocketAddress saddr = UnixDomainSocketAddress.of(sock1);
|
||||||
|
try (var s1 = ServerSocketChannel.open(UNIX)) {
|
||||||
|
s1.bind(saddr);
|
||||||
|
try (var s2 = ServerSocketChannel.open(UNIX)) {
|
||||||
|
s2.bind(null);
|
||||||
|
var add2 = (UnixDomainSocketAddress)s2.getLocalAddress();
|
||||||
|
saddr.getPath().toFile().deleteOnExit();
|
||||||
|
add2.getPath().toFile().deleteOnExit();
|
||||||
|
|
||||||
|
// Now set security manager and check if we can see addresses
|
||||||
|
|
||||||
|
setSecurityManager("policy3");
|
||||||
|
|
||||||
|
if (((UnixDomainSocketAddress)s1
|
||||||
|
.getLocalAddress())
|
||||||
|
.getPath()
|
||||||
|
.toString()
|
||||||
|
.length() != 0)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("address should have been empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((UnixDomainSocketAddress)s2
|
||||||
|
.getLocalAddress())
|
||||||
|
.getPath()
|
||||||
|
.toString()
|
||||||
|
.length() != 0)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("address should have been empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
123
test/jdk/java/nio/channels/unixdomain/Shutdown.java
Normal file
123
test/jdk/java/nio/channels/unixdomain/Shutdown.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8245194
|
||||||
|
* @run main/othervm Shutdown
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that half close works
|
||||||
|
*/
|
||||||
|
public class Shutdown {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
if (!supported()) {
|
||||||
|
System.out.println("Unix domain channels not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean supported() {
|
||||||
|
try {
|
||||||
|
SocketChannel.open(StandardProtocolFamily.UNIX).close();
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return true; // continue test to see what problem is
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertTrue(boolean condition, String error) {
|
||||||
|
if (!condition)
|
||||||
|
throw new RuntimeException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void runTest() throws IOException {
|
||||||
|
ServerSocketChannel server = null;
|
||||||
|
SocketChannel client = null;
|
||||||
|
SocketChannel acceptee = null;
|
||||||
|
UnixDomainSocketAddress usa = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
server.bind(null);
|
||||||
|
usa = (UnixDomainSocketAddress)server.getLocalAddress();
|
||||||
|
System.out.println("Local address " + usa);
|
||||||
|
client = SocketChannel.open(usa);
|
||||||
|
acceptee = server.accept();
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap("Hello world".getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
ByteBuffer rx = ByteBuffer.allocate(buf.capacity());
|
||||||
|
client.write(buf);
|
||||||
|
buf.rewind();
|
||||||
|
while (rx.hasRemaining())
|
||||||
|
acceptee.read(rx);
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals(buf.array(), rx.array()), "array contents not equal");
|
||||||
|
|
||||||
|
client.shutdownOutput();
|
||||||
|
try {
|
||||||
|
client.write(buf);
|
||||||
|
throw new RuntimeException("shutdown error");
|
||||||
|
} catch (ClosedChannelException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
rx.clear();
|
||||||
|
int c = acceptee.read(rx);
|
||||||
|
assertTrue(c == -1, "read after remote shutdown");
|
||||||
|
|
||||||
|
client.configureBlocking(false);
|
||||||
|
c = client.read(rx);
|
||||||
|
assertTrue(c == 0, "expected c == 0");
|
||||||
|
client.shutdownInput();
|
||||||
|
c = client.read(rx);
|
||||||
|
assertTrue(c == -1, "expected c == -1");
|
||||||
|
} finally {
|
||||||
|
close(server);
|
||||||
|
close(client);
|
||||||
|
close(acceptee);
|
||||||
|
if (usa != null)
|
||||||
|
Files.delete(usa.getPath());
|
||||||
|
}
|
||||||
|
System.out.println("OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close(Closeable c) {
|
||||||
|
try {
|
||||||
|
if (c != null)
|
||||||
|
c.close();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
}
|
||||||
|
}
|
139
test/jdk/java/nio/channels/unixdomain/SocketOptions.java
Normal file
139
test/jdk/java/nio/channels/unixdomain/SocketOptions.java
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8245194
|
||||||
|
* @run main/othervm SocketOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Set;
|
||||||
|
import jdk.net.UnixDomainPrincipal;
|
||||||
|
import static jdk.net.ExtendedSocketOptions.SO_PEERCRED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that all supported options can actually be set and got
|
||||||
|
*/
|
||||||
|
public class SocketOptions {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
if (!supported()) {
|
||||||
|
System.out.println("Unix domain channels not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
test(ServerSocketChannel.open(StandardProtocolFamily.UNIX));
|
||||||
|
test(SocketChannel.open(StandardProtocolFamily.UNIX));
|
||||||
|
testPeerCred();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testPeerCred() throws Exception {
|
||||||
|
UnixDomainSocketAddress addr = null;
|
||||||
|
UnixDomainPrincipal p;
|
||||||
|
try (ServerSocketChannel s = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
|
||||||
|
s.bind(null);
|
||||||
|
addr = (UnixDomainSocketAddress)s.getLocalAddress();
|
||||||
|
try (SocketChannel c = SocketChannel.open(addr)) {
|
||||||
|
if (!c.supportedOptions().contains(SO_PEERCRED)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Files.deleteIfExists(addr.getPath());
|
||||||
|
p = c.getOption(SO_PEERCRED);
|
||||||
|
String s1 = p.user().getName();
|
||||||
|
System.out.println(s1);
|
||||||
|
System.out.println(p.group().getName());
|
||||||
|
String s2 = System.getProperty("user.name");
|
||||||
|
|
||||||
|
// Check returned user name
|
||||||
|
|
||||||
|
if (!s1.equals(s2)) {
|
||||||
|
throw new RuntimeException("wrong username");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try setting the option: Read only
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.setOption(SO_PEERCRED, p);
|
||||||
|
throw new RuntimeException("should have thrown SocketException");
|
||||||
|
} catch (SocketException e) {}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (addr != null)
|
||||||
|
Files.deleteIfExists(addr.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getting from unconnected socket
|
||||||
|
|
||||||
|
try (var c = SocketChannel.open(StandardProtocolFamily.UNIX)) {
|
||||||
|
try {
|
||||||
|
p = c.getOption(SO_PEERCRED);
|
||||||
|
System.out.println(p.user());
|
||||||
|
throw new RuntimeException("should have thrown SocketException");
|
||||||
|
} catch (SocketException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getting from ServerSocketChannel
|
||||||
|
|
||||||
|
try (var server = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
|
||||||
|
try {
|
||||||
|
p = server.getOption(SO_PEERCRED);
|
||||||
|
System.out.println(p.user());
|
||||||
|
throw new RuntimeException("should have thrown USE");
|
||||||
|
} catch (UnsupportedOperationException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean supported() {
|
||||||
|
try {
|
||||||
|
SocketChannel.open(StandardProtocolFamily.UNIX).close();
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return true; // continue test to see what problem is
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void test(NetworkChannel chan) throws IOException {
|
||||||
|
System.out.println("Checking: " + chan.getClass());
|
||||||
|
Set<SocketOption<?>> supported = chan.supportedOptions();
|
||||||
|
for (SocketOption<?> option : supported) {
|
||||||
|
String name = option.name();
|
||||||
|
System.out.println("Checking option " + name);
|
||||||
|
if (option.type() == Boolean.class) {
|
||||||
|
chan.setOption((SocketOption<Boolean>)option, true);
|
||||||
|
chan.setOption((SocketOption<Boolean>)option, false);
|
||||||
|
chan.getOption(option);
|
||||||
|
} else if (option.type() == Integer.class) {
|
||||||
|
chan.setOption((SocketOption<Integer>)option, 10);
|
||||||
|
chan.getOption(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
test/jdk/java/nio/channels/unixdomain/policy1
Normal file
26
test/jdk/java/nio/channels/unixdomain/policy1
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
grant {
|
||||||
|
// No permission
|
||||||
|
permission java.io.FilePermission "sock", "delete";
|
||||||
|
};
|
28
test/jdk/java/nio/channels/unixdomain/policy2
Normal file
28
test/jdk/java/nio/channels/unixdomain/policy2
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
grant {
|
||||||
|
// permission to bind a SocketChannel in sockets directory
|
||||||
|
permission java.net.NetPermission "accessUnixDomainSocket";
|
||||||
|
|
||||||
|
permission java.io.FilePermission "sock", "delete";
|
||||||
|
};
|
26
test/jdk/java/nio/channels/unixdomain/policy3
Normal file
26
test/jdk/java/nio/channels/unixdomain/policy3
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
grant {
|
||||||
|
// No permission
|
||||||
|
permission java.io.FilePermission "sock", "delete";
|
||||||
|
};
|
193
test/micro/org/openjdk/bench/java/net/SocketChannelCompare.java
Normal file
193
test/micro/org/openjdk/bench/java/net/SocketChannelCompare.java
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.java.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests sending a 128 byte message on a second, to a thread which
|
||||||
|
* echo's it back and received by the original thread.
|
||||||
|
* Benchmark is performed for "inet" channels over TCP/IP
|
||||||
|
* and "unix" domain channels.
|
||||||
|
*/
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
public class SocketChannelCompare {
|
||||||
|
|
||||||
|
static final int BUFSIZE = 128; // message size sent and received
|
||||||
|
private ServerSocketChannel ssc;
|
||||||
|
private SocketChannel s1, s2;
|
||||||
|
private EchoThread rt;
|
||||||
|
private ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
|
||||||
|
|
||||||
|
private static volatile String tempDir;
|
||||||
|
private static final AtomicInteger count = new AtomicInteger(0);
|
||||||
|
private volatile Path socket;
|
||||||
|
|
||||||
|
@Param({"inet", "unix"})
|
||||||
|
private volatile String family;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Path p = Files.createTempDirectory("readWriteTest");
|
||||||
|
tempDir = p.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
tempDir = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerSocketChannel getServerSocketChannel() throws IOException {
|
||||||
|
if (family.equals("inet"))
|
||||||
|
return getInetServerSocketChannel();
|
||||||
|
else if (family.equals("unix"))
|
||||||
|
return getUnixServerSocketChannel();
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ServerSocketChannel getInetServerSocketChannel() throws IOException {
|
||||||
|
InetAddress iaddr = InetAddress.getLoopbackAddress();
|
||||||
|
return ServerSocketChannel.open().bind(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerSocketChannel getUnixServerSocketChannel() throws IOException {
|
||||||
|
int next = count.incrementAndGet();
|
||||||
|
socket = Paths.get(tempDir, Integer.toString(next));
|
||||||
|
UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket);
|
||||||
|
return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void beforeRun() throws IOException {
|
||||||
|
ssc = getServerSocketChannel();
|
||||||
|
s1 = SocketChannel.open(ssc.getLocalAddress());
|
||||||
|
s2 = ssc.accept();
|
||||||
|
|
||||||
|
rt = new EchoThread(s2);
|
||||||
|
rt.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown(Level.Trial)
|
||||||
|
public void afterRun() throws IOException, InterruptedException {
|
||||||
|
s1.close();
|
||||||
|
s2.close();
|
||||||
|
ssc.close();
|
||||||
|
if (family.equals("unix")) {
|
||||||
|
Files.delete(socket);
|
||||||
|
Files.delete(Path.of(tempDir));
|
||||||
|
}
|
||||||
|
rt.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void test() throws IOException {
|
||||||
|
bb.position(0).limit(BUFSIZE);
|
||||||
|
s1.write(bb);
|
||||||
|
bb.clear();
|
||||||
|
readFully(s1, bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read until buf is full, or EOF. Always returns number of bytes read
|
||||||
|
|
||||||
|
static int readFully(SocketChannel chan, ByteBuffer buf) throws IOException {
|
||||||
|
int n = buf.remaining();
|
||||||
|
int count = 0;
|
||||||
|
while (n > 0) {
|
||||||
|
int c = chan.read(buf);
|
||||||
|
if (c == -1)
|
||||||
|
return count;
|
||||||
|
n -= c;
|
||||||
|
count += c;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class EchoThread extends Thread {
|
||||||
|
private SocketChannel sc;
|
||||||
|
|
||||||
|
public EchoThread(SocketChannel s2) {
|
||||||
|
this.sc = s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
|
||||||
|
while (true) {
|
||||||
|
bb.clear();
|
||||||
|
int c = readFully(sc, bb);
|
||||||
|
if (c == 0) {
|
||||||
|
sc.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bb.flip();
|
||||||
|
sc.write(bb);
|
||||||
|
}
|
||||||
|
} catch (ClosedChannelException ex) {
|
||||||
|
// shutdown time
|
||||||
|
} catch (IOException ioex) {
|
||||||
|
ioex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws RunnerException {
|
||||||
|
Options opt = new OptionsBuilder()
|
||||||
|
.include(org.openjdk.bench.java.net.SocketChannelCompare.class.getSimpleName())
|
||||||
|
.warmupForks(1)
|
||||||
|
.warmupIterations(2)
|
||||||
|
.measurementIterations(2)
|
||||||
|
.forks(2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
new Runner(opt).run();
|
||||||
|
|
||||||
|
opt = new OptionsBuilder()
|
||||||
|
.include(org.openjdk.bench.java.net.SocketChannelCompare.class.getSimpleName())
|
||||||
|
.warmupForks(1)
|
||||||
|
.warmupIterations(2)
|
||||||
|
.measurementIterations(2)
|
||||||
|
.jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true")
|
||||||
|
.forks(3)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
new Runner(opt).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.java.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.RunnerException;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures connection setup times
|
||||||
|
*/
|
||||||
|
@BenchmarkMode(Mode.SingleShotTime)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
public class SocketChannelConnectionSetup {
|
||||||
|
|
||||||
|
private ServerSocketChannel ssc;
|
||||||
|
private SocketChannel s1, s2;
|
||||||
|
|
||||||
|
private static volatile String tempDir;
|
||||||
|
private static final AtomicInteger count = new AtomicInteger(0);
|
||||||
|
private volatile Path socket;
|
||||||
|
|
||||||
|
@Param({"inet", "unix"})
|
||||||
|
private volatile String family;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Path p = Files.createTempDirectory("readWriteTest");
|
||||||
|
tempDir = p.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
tempDir = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerSocketChannel getServerSocketChannel() throws IOException {
|
||||||
|
if (family.equals("inet"))
|
||||||
|
return getInetServerSocketChannel();
|
||||||
|
else if (family.equals("unix"))
|
||||||
|
return getUnixServerSocketChannel();
|
||||||
|
throw new InternalError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ServerSocketChannel getInetServerSocketChannel() throws IOException {
|
||||||
|
InetAddress iaddr = InetAddress.getLoopbackAddress();
|
||||||
|
return ServerSocketChannel.open().bind(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerSocketChannel getUnixServerSocketChannel() throws IOException {
|
||||||
|
int next = count.incrementAndGet();
|
||||||
|
socket = Paths.get(tempDir, Integer.toString(next));
|
||||||
|
UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket);
|
||||||
|
return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void beforeRun() throws IOException {
|
||||||
|
ssc = getServerSocketChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown(Level.Trial)
|
||||||
|
public void afterRun() throws IOException, InterruptedException {
|
||||||
|
ssc.close();
|
||||||
|
if (family.equals("unix")) {
|
||||||
|
Files.delete(socket);
|
||||||
|
Files.delete(Path.of(tempDir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
@Measurement(iterations = 5, batchSize=200)
|
||||||
|
public void test() throws IOException {
|
||||||
|
s1 = SocketChannel.open(ssc.getLocalAddress());
|
||||||
|
s2 = ssc.accept();
|
||||||
|
s1.close();
|
||||||
|
s2.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws RunnerException {
|
||||||
|
Options opt = new OptionsBuilder()
|
||||||
|
.include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName())
|
||||||
|
.warmupForks(1)
|
||||||
|
.forks(2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
new Runner(opt).run();
|
||||||
|
|
||||||
|
opt = new OptionsBuilder()
|
||||||
|
.include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName())
|
||||||
|
.jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true")
|
||||||
|
.warmupForks(1)
|
||||||
|
.forks(2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
new Runner(opt).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package org.openjdk.bench.java.net;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.StandardProtocolFamily;
|
||||||
|
import java.net.UnixDomainSocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the overheads of I/O API.
|
||||||
|
* This test is known to depend heavily on network conditions and paltform.
|
||||||
|
*/
|
||||||
|
@BenchmarkMode(Mode.Throughput)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@State(Scope.Thread)
|
||||||
|
public class UnixSocketChannelReadWrite {
|
||||||
|
|
||||||
|
private ServerSocketChannel ssc;
|
||||||
|
private SocketChannel s1, s2;
|
||||||
|
private ReadThread rt;
|
||||||
|
private ByteBuffer bb = ByteBuffer.allocate(1);
|
||||||
|
|
||||||
|
private static volatile String tempDir;
|
||||||
|
private static final AtomicInteger count = new AtomicInteger(0);
|
||||||
|
private volatile Path socket;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Path p = Files.createTempDirectory("readWriteTest");
|
||||||
|
tempDir = p.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
tempDir = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServerSocketChannel getServerSocketChannel() throws IOException {
|
||||||
|
int next = count.incrementAndGet();
|
||||||
|
socket = Paths.get(tempDir, Integer.toString(next));
|
||||||
|
UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket);
|
||||||
|
ServerSocketChannel c = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||||
|
c.bind(addr);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void beforeRun() throws IOException {
|
||||||
|
ssc = getServerSocketChannel();
|
||||||
|
s1 = SocketChannel.open(ssc.getLocalAddress());
|
||||||
|
s2 = ssc.accept();
|
||||||
|
|
||||||
|
rt = new ReadThread(s2);
|
||||||
|
rt.start();
|
||||||
|
|
||||||
|
bb.put((byte) 47);
|
||||||
|
bb.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown(Level.Trial)
|
||||||
|
public void afterRun() throws IOException, InterruptedException {
|
||||||
|
s1.close();
|
||||||
|
s2.close();
|
||||||
|
ssc.close();
|
||||||
|
Files.delete(socket);
|
||||||
|
Files.delete(Path.of(tempDir));
|
||||||
|
rt.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void test() throws IOException {
|
||||||
|
s1.write(bb);
|
||||||
|
bb.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ReadThread extends Thread {
|
||||||
|
private SocketChannel sc;
|
||||||
|
|
||||||
|
public ReadThread(SocketChannel s2) {
|
||||||
|
this.sc = s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
ByteBuffer bb = ByteBuffer.allocate(1);
|
||||||
|
while (sc.read(bb) > 0) {
|
||||||
|
bb.flip();
|
||||||
|
}
|
||||||
|
} catch (ClosedChannelException ex) {
|
||||||
|
// shutdown time
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user