diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2015-03-16 11:06:48 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-03-16 11:06:48 +0000 |
commit | 1dacfbb464d8d21c312cca681a1a297e0f632f08 (patch) | |
tree | 2729e3e1c0f6e09f1d923c19aacfc297d1781913 | |
parent | 1ab902acc995d6ef7a297959d57b6d8715a0bd2a (diff) | |
parent | 7d6411b79ecf1a6e2ed0e9a5af2113826e32030f (diff) | |
download | libcore-1dacfbb464d8d21c312cca681a1a297e0f632f08.zip libcore-1dacfbb464d8d21c312cca681a1a297e0f632f08.tar.gz libcore-1dacfbb464d8d21c312cca681a1a297e0f632f08.tar.bz2 |
am 7d6411b7: Merge "Support packet sockets in libcore."
* commit '7d6411b79ecf1a6e2ed0e9a5af2113826e32030f':
Support packet sockets in libcore.
-rw-r--r-- | luni/src/main/java/android/system/OsConstants.java | 6 | ||||
-rw-r--r-- | luni/src/main/native/android_system_OsConstants.cpp | 9 | ||||
-rw-r--r-- | luni/src/main/native/libcore_io_Posix.cpp | 63 | ||||
-rw-r--r-- | luni/src/test/java/libcore/io/OsTest.java | 22 |
4 files changed, 98 insertions, 2 deletions
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java index acc4435..c0d31e5 100644 --- a/luni/src/main/java/android/system/OsConstants.java +++ b/luni/src/main/java/android/system/OsConstants.java @@ -96,6 +96,7 @@ public final class OsConstants { public static final int AF_INET = placeholder(); public static final int AF_INET6 = placeholder(); /** @hide */ public static final int AF_NETLINK = placeholder(); + /** @hide */ public static final int AF_PACKET = placeholder(); public static final int AF_UNIX = placeholder(); public static final int AF_UNSPEC = placeholder(); public static final int AI_ADDRCONFIG = placeholder(); @@ -105,6 +106,8 @@ public final class OsConstants { public static final int AI_NUMERICSERV = placeholder(); public static final int AI_PASSIVE = placeholder(); public static final int AI_V4MAPPED = placeholder(); + /** @hide */ public static final int ARPHRD_ETHER = placeholder(); + /** @hide */ public static final int ARPHRD_LOOPBACK = placeholder(); public static final int CAP_AUDIT_CONTROL = placeholder(); public static final int CAP_AUDIT_WRITE = placeholder(); public static final int CAP_BLOCK_SUSPEND = placeholder(); @@ -228,6 +231,9 @@ public final class OsConstants { public static final int ESPIPE = placeholder(); public static final int ESRCH = placeholder(); public static final int ESTALE = placeholder(); + /** @hide */ public static final int ETH_P_ARP = placeholder(); + /** @hide */ public static final int ETH_P_IP = placeholder(); + /** @hide */ public static final int ETH_P_IPV6 = placeholder(); public static final int ETIME = placeholder(); public static final int ETIMEDOUT = placeholder(); public static final int ETXTBSY = placeholder(); diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp index 0c55305..a9031f4 100644 --- a/luni/src/main/native/android_system_OsConstants.cpp +++ b/luni/src/main/native/android_system_OsConstants.cpp @@ -38,6 +38,9 @@ #include <sys/wait.h> #include <unistd.h> +#include <net/if_arp.h> +#include <linux/if_ether.h> + // After the others because these are not necessarily self-contained in glibc. #ifndef __APPLE__ #include <linux/if_addr.h> @@ -58,6 +61,7 @@ static void initConstant(JNIEnv* env, jclass c, const char* fieldName, int value static void OsConstants_initConstants(JNIEnv* env, jclass c) { initConstant(env, c, "AF_INET", AF_INET); initConstant(env, c, "AF_INET6", AF_INET6); + initConstant(env, c, "AF_PACKET", AF_PACKET); initConstant(env, c, "AF_NETLINK", AF_NETLINK); initConstant(env, c, "AF_UNIX", AF_UNIX); initConstant(env, c, "AF_UNSPEC", AF_UNSPEC); @@ -70,6 +74,8 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) { #endif initConstant(env, c, "AI_PASSIVE", AI_PASSIVE); initConstant(env, c, "AI_V4MAPPED", AI_V4MAPPED); + initConstant(env, c, "ARPHRD_ETHER", ARPHRD_ETHER); + initConstant(env, c, "ARPHRD_LOOPBACK", ARPHRD_LOOPBACK); #if defined(CAP_LAST_CAP) initConstant(env, c, "CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL); initConstant(env, c, "CAP_AUDIT_WRITE", CAP_AUDIT_WRITE); @@ -197,6 +203,9 @@ static void OsConstants_initConstants(JNIEnv* env, jclass c) { initConstant(env, c, "ESPIPE", ESPIPE); initConstant(env, c, "ESRCH", ESRCH); initConstant(env, c, "ESTALE", ESTALE); + initConstant(env, c, "ETH_P_ARP", ETH_P_ARP); + initConstant(env, c, "ETH_P_IP", ETH_P_IP); + initConstant(env, c, "ETH_P_IPV6", ETH_P_IPV6); initConstant(env, c, "ETIME", ETIME); initConstant(env, c, "ETIMEDOUT", ETIMEDOUT); initConstant(env, c, "ETXTBSY", ETXTBSY); diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp index f41ffe6..12ac3f0 100644 --- a/luni/src/main/native/libcore_io_Posix.cpp +++ b/luni/src/main/native/libcore_io_Posix.cpp @@ -333,8 +333,26 @@ static jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage& ss) { return env->NewObject(JniConstants::netlinkSocketAddressClass, ctor, static_cast<jint>(nl_addr->nl_pid), static_cast<jint>(nl_addr->nl_groups)); - } - jniThrowException(env, "java/lang/IllegalArgumentException", "unsupported ss_family"); + } else if (ss.ss_family == AF_PACKET) { + const struct sockaddr_ll* sll = reinterpret_cast<const struct sockaddr_ll*>(&ss); + static jmethodID ctor = env->GetMethodID(JniConstants::packetSocketAddressClass, + "<init>", "(SISB[B)V"); + ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(sll->sll_halen)); + if (byteArray.get() == NULL) { + return NULL; + } + env->SetByteArrayRegion(byteArray.get(), 0, sll->sll_halen, + reinterpret_cast<const jbyte*>(sll->sll_addr)); + jobject packetSocketAddress = env->NewObject(JniConstants::packetSocketAddressClass, ctor, + static_cast<jshort>(ntohs(sll->sll_protocol)), + static_cast<jint>(sll->sll_ifindex), + static_cast<jshort>(sll->sll_hatype), + static_cast<jbyte>(sll->sll_pkttype), + byteArray.get()); + return packetSocketAddress; + } + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "unsupported ss_family: %d", + ss.ss_family); return NULL; } @@ -472,6 +490,42 @@ static bool javaNetlinkSocketAddressToSockaddr( return true; } +static bool javaPacketSocketAddressToSockaddr( + JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) { + static jfieldID protocolFid = env->GetFieldID( + JniConstants::packetSocketAddressClass, "sll_protocol", "S"); + static jfieldID ifindexFid = env->GetFieldID( + JniConstants::packetSocketAddressClass, "sll_ifindex", "I"); + static jfieldID hatypeFid = env->GetFieldID( + JniConstants::packetSocketAddressClass, "sll_hatype", "S"); + static jfieldID pkttypeFid = env->GetFieldID( + JniConstants::packetSocketAddressClass, "sll_pkttype", "B"); + static jfieldID addrFid = env->GetFieldID( + JniConstants::packetSocketAddressClass, "sll_addr", "[B"); + + sockaddr_ll *sll = reinterpret_cast<sockaddr_ll *>(&ss); + sll->sll_family = AF_PACKET; + sll->sll_protocol = ntohs(env->GetShortField(javaSocketAddress, protocolFid)); + sll->sll_ifindex = env->GetIntField(javaSocketAddress, ifindexFid); + sll->sll_hatype = env->GetShortField(javaSocketAddress, hatypeFid); + sll->sll_pkttype = env->GetByteField(javaSocketAddress, pkttypeFid); + + jbyteArray sllAddr = (jbyteArray) env->GetObjectField(javaSocketAddress, addrFid); + if (sllAddr == NULL) { + sll->sll_halen = 0; + memset(&sll->sll_addr, 0, sizeof(sll->sll_addr)); + } else { + jsize len = env->GetArrayLength(sllAddr); + if ((size_t) len > sizeof(sll->sll_addr)) { + len = sizeof(sll->sll_addr); + } + sll->sll_halen = len; + env->GetByteArrayRegion(sllAddr, 0, len, (jbyte*) sll->sll_addr); + } + sa_len = sizeof(sockaddr_ll); + return true; +} + static bool javaSocketAddressToSockaddr( JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) { if (javaSocketAddress == NULL) { @@ -483,6 +537,8 @@ static bool javaSocketAddressToSockaddr( return javaNetlinkSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len); } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) { return javaInetSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len); + } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::packetSocketAddressClass)) { + return javaPacketSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len); } jniThrowException(env, "java/lang/UnsupportedOperationException", "unsupported SocketAddress subclass"); @@ -1599,6 +1655,9 @@ static void Posix_shutdown(JNIEnv* env, jobject, jobject javaFd, jint how) { } static jobject Posix_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) { + if (domain == AF_PACKET) { + protocol = htons(protocol); // Packet sockets specify the protocol in host byte order. + } int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol))); return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL; } diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java index 5a9d436..3ebbfcd 100644 --- a/luni/src/test/java/libcore/io/OsTest.java +++ b/luni/src/test/java/libcore/io/OsTest.java @@ -18,6 +18,7 @@ package libcore.io; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; +import android.system.PacketSocketAddress; import android.system.StructTimeval; import android.system.StructUcred; import java.io.File; @@ -29,6 +30,7 @@ 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; @@ -291,6 +293,26 @@ public class OsTest extends TestCase { Libcore.os.close(nlSocket); } + public void test_PacketSocketAddress() throws Exception { + NetworkInterface lo = NetworkInterface.getByName("lo"); + FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, (short) ETH_P_IPV6); + PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex()); + Libcore.os.bind(fd, addr); + + PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd); + assertEquals((short) ETH_P_IPV6, bound.sll_protocol); + assertEquals(lo.getIndex(), bound.sll_ifindex); + assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype); + assertEquals(0, bound.sll_pkttype); + + // The loopback address is ETH_ALEN bytes long and is all zeros. + // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167 + assertEquals(6, bound.sll_addr.length); + for (int i = 0; i < 6; i++) { + assertEquals(0, bound.sll_addr[i]); + } + } + public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception { checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1")); } |