8245194: Unix domain socket channel implementation

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

View file

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

View file

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

View file

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

View file

@ -1,63 +0,0 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.nio.ch;
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.io.FileDescriptor;
import java.io.IOException;
/**
* Provides access to implementation private constructors and methods.
*/
public final class Secrets {
private Secrets() { }
private static SelectorProvider provider() {
SelectorProvider p = SelectorProvider.provider();
if (!(p instanceof SelectorProviderImpl))
throw new UnsupportedOperationException();
return p;
}
public static SocketChannel newSocketChannel(FileDescriptor fd) {
try {
return new SocketChannelImpl(provider(), fd, false);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
try {
return new ServerSocketChannelImpl(provider(), fd, false);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
}

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -93,7 +93,7 @@ class ServerSocketAdaptor // package-private
@Override
public InetAddress getInetAddress() {
InetSocketAddress local = ssc.localAddress();
SocketAddress local = ssc.localAddress();
if (local == null) {
return null;
} else {
@ -103,7 +103,7 @@ class ServerSocketAdaptor // package-private
@Override
public int getLocalPort() {
InetSocketAddress local = ssc.localAddress();
InetSocketAddress local = (InetSocketAddress) ssc.localAddress();
if (local == null) {
return -1;
} else {

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -72,6 +72,14 @@ class SocketAdaptor
}
}
private InetSocketAddress localAddress() {
return (InetSocketAddress) sc.localAddress();
}
private InetSocketAddress remoteAddress() {
return (InetSocketAddress) sc.remoteAddress();
}
@Override
public void connect(SocketAddress remote) throws IOException {
connect(remote, 0);
@ -106,7 +114,7 @@ class SocketAdaptor
@Override
public InetAddress getInetAddress() {
InetSocketAddress remote = sc.remoteAddress();
InetSocketAddress remote = remoteAddress();
if (remote == null) {
return null;
} else {
@ -117,7 +125,7 @@ class SocketAdaptor
@Override
public InetAddress getLocalAddress() {
if (sc.isOpen()) {
InetSocketAddress local = sc.localAddress();
InetSocketAddress local = localAddress();
if (local != null) {
return Net.getRevealedLocalAddress(local).getAddress();
}
@ -127,7 +135,7 @@ class SocketAdaptor
@Override
public int getPort() {
InetSocketAddress remote = sc.remoteAddress();
InetSocketAddress remote = remoteAddress();
if (remote == null) {
return 0;
} else {
@ -137,7 +145,7 @@ class SocketAdaptor
@Override
public int getLocalPort() {
InetSocketAddress local = sc.localAddress();
InetSocketAddress local = localAddress();
if (local == null) {
return -1;
} else {
@ -152,12 +160,7 @@ class SocketAdaptor
@Override
public SocketAddress getLocalSocketAddress() {
InetSocketAddress local = sc.localAddress();
if (local != null) {
return Net.getRevealedLocalAddress(local);
} else {
return null;
}
return Net.getRevealedLocalAddress(sc.localAddress());
}
@Override

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -154,4 +154,10 @@ public abstract class AbstractFileSystemProvider extends FileSystemProvider {
return false;
}
}
/**
* Returns a path name as bytes for a Unix domain socket.
* Different encodings may be used for these names on some platforms.
*/
public abstract byte[] getSunPathForSocketFile(Path file);
}