mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8245194: Unix domain socket channel implementation
Reviewed-by: erikj, dfuchs, alanb, chegar
This commit is contained in:
parent
8bde2f4e3d
commit
6bb7e45e8e
73 changed files with 5434 additions and 1116 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -48,6 +48,7 @@ public abstract class ExtendedSocketOptions {
|
|||
private final Set<SocketOption<?>> datagramOptions;
|
||||
private final Set<SocketOption<?>> clientStreamOptions;
|
||||
private final Set<SocketOption<?>> serverStreamOptions;
|
||||
private final Set<SocketOption<?>> unixDomainClientOptions;
|
||||
|
||||
/** Tells whether or not the option is supported. */
|
||||
public final boolean isOptionSupported(SocketOption<?> option) {
|
||||
|
@ -73,6 +74,19 @@ public abstract class ExtendedSocketOptions {
|
|||
return getInstance().options0(SOCK_STREAM, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the, possibly empty, set of extended socket options available for
|
||||
* Unix domain client sockets. Note, there are no extended
|
||||
* Unix domain server options.
|
||||
*/
|
||||
private final Set<SocketOption<?>> unixDomainClientOptions() {
|
||||
return unixDomainClientOptions;
|
||||
}
|
||||
|
||||
public static Set<SocketOption<?>> unixDomainSocketOptions() {
|
||||
return getInstance().unixDomainClientOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (possibly empty) set of extended socket options for
|
||||
* datagram-oriented sockets.
|
||||
|
@ -82,14 +96,22 @@ public abstract class ExtendedSocketOptions {
|
|||
}
|
||||
|
||||
private static boolean isDatagramOption(SocketOption<?> option) {
|
||||
return !option.name().startsWith("TCP_");
|
||||
if (option.name().startsWith("TCP_") || isUnixDomainOption(option)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isUnixDomainOption(SocketOption<?> option) {
|
||||
return option.name().equals("SO_PEERCRED");
|
||||
}
|
||||
|
||||
private static boolean isStreamOption(SocketOption<?> option, boolean server) {
|
||||
if (server && "SO_FLOW_SLA".equals(option.name())) {
|
||||
if (option.name().startsWith("UDP_") || isUnixDomainOption(option)) {
|
||||
return false;
|
||||
} else {
|
||||
return !option.name().startsWith("UDP_");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,6 +144,7 @@ public abstract class ExtendedSocketOptions {
|
|||
var datagramOptions = new HashSet<SocketOption<?>>();
|
||||
var serverStreamOptions = new HashSet<SocketOption<?>>();
|
||||
var clientStreamOptions = new HashSet<SocketOption<?>>();
|
||||
var unixDomainClientOptions = new HashSet<SocketOption<?>>();
|
||||
for (var option : options) {
|
||||
if (isDatagramOption(option)) {
|
||||
datagramOptions.add(option);
|
||||
|
@ -132,10 +155,14 @@ public abstract class ExtendedSocketOptions {
|
|||
if (isStreamOption(option, false)) {
|
||||
clientStreamOptions.add(option);
|
||||
}
|
||||
if (isUnixDomainOption(option)) {
|
||||
unixDomainClientOptions.add(option);
|
||||
}
|
||||
}
|
||||
this.datagramOptions = Set.copyOf(datagramOptions);
|
||||
this.serverStreamOptions = Set.copyOf(serverStreamOptions);
|
||||
this.clientStreamOptions = Set.copyOf(clientStreamOptions);
|
||||
this.unixDomainClientOptions = Set.copyOf(unixDomainClientOptions);
|
||||
}
|
||||
|
||||
private static volatile ExtendedSocketOptions instance;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -28,6 +28,8 @@ package sun.net.util;
|
|||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnixDomainSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
|
@ -51,11 +53,22 @@ public final class SocketExceptions {
|
|||
*
|
||||
* Only specific IOException subtypes are supported.
|
||||
*/
|
||||
public static IOException of(IOException e, InetSocketAddress address) {
|
||||
if (!enhancedExceptionText || address == null)
|
||||
public static IOException of(IOException e, SocketAddress addr) {
|
||||
if (!enhancedExceptionText || addr == null) {
|
||||
return e;
|
||||
int port = address.getPort();
|
||||
String host = address.getHostString();
|
||||
}
|
||||
if (addr instanceof UnixDomainSocketAddress) {
|
||||
return ofUnixDomain(e, (UnixDomainSocketAddress)addr);
|
||||
} else if (addr instanceof InetSocketAddress) {
|
||||
return ofInet(e, (InetSocketAddress)addr);
|
||||
} else {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
private static IOException ofInet(IOException e, InetSocketAddress addr) {
|
||||
int port = addr.getPort();
|
||||
String host = addr.getHostString();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(e.getMessage());
|
||||
sb.append(": ");
|
||||
|
@ -66,6 +79,16 @@ public final class SocketExceptions {
|
|||
return create(e, enhancedMsg);
|
||||
}
|
||||
|
||||
private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) {
|
||||
String path = addr.getPath().toString();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(e.getMessage());
|
||||
sb.append(": ");
|
||||
sb.append(path);
|
||||
String enhancedMsg = sb.toString();
|
||||
return create(e, enhancedMsg);
|
||||
}
|
||||
|
||||
// return a new instance of the same type with the given detail
|
||||
// msg, or if the type doesn't support detail msgs, return given
|
||||
// instance.
|
||||
|
|
|
@ -226,29 +226,31 @@ public class Net {
|
|||
/**
|
||||
* Returns the local address after performing a SecurityManager#checkConnect.
|
||||
*/
|
||||
static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
|
||||
static InetSocketAddress getRevealedLocalAddress(SocketAddress sa) {
|
||||
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (addr == null || sm == null)
|
||||
return addr;
|
||||
|
||||
try{
|
||||
sm.checkConnect(addr.getAddress().getHostAddress(), -1);
|
||||
// Security check passed
|
||||
} catch (SecurityException e) {
|
||||
// Return loopback address only if security check fails
|
||||
addr = getLoopbackAddress(addr.getPort());
|
||||
if (isa != null && sm != null) {
|
||||
try {
|
||||
sm.checkConnect(isa.getAddress().getHostAddress(), -1);
|
||||
} catch (SecurityException e) {
|
||||
// Return loopback address only if security check fails
|
||||
isa = getLoopbackAddress(isa.getPort());
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
return isa;
|
||||
}
|
||||
|
||||
static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
|
||||
return System.getSecurityManager() == null ? addr.toString() :
|
||||
getLoopbackAddress(addr.getPort()).toString();
|
||||
static String getRevealedLocalAddressAsString(SocketAddress sa) {
|
||||
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||
if (System.getSecurityManager() == null) {
|
||||
return isa.toString();
|
||||
} else {
|
||||
return getLoopbackAddress(isa.getPort()).toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static InetSocketAddress getLoopbackAddress(int port) {
|
||||
return new InetSocketAddress(InetAddress.getLoopbackAddress(),
|
||||
port);
|
||||
return new InetSocketAddress(InetAddress.getLoopbackAddress(), port);
|
||||
}
|
||||
|
||||
private static final InetAddress anyLocalInet4Address;
|
||||
|
@ -574,6 +576,13 @@ public class Net {
|
|||
return connect0(preferIPv6, fd, remote, remotePort);
|
||||
}
|
||||
|
||||
static int connect(ProtocolFamily family, FileDescriptor fd, SocketAddress remote)
|
||||
throws IOException
|
||||
{
|
||||
InetSocketAddress isa = (InetSocketAddress) remote;
|
||||
return connect(family, fd, isa.getAddress(), isa.getPort());
|
||||
}
|
||||
|
||||
private static native int connect0(boolean preferIPv6,
|
||||
FileDescriptor fd,
|
||||
InetAddress remote,
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Provides access to implementation private constructors and methods.
|
||||
*/
|
||||
|
||||
public final class Secrets {
|
||||
private Secrets() { }
|
||||
|
||||
private static SelectorProvider provider() {
|
||||
SelectorProvider p = SelectorProvider.provider();
|
||||
if (!(p instanceof SelectorProviderImpl))
|
||||
throw new UnsupportedOperationException();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static SocketChannel newSocketChannel(FileDescriptor fd) {
|
||||
try {
|
||||
return new SocketChannelImpl(provider(), fd, false);
|
||||
} catch (IOException ioe) {
|
||||
throw new AssertionError(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
|
||||
try {
|
||||
return new ServerSocketChannelImpl(provider(), fd, false);
|
||||
} catch (IOException ioe) {
|
||||
throw new AssertionError(ioe);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,6 +33,10 @@ import java.nio.channels.ServerSocketChannel;
|
|||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.Objects;
|
||||
import static java.net.StandardProtocolFamily.INET;
|
||||
import static java.net.StandardProtocolFamily.INET6;
|
||||
import static java.net.StandardProtocolFamily.UNIX;
|
||||
|
||||
public abstract class SelectorProviderImpl
|
||||
extends SelectorProvider
|
||||
|
@ -75,11 +79,29 @@ public abstract class SelectorProviderImpl
|
|||
|
||||
@Override
|
||||
public SocketChannel openSocketChannel(ProtocolFamily family) throws IOException {
|
||||
return new SocketChannelImpl(this, family);
|
||||
Objects.requireNonNull(family, "'family' is null");
|
||||
if (family == INET6 && !Net.isIPv6Available()) {
|
||||
throw new UnsupportedOperationException("IPv6 not available");
|
||||
} else if (family == INET || family == INET6) {
|
||||
return new SocketChannelImpl(this, family);
|
||||
} else if (family == UNIX && UnixDomainSockets.isSupported()) {
|
||||
return new SocketChannelImpl(this, family);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Protocol family not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) {
|
||||
return new ServerSocketChannelImpl(this, family);
|
||||
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) throws IOException {
|
||||
Objects.requireNonNull(family, "'family' is null");
|
||||
if (family == INET6 && !Net.isIPv6Available()) {
|
||||
throw new UnsupportedOperationException("IPv6 not available");
|
||||
} else if (family == INET || family == INET6) {
|
||||
return new ServerSocketChannelImpl(this, family);
|
||||
} else if (family == UNIX && UnixDomainSockets.isSupported()) {
|
||||
return new ServerSocketChannelImpl(this, family);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Protocol family not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -93,7 +93,7 @@ class ServerSocketAdaptor // package-private
|
|||
|
||||
@Override
|
||||
public InetAddress getInetAddress() {
|
||||
InetSocketAddress local = ssc.localAddress();
|
||||
SocketAddress local = ssc.localAddress();
|
||||
if (local == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -103,7 +103,7 @@ class ServerSocketAdaptor // package-private
|
|||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
InetSocketAddress local = ssc.localAddress();
|
||||
InetSocketAddress local = (InetSocketAddress) ssc.localAddress();
|
||||
if (local == null) {
|
||||
return -1;
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -27,14 +27,15 @@ package sun.nio.ch;
|
|||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.BindException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketOption;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.net.UnixDomainSocketAddress;
|
||||
import java.nio.channels.AlreadyBoundException;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
|
@ -44,11 +45,15 @@ import java.nio.channels.SelectionKey;
|
|||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import static java.net.StandardProtocolFamily.INET;
|
||||
import static java.net.StandardProtocolFamily.INET6;
|
||||
import static java.net.StandardProtocolFamily.UNIX;
|
||||
|
||||
import sun.net.NetHooks;
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
|
@ -90,7 +95,7 @@ class ServerSocketChannelImpl
|
|||
private long thread;
|
||||
|
||||
// Binding
|
||||
private InetSocketAddress localAddress; // null => unbound
|
||||
private SocketAddress localAddress; // null => unbound
|
||||
|
||||
// set true when exclusive binding is on and SO_REUSEADDR is emulated
|
||||
private boolean isReuseAddress;
|
||||
|
@ -100,47 +105,72 @@ class ServerSocketChannelImpl
|
|||
|
||||
// -- End of fields protected by stateLock
|
||||
|
||||
ServerSocketChannelImpl(SelectorProvider sp) {
|
||||
this(sp, Net.isIPv6Available()
|
||||
? StandardProtocolFamily.INET6
|
||||
: StandardProtocolFamily.INET);
|
||||
ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
|
||||
this(sp, Net.isIPv6Available() ? INET6 : INET);
|
||||
}
|
||||
|
||||
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) {
|
||||
ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
Objects.requireNonNull(family, "'family' is null");
|
||||
|
||||
if ((family != StandardProtocolFamily.INET) &&
|
||||
(family != StandardProtocolFamily.INET6)) {
|
||||
if ((family != INET) && (family != INET6) && (family != UNIX)) {
|
||||
throw new UnsupportedOperationException("Protocol family not supported");
|
||||
}
|
||||
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
|
||||
if (family == INET6 && !Net.isIPv6Available()) {
|
||||
throw new UnsupportedOperationException("IPv6 not available");
|
||||
}
|
||||
|
||||
this.family = family;
|
||||
this.fd = Net.serverSocket(family, true);
|
||||
if (family == UNIX) {
|
||||
this.fd = UnixDomainSockets.socket();
|
||||
} else {
|
||||
this.fd = Net.serverSocket(family, true);
|
||||
}
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
}
|
||||
|
||||
ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
|
||||
ServerSocketChannelImpl(SelectorProvider sp,
|
||||
ProtocolFamily family,
|
||||
FileDescriptor fd,
|
||||
boolean bound)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
|
||||
this.family = Net.isIPv6Available()
|
||||
? StandardProtocolFamily.INET6
|
||||
: StandardProtocolFamily.INET;
|
||||
this.fd = fd;
|
||||
if (family == UNIX) {
|
||||
this.family = UNIX;
|
||||
} else {
|
||||
this.family = Net.isIPv6Available() ? INET6 : INET;
|
||||
}
|
||||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
|
||||
if (bound) {
|
||||
synchronized (stateLock) {
|
||||
localAddress = Net.localAddress(fd);
|
||||
if (family == UNIX) {
|
||||
localAddress = UnixDomainSockets.localAddress(fd);
|
||||
} else {
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this channel is to a INET or INET6 socket.
|
||||
*/
|
||||
private boolean isNetSocket() {
|
||||
return (family == INET) || (family == INET6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this channel is to a UNIX socket.
|
||||
*/
|
||||
boolean isUnixSocket() {
|
||||
return (family == UNIX);
|
||||
}
|
||||
|
||||
// @throws ClosedChannelException if channel is closed
|
||||
private void ensureOpen() throws ClosedChannelException {
|
||||
if (!isOpen())
|
||||
|
@ -150,8 +180,13 @@ class ServerSocketChannelImpl
|
|||
@Override
|
||||
public ServerSocket socket() {
|
||||
synchronized (stateLock) {
|
||||
if (socket == null)
|
||||
socket = ServerSocketAdaptor.create(this);
|
||||
if (socket == null) {
|
||||
if (isNetSocket()) {
|
||||
socket = ServerSocketAdaptor.create(this);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
@ -160,9 +195,11 @@ class ServerSocketChannelImpl
|
|||
public SocketAddress getLocalAddress() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
return (localAddress == null)
|
||||
? null
|
||||
: Net.getRevealedLocalAddress(localAddress);
|
||||
if (isUnixSocket()) {
|
||||
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
|
||||
} else {
|
||||
return Net.getRevealedLocalAddress(localAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,10 +215,11 @@ class ServerSocketChannelImpl
|
|||
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
if (isNetSocket()
|
||||
&& name == StandardSocketOptions.SO_REUSEADDR
|
||||
&& Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean)value;
|
||||
isReuseAddress = (Boolean) value;
|
||||
} else {
|
||||
// no options that require special handling
|
||||
Net.setSocketOption(fd, Net.UNSPEC, name, value);
|
||||
|
@ -201,19 +239,23 @@ class ServerSocketChannelImpl
|
|||
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
if (isNetSocket()
|
||||
&& name == StandardSocketOptions.SO_REUSEADDR
|
||||
&& Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T)Boolean.valueOf(isReuseAddress);
|
||||
return (T) Boolean.valueOf(isReuseAddress);
|
||||
} else {
|
||||
// no options that require special handling
|
||||
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
|
||||
}
|
||||
// no options that require special handling
|
||||
return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DefaultOptionsHolder {
|
||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
||||
static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
|
||||
static final Set<SocketOption<?>> defaultUnixDomainOptions = defaultUnixDomainOptions();
|
||||
|
||||
private static Set<SocketOption<?>> defaultOptions() {
|
||||
private static Set<SocketOption<?>> defaultInetOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
set.add(StandardSocketOptions.SO_REUSEADDR);
|
||||
|
@ -223,11 +265,21 @@ class ServerSocketChannelImpl
|
|||
set.addAll(ExtendedSocketOptions.serverSocketOptions());
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
private static Set<SocketOption<?>> defaultUnixDomainOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Set<SocketOption<?>> supportedOptions() {
|
||||
return DefaultOptionsHolder.defaultOptions;
|
||||
if (isUnixSocket()) {
|
||||
return DefaultOptionsHolder.defaultUnixDomainOptions;
|
||||
} else {
|
||||
return DefaultOptionsHolder.defaultInetOptions;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -236,23 +288,56 @@ class ServerSocketChannelImpl
|
|||
ensureOpen();
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa;
|
||||
if (local == null) {
|
||||
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
|
||||
if (isUnixSocket()) {
|
||||
localAddress = unixBind(local, backlog);
|
||||
} else {
|
||||
isa = Net.checkAddress(local, family);
|
||||
localAddress = netBind(local, backlog);
|
||||
}
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(family, fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private SocketAddress unixBind(SocketAddress local, int backlog) throws IOException {
|
||||
UnixDomainSockets.checkPermission();
|
||||
if (local == null) {
|
||||
// Attempt up to 10 times to find an unused name in temp directory.
|
||||
// If local address supplied then bind called only once
|
||||
boolean bound = false;
|
||||
int attempts = 0;
|
||||
while (attempts < 10 && !bound) {
|
||||
try {
|
||||
Path path = UnixDomainSockets.generateTempName().getPath();
|
||||
UnixDomainSockets.bind(fd, path);
|
||||
bound = true;
|
||||
} catch (BindException e) { }
|
||||
attempts++;
|
||||
}
|
||||
if (!bound)
|
||||
throw new BindException("Could not bind to temporary name");
|
||||
} else {
|
||||
Path path = UnixDomainSockets.checkAddress(local).getPath();
|
||||
UnixDomainSockets.bind(fd, path);
|
||||
}
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
return UnixDomainSockets.localAddress(fd);
|
||||
}
|
||||
|
||||
private SocketAddress netBind(SocketAddress local, int backlog) throws IOException {
|
||||
InetSocketAddress isa;
|
||||
if (local == null) {
|
||||
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
|
||||
} else {
|
||||
isa = Net.checkAddress(local, family);
|
||||
}
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkListen(isa.getPort());
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(family, fd, isa.getAddress(), isa.getPort());
|
||||
Net.listen(fd, backlog < 1 ? 50 : backlog);
|
||||
return Net.localAddress(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of an I/O operation that might block.
|
||||
*
|
||||
|
@ -295,18 +380,18 @@ class ServerSocketChannelImpl
|
|||
public SocketChannel accept() throws IOException {
|
||||
int n = 0;
|
||||
FileDescriptor newfd = new FileDescriptor();
|
||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
||||
SocketAddress[] saa = new SocketAddress[1];
|
||||
|
||||
acceptLock.lock();
|
||||
try {
|
||||
boolean blocking = isBlocking();
|
||||
try {
|
||||
begin(blocking);
|
||||
n = Net.accept(this.fd, newfd, isaa);
|
||||
n = implAccept(this.fd, newfd, saa);
|
||||
if (blocking) {
|
||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||
park(Net.POLLIN);
|
||||
n = Net.accept(this.fd, newfd, isaa);
|
||||
n = implAccept(this.fd, newfd, saa);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
@ -318,12 +403,31 @@ class ServerSocketChannelImpl
|
|||
}
|
||||
|
||||
if (n > 0) {
|
||||
return finishAccept(newfd, isaa[0]);
|
||||
return finishAccept(newfd, saa[0]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa)
|
||||
throws IOException
|
||||
{
|
||||
if (isUnixSocket()) {
|
||||
UnixDomainSockets.checkPermission();
|
||||
String[] pa = new String[1];
|
||||
int n = UnixDomainSockets.accept(fd, newfd, pa);
|
||||
if (n > 0)
|
||||
saa[0] = UnixDomainSocketAddress.of(pa[0]);
|
||||
return n;
|
||||
} else {
|
||||
InetSocketAddress[] issa = new InetSocketAddress[1];
|
||||
int n = Net.accept(fd, newfd, issa);
|
||||
if (n > 0)
|
||||
saa[0] = issa[0];
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a new connection with a given timeout. This method requires the
|
||||
* channel to be configured in blocking mode.
|
||||
|
@ -337,7 +441,7 @@ class ServerSocketChannelImpl
|
|||
SocketChannel blockingAccept(long nanos) throws IOException {
|
||||
int n = 0;
|
||||
FileDescriptor newfd = new FileDescriptor();
|
||||
InetSocketAddress[] isaa = new InetSocketAddress[1];
|
||||
SocketAddress[] saa = new SocketAddress[1];
|
||||
|
||||
acceptLock.lock();
|
||||
try {
|
||||
|
@ -351,14 +455,14 @@ class ServerSocketChannelImpl
|
|||
lockedConfigureBlocking(false);
|
||||
try {
|
||||
long startNanos = System.nanoTime();
|
||||
n = Net.accept(fd, newfd, isaa);
|
||||
n = implAccept(fd, newfd, saa);
|
||||
while (n == IOStatus.UNAVAILABLE && isOpen()) {
|
||||
long remainingNanos = nanos - (System.nanoTime() - startNanos);
|
||||
if (remainingNanos <= 0) {
|
||||
throw new SocketTimeoutException("Accept timed out");
|
||||
}
|
||||
park(Net.POLLIN, remainingNanos);
|
||||
n = Net.accept(fd, newfd, isaa);
|
||||
n = implAccept(fd, newfd, saa);
|
||||
}
|
||||
} finally {
|
||||
// restore socket to blocking mode (if channel is open)
|
||||
|
@ -372,10 +476,10 @@ class ServerSocketChannelImpl
|
|||
}
|
||||
|
||||
assert n > 0;
|
||||
return finishAccept(newfd, isaa[0]);
|
||||
return finishAccept(newfd, saa[0]);
|
||||
}
|
||||
|
||||
private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa)
|
||||
private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
|
@ -383,11 +487,14 @@ class ServerSocketChannelImpl
|
|||
IOUtil.configureBlocking(newfd, true);
|
||||
|
||||
// check permitted to accept connections from the remote address
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
||||
if (isNetSocket()) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||
sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort());
|
||||
}
|
||||
}
|
||||
return new SocketChannelImpl(provider(), family, newfd, isa);
|
||||
return new SocketChannelImpl(provider(), family, newfd, sa);
|
||||
} catch (Exception e) {
|
||||
nd.close(newfd);
|
||||
throw e;
|
||||
|
@ -536,7 +643,7 @@ class ServerSocketChannelImpl
|
|||
/**
|
||||
* Returns the local address, or null if not bound
|
||||
*/
|
||||
InetSocketAddress localAddress() {
|
||||
SocketAddress localAddress() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress;
|
||||
}
|
||||
|
@ -605,9 +712,11 @@ class ServerSocketChannelImpl
|
|||
sb.append("closed");
|
||||
} else {
|
||||
synchronized (stateLock) {
|
||||
InetSocketAddress addr = localAddress;
|
||||
SocketAddress addr = localAddress;
|
||||
if (addr == null) {
|
||||
sb.append("unbound");
|
||||
} else if (isUnixSocket()) {
|
||||
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
|
||||
} else {
|
||||
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -72,6 +72,14 @@ class SocketAdaptor
|
|||
}
|
||||
}
|
||||
|
||||
private InetSocketAddress localAddress() {
|
||||
return (InetSocketAddress) sc.localAddress();
|
||||
}
|
||||
|
||||
private InetSocketAddress remoteAddress() {
|
||||
return (InetSocketAddress) sc.remoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(SocketAddress remote) throws IOException {
|
||||
connect(remote, 0);
|
||||
|
@ -106,7 +114,7 @@ class SocketAdaptor
|
|||
|
||||
@Override
|
||||
public InetAddress getInetAddress() {
|
||||
InetSocketAddress remote = sc.remoteAddress();
|
||||
InetSocketAddress remote = remoteAddress();
|
||||
if (remote == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -117,7 +125,7 @@ class SocketAdaptor
|
|||
@Override
|
||||
public InetAddress getLocalAddress() {
|
||||
if (sc.isOpen()) {
|
||||
InetSocketAddress local = sc.localAddress();
|
||||
InetSocketAddress local = localAddress();
|
||||
if (local != null) {
|
||||
return Net.getRevealedLocalAddress(local).getAddress();
|
||||
}
|
||||
|
@ -127,7 +135,7 @@ class SocketAdaptor
|
|||
|
||||
@Override
|
||||
public int getPort() {
|
||||
InetSocketAddress remote = sc.remoteAddress();
|
||||
InetSocketAddress remote = remoteAddress();
|
||||
if (remote == null) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -137,7 +145,7 @@ class SocketAdaptor
|
|||
|
||||
@Override
|
||||
public int getLocalPort() {
|
||||
InetSocketAddress local = sc.localAddress();
|
||||
InetSocketAddress local = localAddress();
|
||||
if (local == null) {
|
||||
return -1;
|
||||
} else {
|
||||
|
@ -152,12 +160,7 @@ class SocketAdaptor
|
|||
|
||||
@Override
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
InetSocketAddress local = sc.localAddress();
|
||||
if (local != null) {
|
||||
return Net.getRevealedLocalAddress(local);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return Net.getRevealedLocalAddress(sc.localAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.net.SocketAddress;
|
|||
import java.net.SocketException;
|
||||
import java.net.SocketOption;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AlreadyBoundException;
|
||||
|
@ -50,11 +49,15 @@ import java.nio.channels.NotYetConnectedException;
|
|||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import static java.net.StandardProtocolFamily.INET;
|
||||
import static java.net.StandardProtocolFamily.INET6;
|
||||
import static java.net.StandardProtocolFamily.UNIX;
|
||||
|
||||
import sun.net.ConnectionResetException;
|
||||
import sun.net.NetHooks;
|
||||
|
@ -114,52 +117,35 @@ class SocketChannelImpl
|
|||
private long writerThread;
|
||||
|
||||
// Binding
|
||||
private InetSocketAddress localAddress;
|
||||
private InetSocketAddress remoteAddress;
|
||||
private SocketAddress localAddress;
|
||||
private SocketAddress remoteAddress;
|
||||
|
||||
// Socket adaptor, created on demand
|
||||
private Socket socket;
|
||||
|
||||
// -- End of fields protected by stateLock
|
||||
|
||||
// Constructor for normal connecting sockets
|
||||
//
|
||||
SocketChannelImpl(SelectorProvider sp) throws IOException {
|
||||
this(sp, Net.isIPv6Available()
|
||||
? StandardProtocolFamily.INET6
|
||||
: StandardProtocolFamily.INET);
|
||||
this(sp, Net.isIPv6Available() ? INET6 : INET);
|
||||
}
|
||||
|
||||
SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
|
||||
super(sp);
|
||||
Objects.requireNonNull(family, "'family' is null");
|
||||
if ((family != StandardProtocolFamily.INET) &&
|
||||
(family != StandardProtocolFamily.INET6)) {
|
||||
if ((family != INET) && (family != INET6) && (family != UNIX)) {
|
||||
throw new UnsupportedOperationException("Protocol family not supported");
|
||||
}
|
||||
if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) {
|
||||
if (family == INET6 && !Net.isIPv6Available()) {
|
||||
throw new UnsupportedOperationException("IPv6 not available");
|
||||
}
|
||||
|
||||
this.family = family;
|
||||
this.fd = Net.socket(family, true);
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
}
|
||||
|
||||
SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
this.family = Net.isIPv6Available()
|
||||
? StandardProtocolFamily.INET6
|
||||
: StandardProtocolFamily.INET;
|
||||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
|
||||
if (bound) {
|
||||
synchronized (stateLock) {
|
||||
this.localAddress = Net.localAddress(fd);
|
||||
}
|
||||
if (family == UNIX) {
|
||||
this.fd = UnixDomainSockets.socket();
|
||||
} else {
|
||||
this.fd = Net.socket(family, true);
|
||||
}
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
}
|
||||
|
||||
// Constructor for sockets obtained from server sockets
|
||||
|
@ -167,7 +153,7 @@ class SocketChannelImpl
|
|||
SocketChannelImpl(SelectorProvider sp,
|
||||
ProtocolFamily family,
|
||||
FileDescriptor fd,
|
||||
InetSocketAddress isa)
|
||||
SocketAddress remoteAddress)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
|
@ -175,12 +161,30 @@ class SocketChannelImpl
|
|||
this.fd = fd;
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
synchronized (stateLock) {
|
||||
this.localAddress = Net.localAddress(fd);
|
||||
this.remoteAddress = isa;
|
||||
if (family == UNIX) {
|
||||
this.localAddress = UnixDomainSockets.localAddress(fd);
|
||||
} else {
|
||||
this.localAddress = Net.localAddress(fd);
|
||||
}
|
||||
this.remoteAddress = remoteAddress;
|
||||
this.state = ST_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this channel is to a INET or INET6 socket.
|
||||
*/
|
||||
boolean isNetSocket() {
|
||||
return (family == INET) || (family == INET6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this channel is to a UNIX socket.
|
||||
*/
|
||||
boolean isUnixSocket() {
|
||||
return (family == UNIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the channel is open.
|
||||
*
|
||||
|
@ -215,8 +219,13 @@ class SocketChannelImpl
|
|||
@Override
|
||||
public Socket socket() {
|
||||
synchronized (stateLock) {
|
||||
if (socket == null)
|
||||
socket = SocketAdaptor.create(this);
|
||||
if (socket == null) {
|
||||
if (isNetSocket()) {
|
||||
socket = SocketAdaptor.create(this);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +234,11 @@ class SocketChannelImpl
|
|||
public SocketAddress getLocalAddress() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
return Net.getRevealedLocalAddress(localAddress);
|
||||
if (isUnixSocket()) {
|
||||
return UnixDomainSockets.getRevealedLocalAddress(localAddress);
|
||||
} else {
|
||||
return Net.getRevealedLocalAddress(localAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,15 +263,17 @@ class SocketChannelImpl
|
|||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
Net.setSocketOption(fd, family, name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean)value;
|
||||
return this;
|
||||
if (isNetSocket()) {
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
// special handling for IP_TOS
|
||||
Net.setSocketOption(fd, family, name, value);
|
||||
return this;
|
||||
}
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
isReuseAddress = (Boolean) value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// no options that require special handling
|
||||
|
@ -279,14 +294,15 @@ class SocketChannelImpl
|
|||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T)Boolean.valueOf(isReuseAddress);
|
||||
}
|
||||
|
||||
// special handling for IP_TOS
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
return (T) Net.getSocketOption(fd, family, name);
|
||||
if (isNetSocket()) {
|
||||
if (name == StandardSocketOptions.IP_TOS) {
|
||||
// special handling for IP_TOS
|
||||
return (T) Net.getSocketOption(fd, family, name);
|
||||
}
|
||||
if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) {
|
||||
// SO_REUSEADDR emulated when using exclusive bind
|
||||
return (T) Boolean.valueOf(isReuseAddress);
|
||||
}
|
||||
}
|
||||
|
||||
// no options that require special handling
|
||||
|
@ -295,9 +311,10 @@ class SocketChannelImpl
|
|||
}
|
||||
|
||||
private static class DefaultOptionsHolder {
|
||||
static final Set<SocketOption<?>> defaultOptions = defaultOptions();
|
||||
static final Set<SocketOption<?>> defaultInetOptions = defaultInetOptions();
|
||||
static final Set<SocketOption<?>> defaultUnixOptions = defaultUnixOptions();
|
||||
|
||||
private static Set<SocketOption<?>> defaultOptions() {
|
||||
private static Set<SocketOption<?>> defaultInetOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
|
@ -314,11 +331,24 @@ class SocketChannelImpl
|
|||
set.addAll(ExtendedSocketOptions.clientSocketOptions());
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
private static Set<SocketOption<?>> defaultUnixOptions() {
|
||||
HashSet<SocketOption<?>> set = new HashSet<>();
|
||||
set.add(StandardSocketOptions.SO_SNDBUF);
|
||||
set.add(StandardSocketOptions.SO_RCVBUF);
|
||||
set.add(StandardSocketOptions.SO_LINGER);
|
||||
set.addAll(ExtendedSocketOptions.unixDomainSocketOptions());
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Set<SocketOption<?>> supportedOptions() {
|
||||
return DefaultOptionsHolder.defaultOptions;
|
||||
if (isUnixSocket()) {
|
||||
return DefaultOptionsHolder.defaultUnixOptions;
|
||||
} else {
|
||||
return DefaultOptionsHolder.defaultInetOptions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -625,7 +655,7 @@ class SocketChannelImpl
|
|||
/**
|
||||
* Returns the local address, or null if not bound
|
||||
*/
|
||||
InetSocketAddress localAddress() {
|
||||
SocketAddress localAddress() {
|
||||
synchronized (stateLock) {
|
||||
return localAddress;
|
||||
}
|
||||
|
@ -634,7 +664,7 @@ class SocketChannelImpl
|
|||
/**
|
||||
* Returns the remote address, or null if not connected
|
||||
*/
|
||||
InetSocketAddress remoteAddress() {
|
||||
SocketAddress remoteAddress() {
|
||||
synchronized (stateLock) {
|
||||
return remoteAddress;
|
||||
}
|
||||
|
@ -652,19 +682,11 @@ class SocketChannelImpl
|
|||
throw new ConnectionPendingException();
|
||||
if (localAddress != null)
|
||||
throw new AlreadyBoundException();
|
||||
InetSocketAddress isa;
|
||||
if (local == null) {
|
||||
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
|
||||
if (isUnixSocket()) {
|
||||
localAddress = unixBind(local);
|
||||
} else {
|
||||
isa = Net.checkAddress(local, family);
|
||||
localAddress = netBind(local);
|
||||
}
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkListen(isa.getPort());
|
||||
}
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(family, fd, isa.getAddress(), isa.getPort());
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
|
@ -675,6 +697,38 @@ class SocketChannelImpl
|
|||
return this;
|
||||
}
|
||||
|
||||
private SocketAddress unixBind(SocketAddress local) throws IOException {
|
||||
UnixDomainSockets.checkPermission();
|
||||
if (local == null) {
|
||||
return UnixDomainSockets.UNNAMED;
|
||||
} else {
|
||||
Path path = UnixDomainSockets.checkAddress(local).getPath();
|
||||
if (path.toString().isEmpty()) {
|
||||
return UnixDomainSockets.UNNAMED;
|
||||
} else {
|
||||
// bind to non-empty path
|
||||
UnixDomainSockets.bind(fd, path);
|
||||
return UnixDomainSockets.localAddress(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SocketAddress netBind(SocketAddress local) throws IOException {
|
||||
InetSocketAddress isa;
|
||||
if (local == null) {
|
||||
isa = new InetSocketAddress(Net.anyLocalAddress(family), 0);
|
||||
} else {
|
||||
isa = Net.checkAddress(local, family);
|
||||
}
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkListen(isa.getPort());
|
||||
}
|
||||
NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
|
||||
Net.bind(family, fd, isa.getAddress(), isa.getPort());
|
||||
return Net.localAddress(fd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return (state == ST_CONNECTED);
|
||||
|
@ -694,7 +748,7 @@ class SocketChannelImpl
|
|||
* @throws ConnectionPendingException is a connection is pending
|
||||
* @throws IOException if the pre-connect hook fails
|
||||
*/
|
||||
private void beginConnect(boolean blocking, InetSocketAddress isa)
|
||||
private void beginConnect(boolean blocking, SocketAddress sa)
|
||||
throws IOException
|
||||
{
|
||||
if (blocking) {
|
||||
|
@ -711,9 +765,11 @@ class SocketChannelImpl
|
|||
assert state == ST_UNCONNECTED;
|
||||
this.state = ST_CONNECTIONPENDING;
|
||||
|
||||
if (localAddress == null)
|
||||
if (isNetSocket() && (localAddress == null)) {
|
||||
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||
NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
|
||||
remoteAddress = isa;
|
||||
}
|
||||
remoteAddress = sa;
|
||||
|
||||
if (blocking) {
|
||||
// record thread so it can be signalled if needed
|
||||
|
@ -737,7 +793,11 @@ class SocketChannelImpl
|
|||
if (completed) {
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_CONNECTIONPENDING) {
|
||||
localAddress = Net.localAddress(fd);
|
||||
if (isUnixSocket()) {
|
||||
localAddress = UnixDomainSockets.localAddress(fd);
|
||||
} else {
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
state = ST_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
@ -747,29 +807,34 @@ class SocketChannelImpl
|
|||
/**
|
||||
* Checks the remote address to which this channel is to be connected.
|
||||
*/
|
||||
private InetSocketAddress checkRemote(SocketAddress sa) {
|
||||
InetSocketAddress isa = Net.checkAddress(sa, family);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
|
||||
}
|
||||
InetAddress address = isa.getAddress();
|
||||
if (address.isAnyLocalAddress()) {
|
||||
int port = isa.getPort();
|
||||
if (address instanceof Inet4Address) {
|
||||
return new InetSocketAddress(Net.inet4LoopbackAddress(), port);
|
||||
} else {
|
||||
assert family == StandardProtocolFamily.INET6;
|
||||
return new InetSocketAddress(Net.inet6LoopbackAddress(), port);
|
||||
}
|
||||
private SocketAddress checkRemote(SocketAddress sa) {
|
||||
if (isUnixSocket()) {
|
||||
UnixDomainSockets.checkPermission();
|
||||
return UnixDomainSockets.checkAddress(sa);
|
||||
} else {
|
||||
return isa;
|
||||
InetSocketAddress isa = Net.checkAddress(sa, family);
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
|
||||
}
|
||||
InetAddress address = isa.getAddress();
|
||||
if (address.isAnyLocalAddress()) {
|
||||
int port = isa.getPort();
|
||||
if (address instanceof Inet4Address) {
|
||||
return new InetSocketAddress(Net.inet4LoopbackAddress(), port);
|
||||
} else {
|
||||
assert family == INET6;
|
||||
return new InetSocketAddress(Net.inet6LoopbackAddress(), port);
|
||||
}
|
||||
} else {
|
||||
return isa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect(SocketAddress remote) throws IOException {
|
||||
InetSocketAddress isa = checkRemote(remote);
|
||||
SocketAddress sa = checkRemote(remote);
|
||||
try {
|
||||
readLock.lock();
|
||||
try {
|
||||
|
@ -778,11 +843,13 @@ class SocketChannelImpl
|
|||
boolean blocking = isBlocking();
|
||||
boolean connected = false;
|
||||
try {
|
||||
beginConnect(blocking, isa);
|
||||
int n = Net.connect(family,
|
||||
fd,
|
||||
isa.getAddress(),
|
||||
isa.getPort());
|
||||
beginConnect(blocking, sa);
|
||||
int n;
|
||||
if (isUnixSocket()) {
|
||||
n = UnixDomainSockets.connect(fd, sa);
|
||||
} else {
|
||||
n = Net.connect(family, fd, sa);
|
||||
}
|
||||
if (n > 0) {
|
||||
connected = true;
|
||||
} else if (blocking) {
|
||||
|
@ -807,7 +874,7 @@ class SocketChannelImpl
|
|||
} catch (IOException ioe) {
|
||||
// connect failed, close the channel
|
||||
close();
|
||||
throw SocketExceptions.of(ioe, isa);
|
||||
throw SocketExceptions.of(ioe, sa);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -848,7 +915,11 @@ class SocketChannelImpl
|
|||
if (completed) {
|
||||
synchronized (stateLock) {
|
||||
if (state == ST_CONNECTIONPENDING) {
|
||||
localAddress = Net.localAddress(fd);
|
||||
if (isUnixSocket()) {
|
||||
localAddress = UnixDomainSockets.localAddress(fd);
|
||||
} else {
|
||||
localAddress = Net.localAddress(fd);
|
||||
}
|
||||
state = ST_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
@ -1087,7 +1158,7 @@ class SocketChannelImpl
|
|||
* @throws SocketTimeoutException if the read timeout elapses
|
||||
*/
|
||||
void blockingConnect(SocketAddress remote, long nanos) throws IOException {
|
||||
InetSocketAddress isa = checkRemote(remote);
|
||||
SocketAddress sa = checkRemote(remote);
|
||||
try {
|
||||
readLock.lock();
|
||||
try {
|
||||
|
@ -1097,11 +1168,16 @@ class SocketChannelImpl
|
|||
throw new IllegalBlockingModeException();
|
||||
boolean connected = false;
|
||||
try {
|
||||
beginConnect(true, isa);
|
||||
beginConnect(true, sa);
|
||||
// change socket to non-blocking
|
||||
lockedConfigureBlocking(false);
|
||||
try {
|
||||
int n = Net.connect(fd, isa.getAddress(), isa.getPort());
|
||||
int n;
|
||||
if (isUnixSocket()) {
|
||||
n = UnixDomainSockets.connect(fd, sa);
|
||||
} else {
|
||||
n = Net.connect(family, fd, sa);
|
||||
}
|
||||
connected = (n > 0) ? true : finishTimedConnect(nanos);
|
||||
} finally {
|
||||
// restore socket to blocking mode (if channel is open)
|
||||
|
@ -1119,7 +1195,7 @@ class SocketChannelImpl
|
|||
} catch (IOException ioe) {
|
||||
// connect failed, close the channel
|
||||
close();
|
||||
throw SocketExceptions.of(ioe, isa);
|
||||
throw SocketExceptions.of(ioe, sa);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1390,10 +1466,14 @@ class SocketChannelImpl
|
|||
sb.append(" oshut");
|
||||
break;
|
||||
}
|
||||
InetSocketAddress addr = localAddress();
|
||||
SocketAddress addr = localAddress();
|
||||
if (addr != null) {
|
||||
sb.append(" local=");
|
||||
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
||||
if (isUnixSocket()) {
|
||||
sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr));
|
||||
} else {
|
||||
sb.append(Net.getRevealedLocalAddressAsString(addr));
|
||||
}
|
||||
}
|
||||
if (remoteAddress() != null) {
|
||||
sb.append(" remote=");
|
||||
|
|
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -154,4 +154,10 @@ public abstract class AbstractFileSystemProvider extends FileSystemProvider {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a path name as bytes for a Unix domain socket.
|
||||
* Different encodings may be used for these names on some platforms.
|
||||
*/
|
||||
public abstract byte[] getSunPathForSocketFile(Path file);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue