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

@ -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

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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));

View 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

View file

@ -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);
}
}

View 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);
}

View file

@ -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);