summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndroid (Google) Code Review <android-gerrit@google.com>2009-11-20 19:13:58 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2009-11-20 19:13:58 -0800
commitd2c1275661bbebbbb3fae30b6359f71f2628c4b3 (patch)
treeae525c8a062e4069fa8d062421db0f6099326e20
parent1f89002162163659b067809085d9e1d91a6f5378 (diff)
parentb5fc5ecd3fe5315fc2756c0c25adc458cc8c8d91 (diff)
downloadlibcore-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.h16
-rw-r--r--include/ScopedFd.h42
-rw-r--r--luni/src/main/java/java/net/InterfaceAddress.java41
-rw-r--r--luni/src/main/java/java/net/NetworkInterface.java47
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/net/GenericIPMreq.java30
-rw-r--r--luni/src/main/native/ifaddrs-android.h185
-rw-r--r--luni/src/main/native/java_net_NetworkInterface.cpp246
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp1
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;