mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +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
|
@ -32,10 +32,13 @@ import java.net.InetAddress;
|
|||
import java.net.Inet6Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.UnixDomainSocketAddress;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import static java.net.StandardProtocolFamily.INET6;
|
||||
import static java.net.StandardProtocolFamily.INET;
|
||||
import static java.net.StandardProtocolFamily.UNIX;
|
||||
|
||||
class InheritedChannel {
|
||||
|
||||
|
@ -45,10 +48,10 @@ class InheritedChannel {
|
|||
private static final int SOCK_DGRAM = 2;
|
||||
|
||||
// socket address type
|
||||
private static final int AF_UNKNOWN = -1;
|
||||
private static final int AF_INET = 1;
|
||||
private static final int AF_INET6 = 2;
|
||||
private static final int AF_UNIX = 3;
|
||||
static final int AF_UNKNOWN = -1;
|
||||
static final int AF_INET = 1;
|
||||
static final int AF_INET6 = 2;
|
||||
static final int AF_UNIX = 3;
|
||||
|
||||
// oflag values when opening a file
|
||||
private static final int O_RDONLY = 0;
|
||||
|
@ -75,6 +78,24 @@ class InheritedChannel {
|
|||
}
|
||||
}
|
||||
|
||||
static ProtocolFamily protocolFamily(SocketAddress sa) {
|
||||
if (sa instanceof UnixDomainSocketAddress) {
|
||||
return UNIX;
|
||||
} else {
|
||||
InetSocketAddress isa = (InetSocketAddress) sa;
|
||||
return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET;
|
||||
}
|
||||
}
|
||||
|
||||
static ProtocolFamily protocolFamily(int family) {
|
||||
return switch (family) {
|
||||
case AF_INET -> INET;
|
||||
case AF_INET6 -> INET6;
|
||||
case AF_UNIX -> UNIX;
|
||||
default -> throw new IllegalArgumentException();
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the implCloseSelectableChannel for each channel type - this
|
||||
* allows us to "detach" the standard streams after closing and ensures
|
||||
|
@ -82,16 +103,12 @@ class InheritedChannel {
|
|||
*/
|
||||
public static class InheritedSocketChannelImpl extends SocketChannelImpl {
|
||||
|
||||
static ProtocolFamily family(InetSocketAddress isa) {
|
||||
return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET;
|
||||
}
|
||||
|
||||
InheritedSocketChannelImpl(SelectorProvider sp,
|
||||
FileDescriptor fd,
|
||||
InetSocketAddress remote)
|
||||
SocketAddress remote)
|
||||
throws IOException
|
||||
{
|
||||
super(sp, family(remote), fd, remote);
|
||||
super(sp, protocolFamily(remote), fd, remote);
|
||||
}
|
||||
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
|
@ -100,39 +117,24 @@ class InheritedChannel {
|
|||
}
|
||||
}
|
||||
|
||||
public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl {
|
||||
|
||||
InheritedUnixChannelImpl(FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
super(fd);
|
||||
}
|
||||
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
super.implCloseChannel();
|
||||
detachIOStreams();
|
||||
}
|
||||
}
|
||||
|
||||
public static class InheritedServerSocketChannelImpl extends
|
||||
ServerSocketChannelImpl {
|
||||
public static class InheritedServerSocketChannelImpl extends ServerSocketChannelImpl {
|
||||
|
||||
InheritedServerSocketChannelImpl(SelectorProvider sp,
|
||||
ProtocolFamily family,
|
||||
FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
super(sp, fd, true);
|
||||
super(sp, family, fd, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void implCloseSelectableChannel() throws IOException {
|
||||
super.implCloseSelectableChannel();
|
||||
detachIOStreams();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class InheritedDatagramChannelImpl extends
|
||||
DatagramChannelImpl {
|
||||
public static class InheritedDatagramChannelImpl extends DatagramChannelImpl {
|
||||
|
||||
InheritedDatagramChannelImpl(SelectorProvider sp,
|
||||
FileDescriptor fd)
|
||||
|
@ -151,16 +153,13 @@ class InheritedChannel {
|
|||
* If there's a SecurityManager then check for the appropriate
|
||||
* RuntimePermission.
|
||||
*/
|
||||
private static void checkAccess(Channel c) {
|
||||
private static void checkAccess() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(
|
||||
new RuntimePermission("inheritedChannel")
|
||||
);
|
||||
sm.checkPermission(new RuntimePermission("inheritedChannel"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If standard inherited channel is connected to a socket then return a Channel
|
||||
* of the appropriate type based standard input.
|
||||
|
@ -197,7 +196,7 @@ class InheritedChannel {
|
|||
|
||||
|
||||
// Now create the channel. If the socket is a streams socket then
|
||||
// we see if tthere is a peer (ie: connected). If so, then we
|
||||
// we see if there is a peer (ie: connected). If so, then we
|
||||
// create a SocketChannel, otherwise a ServerSocketChannel.
|
||||
// If the socket is a datagram socket then create a DatagramChannel
|
||||
|
||||
|
@ -209,19 +208,21 @@ class InheritedChannel {
|
|||
int family = addressFamily(fdVal);
|
||||
if (family == AF_UNKNOWN)
|
||||
return null;
|
||||
ProtocolFamily pfamily = protocolFamily(family);
|
||||
if (family == AF_UNIX) {
|
||||
if (isConnected(fdVal)) {
|
||||
return new InheritedUnixChannelImpl(fd);
|
||||
var sa = UnixDomainSocketAddress.of(unixPeerAddress(fdVal));
|
||||
return new InheritedSocketChannelImpl(provider, fd, sa);
|
||||
} else {
|
||||
// listener. unsupported.
|
||||
return null;
|
||||
return new InheritedServerSocketChannelImpl(provider, pfamily, fd);
|
||||
}
|
||||
}
|
||||
InetAddress ia = peerAddress0(fdVal);
|
||||
InetAddress ia = inetPeerAddress0(fdVal);
|
||||
if (ia == null) {
|
||||
c = new InheritedServerSocketChannelImpl(provider, fd);
|
||||
c = new InheritedServerSocketChannelImpl(provider, pfamily, fd);
|
||||
} else {
|
||||
int port = peerPort0(fdVal);
|
||||
|
||||
assert port > 0;
|
||||
InetSocketAddress isa = new InetSocketAddress(ia, port);
|
||||
c = new InheritedSocketChannelImpl(provider, fd, isa);
|
||||
|
@ -253,11 +254,15 @@ class InheritedChannel {
|
|||
// if there is a channel then do the security check before
|
||||
// returning it.
|
||||
if (channel != null) {
|
||||
checkAccess(channel);
|
||||
checkAccess();
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
private static String unixPeerAddress(int fd) throws IOException {
|
||||
byte[] bytes = unixPeerAddress0(fd);
|
||||
return new String(bytes);
|
||||
}
|
||||
|
||||
// -- Native methods --
|
||||
|
||||
|
@ -268,7 +273,8 @@ class InheritedChannel {
|
|||
private static native void close0(int fd) throws IOException;
|
||||
private static native int soType0(int fd);
|
||||
private static native int addressFamily(int fd);
|
||||
private static native InetAddress peerAddress0(int fd);
|
||||
private static native InetAddress inetPeerAddress0(int fd);
|
||||
private static native byte[] unixPeerAddress0(int fd);
|
||||
private static native int peerPort0(int fd);
|
||||
|
||||
// return true if socket is connected to a peer
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ByteChannel;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.nio.channels.spi.AbstractInterruptibleChannel;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
class UnixDomainSocketChannelImpl
|
||||
extends AbstractInterruptibleChannel
|
||||
implements ByteChannel
|
||||
{
|
||||
// Used to make native read and write calls
|
||||
private static final NativeDispatcher nd = new SocketDispatcher();
|
||||
|
||||
// Our file descriptor object
|
||||
private final FileDescriptor fd;
|
||||
// Lock held by current reading or connecting thread
|
||||
private final ReentrantLock readLock = new ReentrantLock();
|
||||
|
||||
// Lock held by current writing or connecting thread
|
||||
private final ReentrantLock writeLock = new ReentrantLock();
|
||||
|
||||
// Lock for managing close state
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
// Channel state
|
||||
private static final int ST_INUSE = 0;
|
||||
private static final int ST_CLOSING = 1;
|
||||
private static final int ST_CLOSED = 2;
|
||||
private int state;
|
||||
|
||||
// IDs of native threads doing reads and writes, for signalling
|
||||
private long readerThread;
|
||||
private long writerThread;
|
||||
|
||||
UnixDomainSocketChannelImpl(FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
this.fd = fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the channel is open.
|
||||
*
|
||||
* @throws ClosedChannelException if channel is closed (or closing)
|
||||
*/
|
||||
private void ensureOpen() throws ClosedChannelException {
|
||||
if (!isOpen())
|
||||
throw new ClosedChannelException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the socket if there are no I/O operations in progress
|
||||
*/
|
||||
private boolean tryClose() throws IOException {
|
||||
assert Thread.holdsLock(stateLock) && state == ST_CLOSING;
|
||||
if (readerThread == 0 && writerThread == 0) {
|
||||
state = ST_CLOSED;
|
||||
nd.close(fd);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete closure of pre-closed socket (release the file descriptor)
|
||||
*/
|
||||
private void tryFinishClose() {
|
||||
try {
|
||||
tryClose();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of a read operation
|
||||
*
|
||||
* @throws ClosedChannelException if the channel is closed
|
||||
* @throws NotYetConnectedException if the channel is not yet connected
|
||||
*/
|
||||
private void beginRead() throws ClosedChannelException {
|
||||
// set hook for Thread.interrupt
|
||||
begin();
|
||||
synchronized (stateLock) {
|
||||
ensureOpen();
|
||||
readerThread = NativeThread.current();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of a read operation that may have blocked.
|
||||
*
|
||||
* @throws AsynchronousCloseException if the channel was closed due to this
|
||||
* thread being interrupted on a blocking read operation.
|
||||
*/
|
||||
private void endRead(boolean completed)
|
||||
throws AsynchronousCloseException
|
||||
{
|
||||
synchronized (stateLock) {
|
||||
readerThread = 0;
|
||||
if (state == ST_CLOSING) {
|
||||
tryFinishClose();
|
||||
}
|
||||
}
|
||||
end(completed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer buf) throws IOException {
|
||||
Objects.requireNonNull(buf);
|
||||
|
||||
readLock.lock();
|
||||
try {
|
||||
int n = 0;
|
||||
try {
|
||||
beginRead();
|
||||
n = IOUtil.read(fd, buf, -1, nd);
|
||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||
park(Net.POLLIN, 0L);
|
||||
n = IOUtil.read(fd, buf, -1, nd);
|
||||
}
|
||||
} finally {
|
||||
endRead(n > 0);
|
||||
}
|
||||
return n;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the beginning of a write operation that might block.
|
||||
*
|
||||
* @throws ClosedChannelException if the channel is closed
|
||||
* @throws NotYetConnectedException if the channel is not yet connected
|
||||
*/
|
||||
private void beginWrite() throws ClosedChannelException {
|
||||
begin();
|
||||
synchronized (stateLock) {
|
||||
// set hook for Thread.interrupt
|
||||
ensureOpen();
|
||||
writerThread = NativeThread.current();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the end of a write operation that may have blocked.
|
||||
*
|
||||
* @throws AsynchronousCloseException if the channel was closed due to this
|
||||
* thread being interrupted on a blocking write operation.
|
||||
*/
|
||||
private void endWrite(boolean completed)
|
||||
throws AsynchronousCloseException
|
||||
{
|
||||
synchronized (stateLock) {
|
||||
writerThread = 0;
|
||||
if (state == ST_CLOSING) {
|
||||
tryFinishClose();
|
||||
}
|
||||
}
|
||||
end(completed);
|
||||
}
|
||||
|
||||
void park(int event, long nanos) throws IOException {
|
||||
long millis;
|
||||
if (nanos <= 0) {
|
||||
millis = -1;
|
||||
} else {
|
||||
millis = NANOSECONDS.toMillis(nanos);
|
||||
}
|
||||
Net.poll(fd, event, millis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ByteBuffer buf) throws IOException {
|
||||
Objects.requireNonNull(buf);
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
int n = 0;
|
||||
try {
|
||||
beginWrite();
|
||||
n = IOUtil.write(fd, buf, -1, nd);
|
||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||
park(Net.POLLOUT, 0L);
|
||||
n = IOUtil.write(fd, buf, -1, nd);
|
||||
}
|
||||
} finally {
|
||||
endWrite(n > 0);
|
||||
}
|
||||
return n;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this channel
|
||||
*
|
||||
* If there is an I/O operation in progress then the socket is pre-closed
|
||||
* and the I/O threads signalled, in which case the final close is deferred
|
||||
* until all I/O operations complete.
|
||||
*/
|
||||
@Override
|
||||
protected void implCloseChannel() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
assert state == ST_INUSE;
|
||||
state = ST_CLOSING;
|
||||
if (!tryClose()) {
|
||||
long reader = readerThread;
|
||||
long writer = writerThread;
|
||||
if (reader != 0 || writer != 0) {
|
||||
nd.preClose(fd);
|
||||
if (reader != 0)
|
||||
NativeThread.signal(reader);
|
||||
if (writer != 0)
|
||||
NativeThread.signal(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.getClass().getSuperclass().getName());
|
||||
sb.append('[');
|
||||
if (!isOpen())
|
||||
sb.append("closed");
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.net.NetProperties;
|
||||
import jdk.internal.util.StaticProperty;
|
||||
|
||||
/**
|
||||
* Platform specific utility functions
|
||||
*/
|
||||
class UnixDomainSocketsUtil {
|
||||
private UnixDomainSocketsUtil() { }
|
||||
|
||||
static Charset getCharset() {
|
||||
return Charset.defaultCharset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the temp directory for storing automatically bound
|
||||
* server sockets.
|
||||
*
|
||||
* On UNIX we search the following directories in sequence:
|
||||
*
|
||||
* 1. ${jdk.net.unixdomain.tmpdir} if set as system property
|
||||
* 2. ${jdk.net.unixdomain.tmpdir} if set as net property
|
||||
* 3. ${java.io.tmpdir} system property
|
||||
*/
|
||||
static String getTempDir() {
|
||||
PrivilegedAction<String> action = () -> {
|
||||
String s = NetProperties.get("jdk.net.unixdomain.tmpdir");
|
||||
if (s != null && s.length() > 0) {
|
||||
return s;
|
||||
} else {
|
||||
return StaticProperty.javaIoTmpDir();
|
||||
}
|
||||
};
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -557,4 +557,10 @@ public abstract class UnixFileSystemProvider
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getSunPathForSocketFile(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
return file.getByteArrayForSysCalls();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -33,7 +33,7 @@ import static sun.nio.fs.UnixNativeDispatcher.*;
|
|||
* Unix implementation of java.nio.file.attribute.UserPrincipal
|
||||
*/
|
||||
|
||||
class UnixUserPrincipals {
|
||||
public class UnixUserPrincipals {
|
||||
private static User createSpecial(String name) { return new User(-1, name); }
|
||||
|
||||
static final User SPECIAL_OWNER = createSpecial("OWNER@");
|
||||
|
@ -108,7 +108,7 @@ class UnixUserPrincipals {
|
|||
}
|
||||
|
||||
// return UserPrincipal representing given uid
|
||||
static User fromUid(int uid) {
|
||||
public static User fromUid(int uid) {
|
||||
String name;
|
||||
try {
|
||||
name = Util.toString(getpwuid(uid));
|
||||
|
@ -119,7 +119,7 @@ class UnixUserPrincipals {
|
|||
}
|
||||
|
||||
// return GroupPrincipal representing given gid
|
||||
static Group fromGid(int gid) {
|
||||
public static Group fromGid(int gid) {
|
||||
String name;
|
||||
try {
|
||||
name = Util.toString(getgrgid(gid));
|
||||
|
|
15
src/java.base/unix/conf/net.properties
Normal file
15
src/java.base/unix/conf/net.properties
Normal file
|
@ -0,0 +1,15 @@
|
|||
#
|
||||
# Default directory where automatically bound Unix domain server
|
||||
# sockets are stored. Sockets are automatically bound when bound
|
||||
# with a null address.
|
||||
#
|
||||
# On Unix the search order to determine this directory is:
|
||||
#
|
||||
# 1. System property jdk.net.unixdomain.tmpdir
|
||||
#
|
||||
# 2. Networking property jdk.net.unixdomain.tmpdir specified
|
||||
# in this file (effective default)
|
||||
#
|
||||
# 3. System property java.io.tmpdir
|
||||
#
|
||||
jdk.net.unixdomain.tmpdir=/tmp
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -34,10 +34,11 @@
|
|||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "net_util.h"
|
||||
#include "nio_util.h"
|
||||
|
||||
#include "sun_nio_ch_InheritedChannel.h"
|
||||
|
||||
static int matchFamily(SOCKETADDRESS *sa) {
|
||||
static int toInetFamily(SOCKETADDRESS *sa) {
|
||||
return (sa->sa.sa_family == (ipv6_available() ? AF_INET6 : AF_INET));
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,7 @@ Java_sun_nio_ch_InheritedChannel_initIDs(JNIEnv *env, jclass cla)
|
|||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
|
||||
Java_sun_nio_ch_InheritedChannel_inetPeerAddress0(JNIEnv *env, jclass cla, jint fd)
|
||||
{
|
||||
SOCKETADDRESS sa;
|
||||
socklen_t len = sizeof(SOCKETADDRESS);
|
||||
|
@ -57,7 +58,7 @@ Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
|
|||
jint remote_port;
|
||||
|
||||
if (getpeername(fd, &sa.sa, &len) == 0) {
|
||||
if (matchFamily(&sa)) {
|
||||
if (toInetFamily(&sa)) {
|
||||
remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +66,21 @@ Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd)
|
|||
return remote_ia;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_sun_nio_ch_InheritedChannel_unixPeerAddress0(JNIEnv *env, jclass cla, jint fd)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
socklen_t len = sizeof(struct sockaddr_un);
|
||||
jobject remote_sa = NULL;
|
||||
|
||||
if (getpeername(fd, (struct sockaddr *)&sa, &len) == 0) {
|
||||
if (sa.sun_family == AF_UNIX) {
|
||||
remote_sa = sockaddrToUnixAddressBytes(env, &sa, len);
|
||||
}
|
||||
}
|
||||
return remote_sa;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd)
|
||||
{
|
||||
|
@ -72,8 +88,8 @@ Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd)
|
|||
socklen_t len = sizeof(SOCKETADDRESS);
|
||||
jint remote_port = -1;
|
||||
|
||||
if (getpeername(fd, &sa.sa, &len) == 0) {
|
||||
if (matchFamily(&sa)) {
|
||||
if (getpeername(fd, (struct sockaddr *)&sa.sa, &len) == 0) {
|
||||
if (toInetFamily(&sa)) {
|
||||
NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
|
||||
}
|
||||
}
|
||||
|
|
194
src/java.base/unix/native/libnio/ch/UnixDomainSockets.c
Normal file
194
src/java.base/unix/native/libnio/ch/UnixDomainSockets.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "jni.h"
|
||||
#include "java_props.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
#include "jlong.h"
|
||||
#include "sun_nio_ch_Net.h"
|
||||
#include "nio_util.h"
|
||||
#include "nio.h"
|
||||
|
||||
/* Subtle platform differences in how unnamed sockets (empty path)
|
||||
* are returned from getsockname()
|
||||
*/
|
||||
#ifdef MACOSX
|
||||
#define ZERO_PATHLEN(len) (JNI_FALSE)
|
||||
#else
|
||||
#define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path))
|
||||
#endif
|
||||
|
||||
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len)
|
||||
{
|
||||
if (sa->sun_family == AF_UNIX) {
|
||||
int namelen;
|
||||
if (ZERO_PATHLEN(len)) {
|
||||
namelen = 0;
|
||||
} else {
|
||||
namelen = strlen(sa->sun_path);
|
||||
}
|
||||
jbyteArray name = (*env)->NewByteArray(env, namelen);
|
||||
if (namelen != 0) {
|
||||
(*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray path, struct sockaddr_un *sa, int *len)
|
||||
{
|
||||
memset(sa, 0, sizeof(struct sockaddr_un));
|
||||
sa->sun_family = AF_UNIX;
|
||||
int ret;
|
||||
const char* pname = (const char *)(*env)->GetByteArrayElements(env, path, NULL);
|
||||
if (pname == NULL) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present");
|
||||
return -1;
|
||||
}
|
||||
size_t name_len = (*env)->GetArrayLength(env, path);
|
||||
if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long");
|
||||
ret = -1;
|
||||
} else {
|
||||
memcpy(sa->sun_path, pname, name_len);
|
||||
*len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len + 1);
|
||||
ret = 0;
|
||||
}
|
||||
(*env)->ReleaseByteArrayElements(env, path, (jbyte *)pname, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_UnixDomainSockets_socketSupported(JNIEnv *env, jclass cl)
|
||||
{
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl)
|
||||
{
|
||||
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
return handleSocketError(env, errno);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
int sa_len = 0;
|
||||
int rv = 0;
|
||||
|
||||
if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0)
|
||||
return;
|
||||
|
||||
rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
||||
if (rv != 0) {
|
||||
handleSocketError(env, errno);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
int sa_len = 0;
|
||||
int rv;
|
||||
|
||||
if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) {
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
|
||||
if (rv != 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
return IOS_UNAVAILABLE;
|
||||
} else if (errno == EINTR) {
|
||||
return IOS_INTERRUPTED;
|
||||
}
|
||||
return handleSocketError(env, errno);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo,
|
||||
jobjectArray array)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
jint newfd;
|
||||
struct sockaddr_un sa;
|
||||
socklen_t sa_len = sizeof(struct sockaddr_un);
|
||||
jbyteArray address;
|
||||
|
||||
newfd = accept(fd, (struct sockaddr *)&sa, &sa_len);
|
||||
if (newfd < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return IOS_UNAVAILABLE;
|
||||
if (errno == EINTR)
|
||||
return IOS_INTERRUPTED;
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
|
||||
setfdval(env, newfdo, newfd);
|
||||
|
||||
address = sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
||||
CHECK_NULL_RETURN(address, IOS_THROWN);
|
||||
|
||||
(*env)->SetObjectArrayElement(env, array, 0, address);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
socklen_t sa_len = sizeof(struct sockaddr_un);
|
||||
int port;
|
||||
if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
|
||||
handleSocketError(env, errno);
|
||||
return NULL;
|
||||
}
|
||||
return sockaddrToUnixAddressBytes(env, &sa, sa_len);
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include "jlong.h"
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define RESTARTABLE(_cmd, _result) do { \
|
||||
do { \
|
||||
|
@ -47,6 +48,12 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* 2 bytes to allow for null at end of string and null at start of string
|
||||
* for abstract name
|
||||
*/
|
||||
#define MAX_UNIX_DOMAIN_PATH_LEN \
|
||||
(int)(sizeof(((struct sockaddr_un *)0)->sun_path)-2)
|
||||
|
||||
/* NIO utility procedures */
|
||||
|
||||
|
||||
|
@ -62,3 +69,15 @@ jlong convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading);
|
|||
/* Defined in Net.c */
|
||||
|
||||
jint handleSocketError(JNIEnv *env, jint errorValue);
|
||||
|
||||
/* Defined in UnixDomainSockets.c */
|
||||
|
||||
jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env,
|
||||
struct sockaddr_un *sa,
|
||||
socklen_t len);
|
||||
|
||||
jint unixSocketAddressToSockaddr(JNIEnv *env,
|
||||
jbyteArray uaddr,
|
||||
struct sockaddr_un *sa,
|
||||
int *len);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue