diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-11-20 19:13:58 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-11-20 19:13:58 -0800 |
commit | d2c1275661bbebbbb3fae30b6359f71f2628c4b3 (patch) | |
tree | ae525c8a062e4069fa8d062421db0f6099326e20 | |
parent | 1f89002162163659b067809085d9e1d91a6f5378 (diff) | |
parent | b5fc5ecd3fe5315fc2756c0c25adc458cc8c8d91 (diff) | |
download | libcore-d2c1275661bbebbbb3fae30b6359f71f2628c4b3.zip libcore-d2c1275661bbebbbb3fae30b6359f71f2628c4b3.tar.gz libcore-d2c1275661bbebbbb3fae30b6359f71f2628c4b3.tar.bz2 |
Merge change I9fa3ef2c
* changes:
Rewrite NetworkInterface's JNI for IPv6.
-rw-r--r-- | include/LocalArray.h | 16 | ||||
-rw-r--r-- | include/ScopedFd.h | 42 | ||||
-rw-r--r-- | luni/src/main/java/java/net/InterfaceAddress.java | 41 | ||||
-rw-r--r-- | luni/src/main/java/java/net/NetworkInterface.java | 47 | ||||
-rw-r--r-- | luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java | 30 | ||||
-rw-r--r-- | luni/src/main/native/ifaddrs-android.h | 185 | ||||
-rw-r--r-- | luni/src/main/native/java_net_NetworkInterface.cpp | 246 | ||||
-rw-r--r-- | luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp | 1 |
8 files changed, 412 insertions, 196 deletions
diff --git a/include/LocalArray.h b/include/LocalArray.h index 85b5a49..74c9085 100644 --- a/include/LocalArray.h +++ b/include/LocalArray.h @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 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. + */ + #ifndef LOCAL_ARRAY_H_included #define LOCAL_ARRAY_H_included diff --git a/include/ScopedFd.h b/include/ScopedFd.h new file mode 100644 index 0000000..30feabd --- /dev/null +++ b/include/ScopedFd.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef SCOPED_FD_H_included +#define SCOPED_FD_H_included + +#include <unistd.h> + +// A smart pointer that closes the given fd on going out of scope. +// Use this when the fd is incidental to the purpose of your function, +// but needs to be cleaned up on exit. +class ScopedFd { +public: + explicit ScopedFd(int fd) : fd(fd) { + } + + ~ScopedFd() { + close(fd); + } + + int get() const { + return fd; + } + +private: + int fd; +}; + +#endif // SCOPED_FD_H_included diff --git a/luni/src/main/java/java/net/InterfaceAddress.java b/luni/src/main/java/java/net/InterfaceAddress.java new file mode 100644 index 0000000..7bc3936 --- /dev/null +++ b/luni/src/main/java/java/net/InterfaceAddress.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 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; + +/** + * Identifies one of a network interface's addresses. + * These are passed back from the JNI behind NetworkInterface.getNetworkInterfaces. + * Multiple addresses for the same interface are collected together on the Java side. + */ +class InterfaceAddress { + // An IPv4 or IPv6 address. + final InetAddress address; + + // The kernel's interface index for the network interface this address + // is currently assigned to. Values start at 1, because 0 means "unknown" + // or "any", depending on context. + final int index; + + // The network interface's name. "lo" or "eth0", for example. + final String name; + + InterfaceAddress(int index, String name, InetAddress address) { + this.index = index; + this.name = name; + this.address = address; + } +} diff --git a/luni/src/main/java/java/net/NetworkInterface.java b/luni/src/main/java/java/net/NetworkInterface.java index f921b07..93a30cb 100644 --- a/luni/src/main/java/java/net/NetworkInterface.java +++ b/luni/src/main/java/java/net/NetworkInterface.java @@ -19,6 +19,9 @@ package java.net; import java.util.Arrays; import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Vector; import org.apache.harmony.luni.util.Msg; @@ -50,18 +53,34 @@ public final class NetworkInterface extends Object { private int hashCode; - /** - * This {@code native} method returns the list of network interfaces - * supported by the system. An array is returned which is easier to generate - * and which can easily be converted into the required enumeration on the - * java side. - * - * @return an array of zero or more {@code NetworkInterface} objects - * @throws SocketException - * if an error occurs when getting network interface information - */ - private static native NetworkInterface[] getNetworkInterfacesImpl() - throws SocketException; + // BEGIN android-changed: we pay this extra complexity on the Java side + // in return for vastly simpler native code. + private static native InterfaceAddress[] getInterfaceAddresses() throws SocketException; + + private static NetworkInterface[] getNetworkInterfacesImpl() throws SocketException { + Map<String, NetworkInterface> networkInterfaces = new LinkedHashMap<String, NetworkInterface>(); + for (InterfaceAddress ia : getInterfaceAddresses()) { + if (ia != null) { // The array may contain harmless null elements. + String name = ia.name; + NetworkInterface ni = networkInterfaces.get(name); + if (ni == null) { + ni = new NetworkInterface(name, name, new InetAddress[] { ia.address }, ia.index); + networkInterfaces.put(name, ni); + } else { + ni.addInterfaceAddress(ia.address); + } + } + } + return networkInterfaces.values().toArray(new NetworkInterface[networkInterfaces.size()]); + } + + private void addInterfaceAddress(InetAddress address) { + InetAddress[] newAddresses = new InetAddress[addresses.length + 1]; + System.arraycopy(addresses, 0, newAddresses, 0, addresses.length); + newAddresses[addresses.length] = address; + addresses = newAddresses; + } + // END android-changed /** * This constructor is used by the native method in order to construct the @@ -424,6 +443,10 @@ public final class NetworkInterface extends Object { string.append(name); string.append("]["); //$NON-NLS-1$ string.append(displayName); + // BEGIN android-added: the RI shows this, and it's useful for IPv6 users. + string.append("]["); //$NON-NLS-1$ + string.append(interfaceIndex); + // END android-added string.append("]"); //$NON-NLS-1$ /* diff --git a/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java b/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java index da300cd..8a0bd55 100644 --- a/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java +++ b/luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java @@ -17,10 +17,13 @@ package org.apache.harmony.luni.net; +import java.lang.reflect.Field; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Enumeration; /** @@ -38,9 +41,25 @@ final class GenericIPMreq { @SuppressWarnings("unused") private boolean isIPV6Address; - @SuppressWarnings("unused") + // BEGIN android-changed: we need interfaceIdx. private int interfaceIdx; + private static final Field networkInterfaceIndexField = getNetworkInterfaceField(); + private static Field getNetworkInterfaceField() { + return AccessController.doPrivileged(new PrivilegedAction<Field>() { + public Field run() { + try { + Field field = NetworkInterface.class.getDeclaredField("interfaceIndex"); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException e) { + throw new AssertionError(e); + } + } + }); + } + // END android-changed + /** * This constructor is used to create an instance of the object * @@ -64,8 +83,13 @@ final class GenericIPMreq { GenericIPMreq(InetAddress addr, NetworkInterface netInterface) { multiaddr = addr; if (null != netInterface) { - // TODO check if necessary - //interfaceIdx = netInterface.getIndex(); + // BEGIN android-changed: we need interfaceIdx. + try { + interfaceIdx = networkInterfaceIndexField.getInt(netInterface); + } catch (IllegalAccessException ex) { + throw new AssertionError(ex); + } + // END android-changed /* * here we need to get the first IPV4 address as we only use it if diff --git a/luni/src/main/native/ifaddrs-android.h b/luni/src/main/native/ifaddrs-android.h new file mode 100644 index 0000000..c1a2c12 --- /dev/null +++ b/luni/src/main/native/ifaddrs-android.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef IFADDRS_ANDROID_H_included +#define IFADDRS_ANDROID_H_included + +#include <cstring> +#include <new> +#include <sys/types.h> +#include <sys/socket.h> + +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include "LocalArray.h" +#include "ScopedFd.h" + +// Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3). +// We fake it here, so java_net_NetworkInterface.cpp can use that API +// with all the non-portable code being in this file. + +// Source-compatible subset of the BSD struct. +struct ifaddrs { + // Pointer to next struct in list, or NULL at end. + ifaddrs* ifa_next; + + // Interface name. + char* ifa_name; + + // Interface flags. + unsigned int ifa_flags; + + // Interface address. + sockaddr* ifa_addr; + + ifaddrs(ifaddrs* next) + : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL) + { + } + + ~ifaddrs() { + delete ifa_next; + delete[] ifa_name; + delete ifa_addr; + } + + // Sadly, we can't keep the interface index for portability with BSD. + // We'll have to keep the name instead, and re-query the index when + // we need it later. + bool setNameAndFlagsByIndex(int interfaceIndex) { + // Get the name. + char buf[IFNAMSIZ]; + char* name = if_indextoname(interfaceIndex, buf); + if (name == NULL) { + return false; + } + ifa_name = new char[strlen(name) + 1]; + strcpy(ifa_name, name); + + // Get the flags. + ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0)); + if (fd.get() == -1) { + return false; + } + ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, name); + int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr); + if (rc == -1) { + return false; + } + ifa_flags = ifr.ifr_flags; + return true; + } + + // Netlink gives us the address family in the header, and the + // sockaddr_in or sockaddr_in6 bytes as the payload. We need to + // stitch the two bits together into the sockaddr that's part of + // our portable interface. + void setAddress(int family, void* data, size_t byteCount) { + sockaddr_storage* ss = new sockaddr_storage; + ss->ss_family = family; + if (family == AF_INET) { + void* dst = &reinterpret_cast<sockaddr_in*>(ss)->sin_addr; + memcpy(dst, data, byteCount); + } else if (family == AF_INET6) { + void* dst = &reinterpret_cast<sockaddr_in6*>(ss)->sin6_addr; + memcpy(dst, data, byteCount); + } + ifa_addr = reinterpret_cast<sockaddr*>(ss); + } +}; + +// FIXME: use iovec instead. +struct addrReq_struct { + nlmsghdr netlinkHeader; + ifaddrmsg msg; +}; + +inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) { + ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0)); + return (sentByteCount == static_cast<ssize_t>(byteCount)); +} + +inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) { + return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0)); +} + +// Source-compatible with the BSD function. +inline int getifaddrs(ifaddrs** result) { + // Simplify cleanup for callers. + *result = NULL; + + // Create a netlink socket. + ScopedFd fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)); + if (fd.get() < 0) { + return -1; + } + + // Ask for the address information. + addrReq_struct addrRequest; + memset(&addrRequest, 0, sizeof(addrRequest)); + addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; + addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR; + addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest))); + addrRequest.msg.ifa_family = AF_UNSPEC; // All families. + addrRequest.msg.ifa_index = 0; // All interfaces. + if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) { + return -1; + } + + // Read the responses. + LocalArray<0> buf(65536); // We don't necessarily have std::vector. + ssize_t bytesRead; + while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) { + nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]); + for (; NLMSG_OK(hdr, bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) { + switch (hdr->nlmsg_type) { + case NLMSG_DONE: + return 0; + case NLMSG_ERROR: + return -1; + case RTM_NEWADDR: + { + ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); + rtattr* rta = IFA_RTA(address); + size_t ifaPayloadLength = IFA_PAYLOAD(hdr); + while (RTA_OK(rta, ifaPayloadLength)) { + if (rta->rta_type == IFA_ADDRESS) { + *result = new ifaddrs(*result); + if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) { + return -1; + } + (*result)->setAddress(address->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + } + rta = RTA_NEXT(rta, ifaPayloadLength); + } + } + break; + } + } + } + // We only get here if recv fails before we see a NLMSG_DONE. + return -1; +} + +// Source-compatible with the BSD function. +inline void freeifaddrs(ifaddrs* addresses) { + delete addresses; +} + +#endif // IFADDRS_ANDROID_H_included diff --git a/luni/src/main/native/java_net_NetworkInterface.cpp b/luni/src/main/native/java_net_NetworkInterface.cpp index 3ea6657..420c045 100644 --- a/luni/src/main/native/java_net_NetworkInterface.cpp +++ b/luni/src/main/native/java_net_NetworkInterface.cpp @@ -30,63 +30,33 @@ #include <net/if.h> // Note: Can't appear before <sys/socket.h> on OS X. -// There are several ways that an interface index might be referenced -// out of an ifreq struct, depending on the platform. -#if defined(ifr_ifindex) -// Linux: No need to do anything. -#elif defined(ifr_index) -#define ifr_ifindex ifr_index // BSD -#elif defined(ifr_intval) -#define ifr_ifindex ifr_intval // OS X +#ifdef ANDROID +#include "ifaddrs-android.h" #else -#error "Unknown how to refer to an interface index on this platform." +#include <ifaddrs.h> #endif -// A smart pointer that closes the given fd on going out of scope. -// TODO: make this generally available. -class scoped_fd { +// Ensures we always call freeifaddrs(3) to clean up after getifaddrs(3). +class ScopedInterfaceAddresses { public: - explicit scoped_fd(int fd) : fd(fd) { + ScopedInterfaceAddresses() : list(NULL) { } - - ~scoped_fd() { - close(fd); + + bool init() { + int rc = getifaddrs(&list); + return (rc != -1); } - - int get() const { - return fd; + + ~ScopedInterfaceAddresses() { + freeifaddrs(list); } - -private: - int fd; + + ifaddrs* list; }; // TODO: add a header file for shared utilities like this. extern jobject socketAddressToInetAddress(JNIEnv* env, sockaddr_storage* sockAddress); -class NetworkInterfaceGetter { -public: - NetworkInterfaceGetter() : interfaces(NULL) { - // Initialize this so we can be responsible for deleting it. - ifc.ifc_buf = NULL; - } - - ~NetworkInterfaceGetter() { - delete[] ifc.ifc_buf; - } - - jobjectArray getNetworkInterfaces(JNIEnv* env); - -private: - jobjectArray interfaces; - ifconf ifc; -}; - -// TODO: move to JNIHelp? -static void jniThrowOutOfMemoryError(JNIEnv* env) { - jniThrowException(env, "java/lang/OutOfMemoryError", "native heap"); -} - // TODO(enh): move to JNIHelp.h static void jniThrowSocketException(JNIEnv* env) { char buf[BUFSIZ]; @@ -94,173 +64,87 @@ static void jniThrowSocketException(JNIEnv* env) { jniStrError(errno, buf, sizeof(buf))); } -// Creates an InetAddress[] of size 'addressCount' from the ifc_req structs -// starting at index 'startIndex' in 'ifc.ifc_req'. -static jobjectArray MakeInetAddressArray(JNIEnv* env, - const ifconf& ifc, size_t startIndex, size_t addressCount) { - jclass inetAddressClass = env->FindClass("java/net/InetAddress"); - if (inetAddressClass == NULL) { +static jobject makeInterfaceAddress(JNIEnv* env, jint interfaceIndex, const char* name, sockaddr_storage* ss) { + jclass clazz = env->FindClass("java/net/InterfaceAddress"); + if (clazz == NULL) { return NULL; } - jobjectArray addresses = env->NewObjectArray(addressCount, inetAddressClass, NULL); - if (addresses == NULL) { + jmethodID constructor = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;Ljava/net/InetAddress;)V"); + if (constructor == NULL) { return NULL; } - for (size_t i = startIndex; i < startIndex + addressCount; ++i) { - sockaddr_storage* sockAddress = - reinterpret_cast<sockaddr_storage*>(&ifc.ifc_req[i].ifr_addr); - jobject element = socketAddressToInetAddress(env, sockAddress); - if (element == NULL) { - return NULL; - } - env->SetObjectArrayElement(addresses, i - startIndex, element); - if (env->ExceptionCheck()) { - return NULL; - } - } - return addresses; -} - -// Creates a NetworkInterface with the given 'name', array of 'addresses', -// and 'id'. -static jobject MakeNetworkInterface(JNIEnv* env, - jstring name, jobjectArray addresses, jint id) { - jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface"); - if (networkInterfaceClass == NULL) { + jobject javaName = env->NewStringUTF(name); + if (javaName == NULL) { return NULL; } - jmethodID networkInterfaceConstructor = - env->GetMethodID(networkInterfaceClass, "<init>", - "(Ljava/lang/String;Ljava/lang/String;[Ljava/net/InetAddress;I)V"); - if (networkInterfaceConstructor == NULL) { + jobject javaAddress = socketAddressToInetAddress(env, ss); + if (javaAddress == NULL) { return NULL; } - return env->NewObject(networkInterfaceClass, networkInterfaceConstructor, - name, name, addresses, id); + return env->NewObject(clazz, constructor, interfaceIndex, javaName, javaAddress); } -jobjectArray NetworkInterfaceGetter::getNetworkInterfaces(JNIEnv* env) { - scoped_fd fd(socket(PF_INET, SOCK_DGRAM, 0)); - if (fd.get() < 0) { +static jobjectArray getInterfaceAddresses(JNIEnv* env, jclass) { + // Get the list of interface addresses. + ScopedInterfaceAddresses addresses; + if (!addresses.init()) { jniThrowSocketException(env); return NULL; } - - // Get the list of interfaces. - // Keep trying larger buffers until the result fits. - int len = 32 * sizeof(ifreq); - for (;;) { - // TODO: std::vector or boost::scoped_array would make this less awful. - if (ifc.ifc_buf != NULL) { - delete[] ifc.ifc_buf; - ifc.ifc_buf = NULL; - } - char* data = new char[len]; - if (data == NULL) { - jniThrowOutOfMemoryError(env); - return NULL; - } - ifc.ifc_len = len; - ifc.ifc_buf = data; - if (ioctl(fd.get(), SIOCGIFCONF, &ifc) != 0) { - jniThrowSocketException(env); - return NULL; - } - if (ifc.ifc_len < len) { - break; - } - // The returned data was likely truncated. - // Expand the buffer and try again. - len += 32 * sizeof(ifreq); - } - - // Count the number of distinct interfaces. - // Multiple addresses for a given interface have the same interface name. - // This whole function assumes that all an interface's addresses will be - // listed adjacent to one another. - size_t totalAddressCount = ifc.ifc_len / sizeof(ifreq); - size_t interfaceCount = 0; - const char* lastName = NULL; - for (size_t i = 0; i < totalAddressCount; ++i) { - const char* name = ifc.ifc_req[i].ifr_name; - if (lastName == NULL || strncmp(lastName, name, IFNAMSIZ) != 0) { - ++interfaceCount; - } - lastName = name; + + // Count how many there are. + int interfaceAddressCount = 0; + for (ifaddrs* ifa = addresses.list; ifa != NULL; ifa = ifa->ifa_next) { + ++interfaceAddressCount; } - - // Build the NetworkInterface[]... - jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface"); - if (networkInterfaceClass == NULL) { + + // Build the InterfaceAddress[]... + jclass interfaceAddressClass = env->FindClass("java/net/InterfaceAddress"); + if (interfaceAddressClass == NULL) { return NULL; } - interfaces = env->NewObjectArray(interfaceCount, networkInterfaceClass, NULL); - if (interfaces == NULL) { + jobjectArray result = env->NewObjectArray(interfaceAddressCount, interfaceAddressClass, NULL); + if (result == NULL) { return NULL; } - - // Fill in the NetworkInterface[]. - size_t arrayIndex = 0; - for (size_t i = 0; i < totalAddressCount; ++i) { - // Get the index for this interface. - // (This is an id the kernel uses, unrelated to our array indexes.) - int id = ifc.ifc_req[i].ifr_ifindex; - - // Get the name for this interface. There only seems to be one name so - // we use it for both name and the display name (as does the RI). - jstring name = env->NewStringUTF(ifc.ifc_req[i].ifr_name); - if (name == NULL) { - return NULL; + + // And fill it in... + int arrayIndex = 0; + for (ifaddrs* ifa = addresses.list; ifa != NULL; ifa = ifa->ifa_next) { + // We're only interested in IP addresses. + int family = ifa->ifa_addr->sa_family; + if (family != AF_INET && family != AF_INET6) { + continue; } - - // Check how many addresses this interface has. - size_t addressCount = 0; - for (size_t j = i; j < totalAddressCount; ++j) { - if (strncmp(ifc.ifc_req[i].ifr_name, ifc.ifc_req[j].ifr_name, IFNAMSIZ) == 0) { - if (ifc.ifc_req[j].ifr_addr.sa_family == AF_INET) { - ++addressCount; - } - } else { - break; - } + // Until we implement Java 6's NetworkInterface.isUp, + // we only want interfaces that are up. + if ((ifa->ifa_flags & IFF_UP) == 0) { + continue; } - - // Get this interface's addresses as an InetAddress[]. - jobjectArray addresses = MakeInetAddressArray(env, ifc, i, addressCount); - if (addresses == NULL) { - return NULL; + // Find the interface's index, and skip this address if + // the interface has gone away. + int interfaceIndex = if_nametoindex(ifa->ifa_name); + if (interfaceIndex == 0) { + continue; } - // Create the NetworkInterface object and add it to the NetworkInterface[]. - jobject interface = MakeNetworkInterface(env, name, addresses, id); - if (interface == NULL) { + // Make a new InterfaceAddress, and insert it into the array. + sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr); + jobject element = makeInterfaceAddress(env, interfaceIndex, ifa->ifa_name, ss); + if (element == NULL) { return NULL; } - env->SetObjectArrayElement(interfaces, arrayIndex++, interface); + env->SetObjectArrayElement(result, arrayIndex, element); if (env->ExceptionCheck()) { return NULL; } - - // Skip over this interface's addresses to the next *interface*. - i += addressCount - 1; + ++arrayIndex; } - return interfaces; + return result; } -/** - * Returns an array of zero or more NetworkInterface objects, one for each - * network interface. - */ -static jobjectArray getNetworkInterfacesImpl(JNIEnv* env, jclass) { - NetworkInterfaceGetter getter; - return getter.getNetworkInterfaces(env); -} - -/* - * JNI registration - */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "getNetworkInterfacesImpl", "()[Ljava/net/NetworkInterface;", (void*) getNetworkInterfacesImpl }, + { "getInterfaceAddresses", "()[Ljava/net/InterfaceAddress;", (void*) getInterfaceAddresses }, }; int register_java_net_NetworkInterface(JNIEnv* env) { return jniRegisterNativeMethods(env, "java/net/NetworkInterface", diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp index b4b6d92..fc98428 100644 --- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp +++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp @@ -1289,6 +1289,7 @@ static void mcastAddDropMembership(JNIEnv *env, int handle, jobject optVal, interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I"); interfaceIndex = env->GetIntField(optVal, interfaceIdxID); } + LOGI("mcastAddDropMembership interfaceIndex=%i", interfaceIndex); if (!inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP)) { return; |