am d30aac6c: Merge "Rearrange how AF_UNIX sockets are handled for accept()"
* commit 'd30aac6cafe07baaa84efcf82f9c5108e7a5c0b7':
Rearrange how AF_UNIX sockets are handled for accept()
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index a1e87c8..2e8d37f 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -43,6 +43,12 @@
public static FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { return Libcore.os.accept(fd, peerAddress); }
/**
+ * TODO Change the public API by removing the overload above and unhiding this version.
+ * @hide
+ */
+ public static FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException { return Libcore.os.accept(fd, peerAddress); }
+
+ /**
* See <a href="http://man7.org/linux/man-pages/man2/access.2.html">access(2)</a>.
*/
public static boolean access(String path, int mode) throws ErrnoException { return Libcore.os.access(path, mode); }
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index 11e5d22..42b0427 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -490,6 +490,7 @@
public static final int S_IXUSR = placeholder();
public static final int TCP_NODELAY = placeholder();
/** @hide */ public static final int TIOCOUTQ = placeholder();
+ /** @hide */ public static final int UNIX_PATH_MAX = placeholder();
public static final int WCONTINUED = placeholder();
public static final int WEXITED = placeholder();
public static final int WNOHANG = placeholder();
diff --git a/luni/src/main/java/android/system/UnixSocketAddress.java b/luni/src/main/java/android/system/UnixSocketAddress.java
new file mode 100644
index 0000000..5c9369d
--- /dev/null
+++ b/luni/src/main/java/android/system/UnixSocketAddress.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.system;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * A UNIX-domain (AF_UNIX / AF_LOCAL) socket address.
+ *
+ * @hide
+ */
+public final class UnixSocketAddress extends SocketAddress {
+
+ private static final int NAMED_PATH_LENGTH = OsConstants.UNIX_PATH_MAX;
+ private static final byte[] UNNAMED_PATH = new byte[0];
+
+ // See unix(7): Three types of UnixSocketAddress:
+ // 1) pathname: sun_path.length == NAMED_PATH_LENGTH, sun_path[0] != 0.
+ // 2) unnamed: sun_path = [].
+ // 3) abstract: sun_path.length == NAMED_PATH_LENGTH, sun_path[0] == 0.
+ private byte[] sun_path;
+
+ /** This constructor is also used from JNI. */
+ private UnixSocketAddress(byte[] sun_path) {
+ if (sun_path == null) {
+ throw new IllegalArgumentException("sun_path must not be null");
+ }
+ if (sun_path.length > NAMED_PATH_LENGTH) {
+ throw new IllegalArgumentException("sun_path exceeds the maximum length");
+ }
+
+ if (sun_path.length == 0) {
+ this.sun_path = UNNAMED_PATH;
+ } else {
+ this.sun_path = new byte[NAMED_PATH_LENGTH];
+ System.arraycopy(sun_path, 0, this.sun_path, 0, sun_path.length);
+ }
+ }
+
+ /**
+ * Creates a named, abstract AF_UNIX socket address.
+ */
+ public static UnixSocketAddress createAbstract(String name) {
+ byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
+ // Abstract sockets have a path that starts with (byte) 0.
+ byte[] path = new byte[nameBytes.length + 1];
+ System.arraycopy(nameBytes, 0, path, 1, nameBytes.length);
+ return new UnixSocketAddress(path);
+ }
+
+ /**
+ * Creates a named, filesystem AF_UNIX socket address.
+ */
+ public static UnixSocketAddress createFileSystem(String path) {
+ return new UnixSocketAddress(path.getBytes(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Creates an unnamed, filesystem AF_UNIX socket address.
+ */
+ public static UnixSocketAddress createUnnamed() {
+ return new UnixSocketAddress(UNNAMED_PATH);
+ }
+
+ /** Used for testing. */
+ public byte[] getSunPath() {
+ if (sun_path.length == 0) {
+ return sun_path;
+ }
+ byte[] sunPathCopy = new byte[sun_path.length];
+ System.arraycopy(sun_path, 0, sunPathCopy, 0, sun_path.length);
+ return sunPathCopy;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ UnixSocketAddress that = (UnixSocketAddress) o;
+ return Arrays.equals(sun_path, that.sun_path);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(sun_path);
+ }
+
+ @Override
+ public String toString() {
+ return "UnixSocketAddress{" +
+ "sun_path=" + Arrays.toString(sun_path) +
+ '}';
+ }
+}
diff --git a/luni/src/main/java/java/net/InetUnixAddress.java b/luni/src/main/java/java/net/InetUnixAddress.java
deleted file mode 100644
index 51236e2..0000000
--- a/luni/src/main/java/java/net/InetUnixAddress.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.net;
-
-import java.nio.charset.StandardCharsets;
-
-import static android.system.OsConstants.*;
-
-/**
- * An AF_UNIX address. See {@link InetAddress}.
- * @hide
- */
-public final class InetUnixAddress extends InetAddress {
- /**
- * Constructs an AF_UNIX InetAddress for the given path.
- */
- public InetUnixAddress(String path) {
- this(path.getBytes(StandardCharsets.UTF_8));
- }
-
- /**
- * Constructs an AF_UNIX InetAddress for the given path.
- */
- public InetUnixAddress(byte[] path) {
- super(AF_UNIX, path, null);
- }
-
- /**
- * Returns a string form of this InetAddress.
- */
- @Override public String toString() {
- return "InetUnixAddress[" + new String(ipaddress, StandardCharsets.UTF_8) + "]";
- }
-}
diff --git a/luni/src/main/java/libcore/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index 532493a..0923c85 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -28,6 +28,7 @@
import java.io.InterruptedIOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import static android.system.OsConstants.*;
@@ -58,7 +59,7 @@
}
}
- @Override public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException {
+ @Override public FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException {
BlockGuard.getThreadPolicy().onNetwork();
return tagSocket(os.accept(fd, peerAddress));
}
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index cb77573..758b4bd 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -50,7 +50,7 @@
this.os = os;
}
- public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { return os.accept(fd, peerAddress); }
+ public FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException { return os.accept(fd, peerAddress); }
public boolean access(String path, int mode) throws ErrnoException { return os.access(path, mode); }
public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return os.android_getaddrinfo(node, hints, netId); }
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.bind(fd, address, port); }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 6d28b95..36ff6ce 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -41,7 +41,7 @@
import java.nio.ByteBuffer;
public interface Os {
- public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
+ public FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException;
public boolean access(String path, int mode) throws ErrnoException;
public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 151809d..09ee313 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -44,7 +44,7 @@
public final class Posix implements Os {
Posix() { }
- public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
+ public native FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException;
public native boolean access(String path, int mode) throws ErrnoException;
public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
diff --git a/luni/src/main/native/NetworkUtilities.cpp b/luni/src/main/native/NetworkUtilities.cpp
index 7215306..f2d0f8a 100644
--- a/luni/src/main/native/NetworkUtilities.cpp
+++ b/luni/src/main/native/NetworkUtilities.cpp
@@ -61,10 +61,6 @@
addressLength = 16;
sin_port = ntohs(sin6.sin6_port);
scope_id = sin6.sin6_scope_id;
- } else if (ss.ss_family == AF_UNIX) {
- const sockaddr_un& sun = reinterpret_cast<const sockaddr_un&>(ss);
- rawAddress = &sun.sun_path;
- addressLength = strlen(sun.sun_path);
} else {
// We can't throw SocketException. We aren't meant to see bad addresses, so seeing one
// really does imply an internal error.
@@ -83,14 +79,6 @@
env->SetByteArrayRegion(byteArray.get(), 0, addressLength,
reinterpret_cast<const jbyte*>(rawAddress));
- if (ss.ss_family == AF_UNIX) {
- // Note that we get here for AF_UNIX sockets on accept(2). The unix(7) man page claims
- // that the peer's sun_path will contain the path, but in practice it doesn't, and the
- // peer length is returned as 2 (meaning only the sun_family field was set).
- static jmethodID ctor = env->GetMethodID(JniConstants::inetUnixAddressClass, "<init>", "([B)V");
- return env->NewObject(JniConstants::inetUnixAddressClass, ctor, byteArray.get());
- }
-
static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inetAddressClass,
"getByAddress", "(Ljava/lang/String;[BI)Ljava/net/InetAddress;");
if (getByAddressMethod == NULL) {
@@ -118,7 +106,7 @@
}
// Check this is an address family we support.
- if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6 && ss.ss_family != AF_UNIX) {
+ if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"inetAddressToSockaddr bad family: %i", ss.ss_family);
return false;
@@ -132,25 +120,6 @@
return false;
}
- // Handle the AF_UNIX special case.
- if (ss.ss_family == AF_UNIX) {
- sockaddr_un& sun = reinterpret_cast<sockaddr_un&>(ss);
-
- size_t path_length = env->GetArrayLength(addressBytes.get());
- if (path_length >= sizeof(sun.sun_path)) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "inetAddressToSockaddr path too long for AF_UNIX: %i", path_length);
- return false;
- }
-
- // Copy the bytes...
- jbyte* dst = reinterpret_cast<jbyte*>(&sun.sun_path);
- memset(dst, 0, sizeof(sun.sun_path));
- env->GetByteArrayRegion(addressBytes.get(), 0, path_length, dst);
- sa_len = sizeof(sun.sun_path);
- return true;
- }
-
// TODO: bionic's getnameinfo(3) seems to want its length parameter to be exactly
// sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
// IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
diff --git a/luni/src/main/native/NetworkUtilities.h b/luni/src/main/native/NetworkUtilities.h
index 6b720d4..db1ad1f 100644
--- a/luni/src/main/native/NetworkUtilities.h
+++ b/luni/src/main/native/NetworkUtilities.h
@@ -17,25 +17,24 @@
#include "jni.h"
#include <sys/socket.h>
-// Convert from sockaddr_storage to Inet4Address (AF_INET), Inet6Address (AF_INET6), or
-// InetUnixAddress (AF_UNIX). If 'port' is non-NULL and the address family includes a notion
+// Convert from sockaddr_storage to Inet4Address (AF_INET) or Inet6Address (AF_INET6).
+// If 'port' is non-NULL and the address family includes a notion
// of port number, *port will be set to the port number.
jobject sockaddrToInetAddress(JNIEnv* env, const sockaddr_storage& ss, int* port);
-// Convert from InetAddress to sockaddr_storage. An InetUnixAddress will be converted to
-// an AF_UNIX sockaddr_un. An Inet6Address will be converted to an AF_INET6 sockaddr_in6.
-// An Inet4Address will be converted to an IPv4-mapped AF_INET6 sockaddr_in6. This is what
-// you want if you're about to perform an operation on a socket, since all our sockets
-// are AF_INET6.
+// Convert from InetAddress to sockaddr_storage. An Inet6Address will be converted to an
+// AF_INET6 sockaddr_in6. An Inet4Address will be converted to an IPv4-mapped AF_INET6
+// sockaddr_in6. This is what you want if you're about to perform an operation on a socket,
+// since all our sockets are AF_INET6.
bool inetAddressToSockaddr(JNIEnv* env, jobject inetAddress, int port,
sockaddr_storage& ss, socklen_t& sa_len);
-// Convert from InetAddress to sockaddr_storage. An InetUnixAddress will be converted to
-// an AF_UNIX sockaddr_un. An Inet6Address will be converted to an AF_INET6 sockaddr_in6.
-// An Inet4Address will be converted to a sockaddr_in. This is probably only useful for
-// getnameinfo(2), where we'll be presenting the result to the user and the user may actually
-// care whether the original address was pure IPv4 or an IPv4-mapped IPv6 address, and
-// for the MCAST_JOIN_GROUP, MCAST_LEAVE_GROUP, and other multicast socket options.
+// Convert from InetAddress to sockaddr_storage. An Inet6Address will be converted to an
+// AF_INET6 sockaddr_in6. An Inet4Address will be converted to a sockaddr_in. This is probably
+// only useful for getnameinfo(2), where we'll be presenting the result to the user and the
+// user may actually care whether the original address was pure IPv4 or an IPv4-mapped IPv6
+// address, and for the MCAST_JOIN_GROUP, MCAST_LEAVE_GROUP, and other multicast socket
+// options.
bool inetAddressToSockaddrVerbatim(JNIEnv* env, jobject inetAddress, int port,
sockaddr_storage& ss, socklen_t& sa_len);
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 38d9129..b84cf5a 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -35,6 +35,7 @@
#endif
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/un.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
@@ -551,6 +552,8 @@
initConstant(env, c, "S_IXUSR", S_IXUSR);
initConstant(env, c, "TCP_NODELAY", TCP_NODELAY);
initConstant(env, c, "TIOCOUTQ", TIOCOUTQ);
+ // UNIX_PATH_MAX is mentioned in some versions of unix(7), but not actually declared.
+ initConstant(env, c, "UNIX_PATH_MAX", sizeof(sockaddr_un::sun_path));
initConstant(env, c, "WCONTINUED", WCONTINUED);
initConstant(env, c, "WEXITED", WEXITED);
initConstant(env, c, "WNOHANG", WNOHANG);
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 99b76f9..ff5b106 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -57,6 +57,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
+#include <sys/un.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/xattr.h>
@@ -317,8 +318,35 @@
std::vector<ScopedT*> mScopedBuffers;
};
-static jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage& ss) {
- if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6 || ss.ss_family == AF_UNIX) {
+/**
+ * Returns the address and length of sockaddr_un.sun_path in ss. As per unix(7) sa_len should be
+ * the length of ss as returned by getsockname(2), getpeername(2), or accept(2). After the call path
+ * will point to sun_path and pathLength will contain the sun_path length. If pathLength is 0 then
+ * the sockaddr_un refers to is an unnamed socket. See unix(7) for more information.
+ */
+static bool getUnixSocketPath(JNIEnv* env, const sockaddr_storage& ss, const socklen_t& sa_len,
+ const void*& path, size_t& pathLength) {
+
+ if (ss.ss_family != AF_UNIX) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "getUnixSocketPath unsupported ss_family: %i", ss.ss_family);
+ return false;
+ }
+ const struct sockaddr_un* un_addr = reinterpret_cast<const struct sockaddr_un*>(&ss);
+ path = &un_addr->sun_path;
+ // See unix(7) for details.
+ if (sa_len == sizeof(sa_family_t)) {
+ // unnamed
+ pathLength = 0;
+ } else {
+ // pathname or abstract. We just return the fixed array length here.
+ pathLength = sizeof(sockaddr_un::sun_path);
+ }
+ return true;
+}
+
+static jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage& ss, const socklen_t sa_len) {
+ if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
jint port;
jobject inetAddress = sockaddrToInetAddress(env, ss, &port);
if (inetAddress == NULL) {
@@ -327,6 +355,23 @@
static jmethodID ctor = env->GetMethodID(JniConstants::inetSocketAddressClass,
"<init>", "(Ljava/net/InetAddress;I)V");
return env->NewObject(JniConstants::inetSocketAddressClass, ctor, inetAddress, port);
+ } else if (ss.ss_family == AF_UNIX) {
+ static jmethodID ctor = env->GetMethodID(JniConstants::unixSocketAddressClass,
+ "<init>", "([B)V");
+
+ const void* pathAddress;
+ size_t pathLength;
+ if (!getUnixSocketPath(env, ss, sa_len, pathAddress, pathLength)) {
+ return NULL;
+ }
+
+ ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(pathLength));
+ if (byteArray.get() == NULL) {
+ return NULL;
+ }
+ env->SetByteArrayRegion(byteArray.get(), 0, pathLength,
+ reinterpret_cast<const jbyte*>(pathAddress));
+ return env->NewObject(JniConstants::unixSocketAddressClass, ctor, byteArray.get());
} else if (ss.ss_family == AF_NETLINK) {
const struct sockaddr_nl* nl_addr = reinterpret_cast<const struct sockaddr_nl*>(&ss);
static jmethodID ctor = env->GetMethodID(JniConstants::netlinkSocketAddressClass,
@@ -448,8 +493,34 @@
return true;
}
-static bool fillInetSocketAddress(JNIEnv* env, jint rc, jobject javaInetSocketAddress, const sockaddr_storage& ss) {
- if (rc == -1 || javaInetSocketAddress == NULL) {
+static bool fillUnixSocketAddress(JNIEnv* env, jobject javaUnixSocketAddress,
+ const sockaddr_storage& ss, const socklen_t& sa_len) {
+ if (javaUnixSocketAddress == NULL) {
+ return true;
+ }
+ const void* pathAddress;
+ size_t pathLength;
+ if (!getUnixSocketPath(env, ss, sa_len, pathAddress, pathLength)) {
+ return false;
+ }
+
+ static jfieldID sunPathFid =
+ env->GetFieldID(JniConstants::unixSocketAddressClass, "sun_path", "[B");
+ ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(pathLength));
+ if (byteArray.get() == NULL) {
+ return false;
+ }
+ if (pathLength > 0) {
+ env->SetByteArrayRegion(byteArray.get(), 0, pathLength,
+ reinterpret_cast<const jbyte*>(pathAddress));
+ }
+ env->SetObjectField(javaUnixSocketAddress, sunPathFid, byteArray.get());
+ return true;
+}
+
+static bool fillInetSocketAddress(JNIEnv* env, jobject javaInetSocketAddress,
+ const sockaddr_storage& ss) {
+ if (javaInetSocketAddress == NULL) {
return true;
}
// Fill out the passed-in InetSocketAddress with the sender's IP address and port number.
@@ -465,6 +536,23 @@
return true;
}
+static bool fillSocketAddress(JNIEnv* env, jobject javaSocketAddress, const sockaddr_storage& ss,
+ const socklen_t& sa_len) {
+ if (javaSocketAddress == NULL) {
+ return true;
+ }
+
+ if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
+ return fillInetSocketAddress(env, javaSocketAddress, ss);
+ } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::unixSocketAddressClass)) {
+ return fillUnixSocketAddress(env, javaSocketAddress, ss, sa_len);
+ }
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "unsupported SocketAddress subclass");
+ return false;
+
+}
+
static void javaInetSocketAddressToInetAddressAndPort(
JNIEnv* env, jobject javaInetSocketAddress, jobject& javaInetAddress, jint& port) {
static jfieldID addressFid = env->GetFieldID(
@@ -497,6 +585,33 @@
return true;
}
+static bool javaUnixSocketAddressToSockaddr(
+ JNIEnv* env, jobject javaUnixSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
+ static jfieldID sunPathFid = env->GetFieldID(
+ JniConstants::unixSocketAddressClass, "sun_path", "[B");
+
+ struct sockaddr_un* un_addr = reinterpret_cast<struct sockaddr_un*>(&ss);
+ un_addr->sun_family = AF_UNIX;
+
+ jbyteArray javaSunPath = (jbyteArray) env->GetObjectField(javaUnixSocketAddress, sunPathFid);
+ jsize pathLength = env->GetArrayLength(javaSunPath);
+ if (pathLength == 0) {
+ sa_len = sizeof(sa_family_t);
+ } else {
+ const size_t sun_path_length = sizeof(sockaddr_un::sun_path);
+ if ((size_t) pathLength != sun_path_length) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "sun_path incorrect size: expected=%i, was=%i",
+ sun_path_length, pathLength);
+ return false;
+ }
+ memset(&un_addr->sun_path, 0, sun_path_length);
+ env->GetByteArrayRegion(javaSunPath, 0, pathLength, (jbyte*) un_addr->sun_path);
+ sa_len = sizeof(sockaddr_un);
+ }
+ return true;
+}
+
static bool javaPacketSocketAddressToSockaddr(
JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
static jfieldID protocolFid = env->GetFieldID(
@@ -546,6 +661,8 @@
return javaInetSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
} else if (env->IsInstanceOf(javaSocketAddress, JniConstants::packetSocketAddressClass)) {
return javaPacketSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
+ } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::unixSocketAddressClass)) {
+ return javaUnixSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
}
jniThrowException(env, "java/lang/UnsupportedOperationException",
"unsupported SocketAddress subclass");
@@ -579,7 +696,7 @@
throwErrnoException(env, is_sockname ? "getsockname" : "getpeername");
return NULL;
}
- return makeSocketAddress(env, ss);
+ return makeSocketAddress(env, ss, byteCount);
}
class Passwd {
@@ -618,14 +735,14 @@
struct passwd* mResult;
};
-static jobject Posix_accept(JNIEnv* env, jobject, jobject javaFd, jobject javaInetSocketAddress) {
+static jobject Posix_accept(JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
sockaddr_storage ss;
socklen_t sl = sizeof(ss);
memset(&ss, 0, sizeof(ss));
- sockaddr* peer = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
- socklen_t* peerLength = (javaInetSocketAddress != NULL) ? &sl : 0;
+ sockaddr* peer = (javaSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
+ socklen_t* peerLength = (javaSocketAddress != NULL) ? &sl : 0;
jint clientFd = NET_FAILURE_RETRY(env, int, accept, javaFd, peer, peerLength);
- if (clientFd == -1 || !fillInetSocketAddress(env, clientFd, javaInetSocketAddress, ss)) {
+ if (clientFd == -1 || !fillSocketAddress(env, javaSocketAddress, ss, *peerLength)) {
close(clientFd);
return NULL;
}
@@ -1435,7 +1552,10 @@
sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
jint recvCount = NET_FAILURE_RETRY(env, ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
- fillInetSocketAddress(env, recvCount, javaInetSocketAddress, ss);
+ if (recvCount == -1) {
+ return recvCount;
+ }
+ fillInetSocketAddress(env, javaInetSocketAddress, ss);
return recvCount;
}
@@ -1856,7 +1976,7 @@
{ #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName ## variant) }
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Posix, accept, "(Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)Ljava/io/FileDescriptor;"),
+ NATIVE_METHOD(Posix, accept, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
NATIVE_METHOD(Posix, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index 9b38ee9..b116276 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -22,6 +22,8 @@
import android.system.PacketSocketAddress;
import android.system.StructTimeval;
import android.system.StructUcred;
+import android.system.UnixSocketAddress;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -30,10 +32,8 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
-import java.net.InetUnixAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
-import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@@ -70,19 +70,25 @@
public void testUnixDomainSockets_in_file_system() throws Exception {
String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
new File(path).delete();
- checkUnixDomainSocket(new InetUnixAddress(path), false);
+ checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false);
}
public void testUnixDomainSocket_abstract_name() throws Exception {
// Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7).
- byte[] path = "/abstract_name_unix_socket".getBytes("UTF-8");
- path[0] = 0;
- checkUnixDomainSocket(new InetUnixAddress(path), true);
+ checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true);
}
- private void checkUnixDomainSocket(final InetUnixAddress address, final boolean isAbstract) throws Exception {
+ public void testUnixDomainSocket_unnamed() throws Exception {
+ final FileDescriptor fd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
+ // unix(7) says an unbound socket is unnamed.
+ checkNoSockName(fd);
+ Libcore.os.close(fd);
+ }
+
+ private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)
+ throws Exception {
final FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
- Libcore.os.bind(serverFd, address, 0);
+ Libcore.os.bind(serverFd, address);
Libcore.os.listen(serverFd, 5);
checkSockName(serverFd, isAbstract, address);
@@ -90,7 +96,7 @@
Thread server = new Thread(new Runnable() {
public void run() {
try {
- InetSocketAddress peerAddress = new InetSocketAddress();
+ UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed();
FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress);
checkSockName(clientFd, isAbstract, address);
checkNoName(peerAddress);
@@ -119,7 +125,7 @@
FileDescriptor clientFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
- Libcore.os.connect(clientFd, address, 0);
+ Libcore.os.connect(clientFd, address);
checkNoSockName(clientFd);
String string = "hello, world!";
@@ -135,26 +141,24 @@
Libcore.os.close(clientFd);
}
- private void checkSockName(FileDescriptor fd, boolean isAbstract, InetAddress address) throws Exception {
- InetSocketAddress isa = (InetSocketAddress) Libcore.os.getsockname(fd);
+ private static void checkSockName(FileDescriptor fd, boolean isAbstract, UnixSocketAddress address) throws Exception {
+ UnixSocketAddress isa = (UnixSocketAddress) Libcore.os.getsockname(fd);
+ assertEquals(address, isa);
if (isAbstract) {
- checkNoName(isa);
- } else {
- assertEquals(address, isa.getAddress());
+ assertEquals(0, isa.getSunPath()[0]);
}
}
- private void checkNoName(SocketAddress sa) {
- InetSocketAddress isa = (InetSocketAddress) sa;
- assertEquals(0, isa.getAddress().getAddress().length);
+ private void checkNoName(UnixSocketAddress usa) {
+ assertEquals(0, usa.getSunPath().length);
}
private void checkNoPeerName(FileDescriptor fd) throws Exception {
- checkNoName(Libcore.os.getpeername(fd));
+ checkNoName((UnixSocketAddress) Libcore.os.getpeername(fd));
}
private void checkNoSockName(FileDescriptor fd) throws Exception {
- checkNoName(Libcore.os.getsockname(fd));
+ checkNoName((UnixSocketAddress) Libcore.os.getsockname(fd));
}
public void test_strsignal() throws Exception {