I was disappointed to find that NetworkInterface doesn't have a default
implementation in Classpath; I put together the attached version.

There are apparently a bunch of ways to get this data. This version is
based on the 'sysctl' one described in W. Richard Stevens' book, UNIX
Network Programming. This seems to work fine on Darwin; I'll try it on
Linux when I get a chance. This version will return IPv6 addresses, if
your system supports it.

I've also changed some of the "RawData" functions in jcl.c.
JCL_GetRawData depends on the static variable `rawData_fid' being
initialized, which only gets set in `JCL_NewRawDataObject.' On jamvm,
the JNI function `NewDirectBuffer' doesn't call `JCL_NewRawDataObject,'
meaning these fields aren't initialized. The current code isn't thread
safe, either, so here I've just removed the caching for now (the caching
code creates a new global reference, so it is important for this to be
thread safe). Removing the caching may be a performance hit.


2006-09-07  Casey Marshall  <[EMAIL PROTECTED]>

        * configure.ac: add check for `sysctl;' add check for IPv6
        support.
        * include/java_net_VMNetworkInterface.h: regenerated.
        * java/net/NetworkInterface.java (name, inetAddresses): removed.
        (netif): new field.
        (<init>, <init>): removed.
        (<init>): new, private constructor.
        (getName): delegate to VMNetworkInterface.
        (getInetAddresses): create inetAddresses Vector here.
        (getByName): iterate over the list of VMNetworkInterface objects.
        (getByAddress): likewise.
        (condense): removed.
        (getNetworkInterfaces): use `VMNetworkInterface.getVMInterfaces.'
        (equals): compare fields in VMNetworkInterface.
        (hashCode): get hash codes from VMNetworkInterface fields.
        (toString): use a StringBuffer.
        * native/jni/classpath/jcl.c (rawDataClass, rawData_fid,
        rawData_mid): removed.
        (JCL_NewRawDataObject): make the above local; don't create a
        global reference.
        (JCL_GetRawData): get the field ID here.
        * native/jni/java-net/Makefile.am (libjavanet_la_SOURCES): add
        netif.c and netif.h.
        * native/jni/java-net/java_net_VMNetworkInterface.c
        (java_net_VMNetworkInterface_init,
        java_net_VMNetworkInterface_addAddress): new static variables.
        (Java_java_net_VMNetworkInterface_initIds): new function.
        (Java_java_net_VMNetworkInterface_getInterfaces): removed.
        (Java_java_net_VMNetworkInterface_getVMInterfaces): new function.
        * native/jni/java-net/netif.c: new file.
        * native/jni/java-net/netif.h: new file.
        * vm/reference/java/net/VMNetworkInterface.java (name, addresses):
        new fields.
        (<clinit>): call `initIds'.
        (initIds): new method.
        (getInterfaces): removed.
        (getVMInterfaces, addAddress): new methods.

? native/jni/java-net/netif.c
? native/jni/java-net/netif.h
Index: configure.ac
===================================================================
RCS file: /cvsroot/classpath/classpath/configure.ac,v
retrieving revision 1.181
diff -u -r1.181 configure.ac
--- configure.ac        31 Aug 2006 19:56:03 -0000      1.181
+++ configure.ac        8 Sep 2006 06:31:12 -0000
@@ -373,12 +373,19 @@
                   fcntl \
                  mmap munmap mincore msync madvise getpagesize sysconf \
                  lstat readlink \
-                 ])
+                 sysctl])
 
   LIBMAGIC=
   AC_CHECK_LIB(magic, magic_open, LIBMAGIC=-lmagic)
   AC_SUBST(LIBMAGIC)
 
+  AC_MSG_CHECKING([whether struct sockaddr_in6 is in netinet/in.h])
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <netinet/in.h>]], [[struct 
sockaddr_in6 addr6;]])],
+                    [AC_DEFINE(HAVE_INET6, 1,
+                     [Define if inet6 structures are defined in netinet/in.h.])
+                     AC_MSG_RESULT(yes)],
+                    [AC_MSG_RESULT(no)])
+
   AC_HEADER_TIME
   AC_STRUCT_TM
   AC_STRUCT_TIMEZONE
Index: include/java_net_VMNetworkInterface.h
===================================================================
RCS file: /cvsroot/classpath/classpath/include/java_net_VMNetworkInterface.h,v
retrieving revision 1.1
diff -u -r1.1 java_net_VMNetworkInterface.h
--- include/java_net_VMNetworkInterface.h       11 Apr 2005 18:58:38 -0000      
1.1
+++ include/java_net_VMNetworkInterface.h       8 Sep 2006 06:31:12 -0000
@@ -1,19 +1,29 @@
 /* DO NOT EDIT THIS FILE - it is machine generated */
-
-#ifndef __java_net_VMNetworkInterface__
-#define __java_net_VMNetworkInterface__
-
 #include <jni.h>
+/* Header for class java_net_VMNetworkInterface */
 
+#ifndef _Included_java_net_VMNetworkInterface
+#define _Included_java_net_VMNetworkInterface
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
-
-JNIEXPORT jobject JNICALL Java_java_net_VMNetworkInterface_getInterfaces 
(JNIEnv *env, jclass);
+/*
+ * Class:     java_net_VMNetworkInterface
+ * Method:    initIds
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_net_VMNetworkInterface_initIds
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     java_net_VMNetworkInterface
+ * Method:    getVMInterfaces
+ * Signature: ()[Ljava/net/VMNetworkInterface;
+ */
+JNIEXPORT jobjectArray JNICALL Java_java_net_VMNetworkInterface_getVMInterfaces
+  (JNIEnv *, jclass);
 
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* __java_net_VMNetworkInterface__ */
+#endif
Index: java/net/NetworkInterface.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/net/NetworkInterface.java,v
retrieving revision 1.18
diff -u -r1.18 NetworkInterface.java
--- java/net/NetworkInterface.java      29 Aug 2006 08:25:15 -0000      1.18
+++ java/net/NetworkInterface.java      8 Sep 2006 06:31:12 -0000
@@ -38,6 +38,8 @@
 
 package java.net;
 
+import gnu.classpath.SystemProperties;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -58,25 +60,13 @@
  */
 public final class NetworkInterface
 {
-  private String name;
-  private Vector inetAddresses;
-
-  NetworkInterface(String name, InetAddress address)
-  {
-    this.name = name;
-    this.inetAddresses = new Vector(1, 1);
-    this.inetAddresses.add(address);
-  }
+  private final VMNetworkInterface netif;
 
-  NetworkInterface(String name, InetAddress[] addresses)
+  private NetworkInterface(VMNetworkInterface netif)
   {
-    this.name = name;
-    this.inetAddresses = new Vector(addresses.length, 1);
-
-    for (int i = 0; i < addresses.length; i++)
-      this.inetAddresses.add(addresses[i]);
+    this.netif = netif;
   }
-
+  
   /**
    * Returns the name of the network interface
    *
@@ -84,7 +74,7 @@
    */
   public String getName()
   {
-    return name;
+    return netif.name;
   }
 
   /**
@@ -100,6 +90,7 @@
   public Enumeration getInetAddresses()
   {
     SecurityManager s = System.getSecurityManager();
+    Vector inetAddresses = new Vector(netif.addresses);
 
     if (s == null)
       return inetAddresses.elements();
@@ -131,7 +122,7 @@
    */
   public String getDisplayName()
   {
-    return name;
+    return netif.name;
   }
 
   /**
@@ -148,15 +139,14 @@
   public static NetworkInterface getByName(String name)
     throws SocketException
   {
-    for (Enumeration e = getNetworkInterfaces(); e.hasMoreElements();)
+    if (name == null)
+      throw new NullPointerException();
+    VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces();
+    for (int i = 0; i < netifs.length; i++)
       {
-       NetworkInterface tmp = (NetworkInterface) e.nextElement();
-
-       if (name.equals(tmp.getName()))
-         return tmp;
+        if (netifs[i].name.equals(name))
+          return new NetworkInterface(netifs[i]);
       }
-
-    // No interface with the given name found.
     return null;
   }
 
@@ -173,55 +163,15 @@
   public static NetworkInterface getByInetAddress(InetAddress addr)
     throws SocketException
   {
-    for (Enumeration interfaces = getNetworkInterfaces();
-         interfaces.hasMoreElements();)
+    if (addr == null)
+      throw new NullPointerException();
+    VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces();
+    for (int i = 0; i < netifs.length; i++)
       {
-       NetworkInterface tmp = (NetworkInterface) interfaces.nextElement();
-
-       for (Enumeration addresses = tmp.inetAddresses.elements();
-            addresses.hasMoreElements();)
-         {
-           if (addr.equals((InetAddress) addresses.nextElement()))
-             return tmp;
-         }
+        if (netifs[i].addresses.contains(addr))
+          return new NetworkInterface(netifs[i]);
       }
-
-    throw new SocketException("no network interface is bound to such an IP 
address");
-  }
-
-  static private Collection condense(Collection interfaces) 
-  {
-    final Map condensed = new HashMap();
-
-    final Iterator interfs = interfaces.iterator();
-    while (interfs.hasNext()) {
-
-      final NetworkInterface face = (NetworkInterface) interfs.next();
-      final String name = face.getName();
-      
-      if (condensed.containsKey(name))
-       {
-         final NetworkInterface conface = (NetworkInterface) 
condensed.get(name);
-         if (!conface.inetAddresses.containsAll(face.inetAddresses))
-           {
-             final Iterator faceAddresses = face.inetAddresses.iterator();
-             while (faceAddresses.hasNext())
-               {
-                 final InetAddress faceAddress = (InetAddress) 
faceAddresses.next();
-                 if (!conface.inetAddresses.contains(faceAddress))
-                   {
-                     conface.inetAddresses.add(faceAddress);
-                   }
-               }
-           }
-       }
-      else
-       {
-         condensed.put(name, face);
-       }
-    }
-
-    return condensed.values();
+    return null;
   }
 
   /**
@@ -233,14 +183,14 @@
    */
   public static Enumeration getNetworkInterfaces() throws SocketException
   {
-    Vector networkInterfaces = VMNetworkInterface.getInterfaces();
-
-    if (networkInterfaces.isEmpty())
-      return null;
-
-    Collection condensed = condense(networkInterfaces);
-
-    return Collections.enumeration(condensed);
+    VMNetworkInterface[] netifs = VMNetworkInterface.getVMInterfaces();
+    Vector networkInterfaces = new Vector(netifs.length);
+    for (int i = 0; i < netifs.length; i++)
+      {
+        if (!netifs[i].addresses.isEmpty())
+          networkInterfaces.add(new NetworkInterface(netifs[i]));
+      }
+    return networkInterfaces.elements();
   }
 
   /**
@@ -257,7 +207,8 @@
 
     NetworkInterface tmp = (NetworkInterface) obj;
 
-    return (name.equals(tmp.name) && inetAddresses.equals(tmp.inetAddresses));
+    return (netif.name.equals(tmp.netif.name)
+            && (netif.addresses.equals(tmp.netif.addresses)));
   }
 
   /**
@@ -268,7 +219,7 @@
   public int hashCode()
   {
     // FIXME: hash correctly
-    return name.hashCode() + inetAddresses.hashCode();
+    return netif.name.hashCode() + netif.addresses.hashCode();
   }
 
   /**
@@ -279,19 +230,22 @@
   public String toString()
   {
     // FIXME: check if this is correct
-    String result;
-    String separator = System.getProperty("line.separator");
+    StringBuffer result;
+    String separator = SystemProperties.getProperty("line.separator");
 
-    result =
-      "name: " + getDisplayName() + " (" + getName() + ") addresses:"
-      + separator;
+    result = new StringBuffer();
+    
+    result.append("name: ");
+    result.append(getDisplayName());
+    result.append(" (").append(getName()).append(") addresses:");
+    result.append(separator);
 
-    for (Enumeration e = inetAddresses.elements(); e.hasMoreElements();)
+    for (Iterator it = netif.addresses.iterator(); it.hasNext(); )
       {
-       InetAddress address = (InetAddress) e.nextElement();
-       result += address.toString() + ";" + separator;
+       InetAddress address = (InetAddress) it.next();
+       result.append(address.toString()).append(";").append(separator);
       }
 
-    return result;
+    return result.toString();
   }
 }
Index: native/jni/classpath/jcl.c
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/classpath/jcl.c,v
retrieving revision 1.23
diff -u -r1.23 jcl.c
--- native/jni/classpath/jcl.c  3 Apr 2006 14:03:12 -0000       1.23
+++ native/jni/classpath/jcl.c  8 Sep 2006 06:31:12 -0000
@@ -186,90 +186,113 @@
  * Build a Pointer object. The function caches the class type 
  */
 
-static jclass rawDataClass;
-static jfieldID rawData_fid;
-static jmethodID rawData_mid;
+/* Note, caching these values doesn't work. On jamvm, for example,
+   this fails if you use the JNI call NewDirectBuffer, because it
+   doesn't use JCL_NewRawDataObject, and thus these ID classes may not
+   have been filled in. This code is also not thread-safe. */
+
+/* static jclass rawDataClass; */
+/* static jfieldID rawData_fid; */
+/* static jmethodID rawData_mid; */
 
 JNIEXPORT jobject JNICALL
 JCL_NewRawDataObject (JNIEnv * env, void *data)
 {
+  jclass rawDataClass;
+  jmethodID rawData_mid;
+  jobject ret;
+
+#if SIZEOF_VOID_P == 8
+  rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64");
   if (rawDataClass == NULL)
     {
-      jclass tmp;
-#if SIZEOF_VOID_P == 8
-      rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64");
-      if (rawDataClass == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to find internal class");
-         return NULL;
-       }
-
-      rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(J)V");
-      if (rawData_mid == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to find internal constructor");
-         return NULL;
-       }
-
-      rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "J");
-      if (rawData_fid == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to find internal field");
-         return NULL;
-       }
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal class");
+      return NULL;
+    }
+
+  rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(J)V");
+  if (rawData_mid == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal constructor");
+      return NULL;
+    }
 #else
-      rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32");
-      if (rawDataClass == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to find internal class");
-         return NULL;
-       }
-
-      rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(I)V");
-      if (rawData_mid == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to find internal constructor");
-         return NULL;
-       }
-
-      rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "I");
-      if (rawData_fid == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to find internal field");
-         return NULL;
-       }
+  rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32");
+  if (rawDataClass == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal class");
+      return NULL;
+    }
 
-#endif
-      tmp = (*env)->NewGlobalRef (env, rawDataClass);
-      if (tmp == NULL)
-       {
-         JCL_ThrowException (env, "java/lang/InternalError",
-                             "unable to create an internal global ref");
-         return NULL;
-       }
-      (*env)->DeleteLocalRef(env, rawDataClass);
-      rawDataClass = tmp;
+  rawData_mid = (*env)->GetMethodID (env, rawDataClass, "<init>", "(I)V");
+  if (rawData_mid == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal constructor");
+      return NULL;
     }
+#endif
 
 #if SIZEOF_VOID_P == 8
-  return (*env)->NewObject (env, rawDataClass, rawData_mid, (jlong) data);
+  ret = (*env)->NewObject (env, rawDataClass, rawData_mid, (jlong) data);
 #else
-  return (*env)->NewObject (env, rawDataClass, rawData_mid, (jint) data);
+  ret = (*env)->NewObject (env, rawDataClass, rawData_mid, (jint) data);
 #endif
+
+  (*env)->DeleteLocalRef (env, rawDataClass);
+  return ret;
 }
 
 JNIEXPORT void * JNICALL
 JCL_GetRawData (JNIEnv * env, jobject rawdata)
 {
+  jclass rawDataClass;
+  jfieldID rawData_fid;
+  jobject ret;
+
 #if SIZEOF_VOID_P == 8
-  return (void *) (*env)->GetLongField (env, rawdata, rawData_fid);
+  rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer64");
+  if (rawDataClass == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal class");
+      return NULL;
+    }
+
+  rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "J");
+  if (rawData_fid == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal field");
+      return NULL;
+    }
+#else
+  rawDataClass = (*env)->FindClass (env, "gnu/classpath/Pointer32");
+  if (rawDataClass == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal class");
+      return NULL;
+    }
+
+  rawData_fid = (*env)->GetFieldID (env, rawDataClass, "data", "I");
+  if (rawData_fid == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "unable to find internal field");
+      return NULL;
+    }
+#endif
+
+#if SIZEOF_VOID_P == 8
+  ret = (void *) (*env)->GetLongField (env, rawdata, rawData_fid);
 #else
-  return (void *) (*env)->GetIntField (env, rawdata, rawData_fid);
-#endif  
+  ret = (void *) (*env)->GetIntField (env, rawdata, rawData_fid);
+#endif
+
+  (*env)->DeleteLocalRef (env, rawDataClass);
+  return ret;
 }
Index: native/jni/java-net/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/native/jni/java-net/Makefile.am,v
retrieving revision 1.18
diff -u -r1.18 Makefile.am
--- native/jni/java-net/Makefile.am     21 Aug 2006 23:34:45 -0000      1.18
+++ native/jni/java-net/Makefile.am     8 Sep 2006 06:31:12 -0000
@@ -15,6 +15,7 @@
                        java_net_VMURLConnection.c \
                        gnu_java_net_VMPlainDatagramSocketImpl.c \
                         gnu_java_net_VMPlainSocketImpl.c \
+                       netif.c netif.h \
                        $(local_sources)
 
 libjavanet_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo \
Index: native/jni/java-net/java_net_VMNetworkInterface.c
===================================================================
RCS file: 
/cvsroot/classpath/classpath/native/jni/java-net/java_net_VMNetworkInterface.c,v
retrieving revision 1.3
diff -u -r1.3 java_net_VMNetworkInterface.c
--- native/jni/java-net/java_net_VMNetworkInterface.c   12 Jan 2006 09:37:31 
-0000      1.3
+++ native/jni/java-net/java_net_VMNetworkInterface.c   8 Sep 2006 06:31:12 
-0000
@@ -35,9 +35,11 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-/* do not move; needed here because of some macro definitions */
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif /* HAVE_CONFIG_H */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -46,20 +48,214 @@
 #include <jcl.h>
 
 #include "java_net_VMNetworkInterface.h"
+#include "netif.h"
+
+
+static jmethodID java_net_VMNetworkInterface_init;
+static jmethodID java_net_VMNetworkInterface_addAddress;
+
+/*
+ * Initialize our static method ID's.
+ *
+ * Class:     java_net_VMNetworkInterface
+ * Method:    initIds
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_VMNetworkInterface_initIds (JNIEnv *env, jclass clazz)
+{
+  java_net_VMNetworkInterface_init =
+    (*env)->GetMethodID (env, clazz, "<init>", "(Ljava/lang/String;)V");
+  if (java_net_VMNetworkInterface_init == NULL)
+    {
+      if (!(*env)->ExceptionCheck (env))
+        JCL_ThrowException (env, "java/lang/NoSuchMethodError",
+                            "VMNetworkinterface.addAddress");
+      return;
+    }
+  java_net_VMNetworkInterface_addAddress =
+    (*env)->GetMethodID (env, clazz, "addAddress", "(Ljava/nio/ByteBuffer;)V");
+  if (java_net_VMNetworkInterface_addAddress == NULL)
+    {
+      if (!(*env)->ExceptionCheck (env))
+        JCL_ThrowException (env, "java/lang/NoSuchMethodError",
+                            "VMNetworkinterface.addAddress");
+    }
+}
 
-#include "javanet.h"
 
 /*
- * Returns all local network interfaces as vector
+ * Returns all local network interfaces as an array.
  */
-JNIEXPORT jobject JNICALL
-Java_java_net_VMNetworkInterface_getInterfaces (JNIEnv * env,
-                                               jclass class
-                                               __attribute__ ((__unused__)))
+JNIEXPORT jobjectArray JNICALL
+Java_java_net_VMNetworkInterface_getVMInterfaces (JNIEnv * env,
+                                                  jclass clazz 
__attribute__((unused)))
 {
-  JCL_ThrowException (env, IO_EXCEPTION,
-                     "java.net.VMNetworkInterface.getInterfaces(): not 
implemented");
-  return 0;
+#ifdef HAVE_SYSCTL
+  size_t ifslen;
+  struct if_msghdr *iflist, *ifcur, *ifend;
+  struct sockaddr *sa, *rti_info[RTAX_MAX];
+  int numifs = 0;
+  int i;
+  jobjectArray netifs;
+  jobject curif;
+
+  iflist = cpnet_rt_iflist (env, &ifslen);
+  if (NULL == iflist)
+    return NULL;
+
+/*   printf ("got iflist: %p; ifslen: %lu\n", (void *) iflist, ifslen); */
+
+  /* First, count the number of interfaces. */
+  ifend = (struct if_msghdr *) (((char *) iflist) + ifslen);
+  for (ifcur = iflist; ifcur < ifend;
+       ifcur = (struct if_msghdr *) ((char *) ifcur + ifcur->ifm_msglen))
+    {
+/*       printf ("looking at ifcur: %p (ifend: %p)\n", (void *) ifcur, (void 
*) ifend); */
+/*       printf ("ifcur->ifm_type = %d\n", ifcur->ifm_type); */
+      if (ifcur->ifm_type == RTM_IFINFO)
+        {
+          /* Skip interfaces that are not up. */
+          if ((ifcur->ifm_flags & IFF_UP) == 0)
+            continue;
+
+          sa = (struct sockaddr *) (ifcur + 1);
+          cpnet_get_rtaddrs (ifcur->ifm_addrs, sa, rti_info);
+          if ((sa = rti_info[RTAX_IFP]) != NULL)
+            {
+              if (sa->sa_family == AF_LINK)
+                {
+                  numifs++;
+                }
+            }
+        }
+    }
+
+/*   printf ("we have %d interfaces\n", numifs); */
+
+  netifs = (*env)->NewObjectArray (env, numifs, clazz, NULL);
+  if (netifs == NULL)
+    {
+      JCL_free (env, iflist);
+      return NULL;
+    }
+
+  /* Create the objects. We fill in the interface names here. */
+  i = 0;
+  curif = NULL;
+  for (ifcur = iflist; ifcur < ifend;
+       ifcur = (struct if_msghdr *) ((char *) ifcur + ifcur->ifm_msglen))
+    {
+      if (ifcur->ifm_type == RTM_IFINFO)
+        {
+/*           printf ("RTM_IFINFO\n"); */
+          if (curif != NULL)
+            (*env)->DeleteLocalRef (env, curif);
+
+          /* Skip interfaces that are not up. */
+          if ((ifcur->ifm_flags & IFF_UP) == 0)
+            {
+              curif = NULL;
+              continue;
+            }
+
+          sa = (struct sockaddr *) (ifcur + 1);
+          cpnet_get_rtaddrs (ifcur->ifm_addrs, sa, rti_info);
+          if ((sa = rti_info[RTAX_IFP]) != NULL)
+            {
+              if (sa->sa_family == AF_LINK)
+                {
+                  char *buf;
+                  jstring ifname;
+                  struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa;
+                  if (i >= numifs)
+                    {
+                      JCL_free (env, iflist);
+                      JCL_ThrowException (env, "java/net/SocketException",
+                                          "too many interfaces!");
+                    }
+
+                  buf = (char *) JCL_malloc (env, sdl->sdl_nlen + 1);
+                  if (buf == NULL)
+                    {
+                      JCL_ThrowException (env, 
"java/lang/OutOfMemoryException",
+                                          strerror (errno));
+                      JCL_free (env, iflist);
+                      return NULL;
+                    }
+                  strncpy (buf, &sdl->sdl_data[0], sdl->sdl_nlen);
+                  buf[sdl->sdl_nlen] = '\0';
+/*                   printf ("we have an interface: %s\n", buf); */
+                  ifname = (*env)->NewStringUTF (env, buf);
+                  JCL_free (env, buf);
+                  curif = (*env)->NewObject (env, clazz,
+                                             java_net_VMNetworkInterface_init,
+                                             ifname);
+                  (*env)->SetObjectArrayElement (env, netifs, i, curif);
+                  i++;
+                }
+            }
+        }
+      else if (ifcur->ifm_type == RTM_NEWADDR)
+        {
+          struct ifa_msghdr *ifam = (struct ifa_msghdr *) ifcur;
+/*           printf ("RTM_NEWADDR\n"); */
+          if (curif == NULL)
+            {
+              JCL_free (env, iflist);
+              JCL_ThrowException (env, "java/net/SocketException",
+                                  "got address with no associated interface");
+            }
+          sa = (struct sockaddr *) (ifam + 1);
+          cpnet_get_rtaddrs (ifam->ifam_addrs, sa, rti_info);
+
+          if ((sa = rti_info[RTAX_IFA]) == NULL)
+            continue; /* Means interface not up??? */
+
+/*           printf ("have a socket address: %p\n", (void *) sa); */
+          if (sa->sa_family == AF_INET)
+            {
+              struct sockaddr_in *in = (struct sockaddr_in *) sa;
+              jobject buffer = (*env)->NewDirectByteBuffer (env, 
&(in->sin_addr.s_addr), 4);
+/*               printf ("have IPV4 address: %08x\n", in->sin_addr.s_addr); */
+/*               printf ("addr is %p\n", (void *) &(in->sin_addr.s_addr)); */
+              (*env)->CallVoidMethod (env, curif,
+                                      java_net_VMNetworkInterface_addAddress,
+                                      buffer);
+              (*env)->DeleteLocalRef (env, buffer);
+              if ((*env)->ExceptionCheck(env))
+                {
+                  JCL_free (env, iflist);
+                  return NULL;
+                }
+            }
+#ifdef HAVE_INET6
+          else if (sa->sa_family == AF_INET6)
+            {
+              struct sockaddr_in6 *in = (struct sockaddr_in6 *) sa;
+              jobject buffer = (*env)->NewDirectByteBuffer (env, 
&(in->sin6_addr.s6_addr), 16);
+              (*env)->CallVoidMethod (env, curif,
+                                      java_net_VMNetworkInterface_addAddress,
+                                      buffer);
+              (*env)->DeleteLocalRef (env, buffer);
+              if ((*env)->ExceptionCheck(env))
+                {
+                  JCL_free (env, iflist);
+                  return NULL;
+                }
+            }
+#endif /* HAVE_INET6 */
+        }
+/*       else */
+/*         printf ("unhandled ifm_type %d!\n", ifcur->ifm_type); */
+    }
+
+  JCL_free (env, iflist);
+  return netifs;
+#else
+  JCL_ThrowException (env, "java/net/SocketException", "sysctl not supported");
+  return NULL;
+#endif /* HAVE_SYSCTL */
 }
 
 /* end of file */
Index: vm/reference/java/net/VMNetworkInterface.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/net/VMNetworkInterface.java,v
retrieving revision 1.4
diff -u -r1.4 VMNetworkInterface.java
--- vm/reference/java/net/VMNetworkInterface.java       2 Mar 2006 00:36:44 
-0000       1.4
+++ vm/reference/java/net/VMNetworkInterface.java       8 Sep 2006 06:31:12 
-0000
@@ -40,6 +40,9 @@
 
 import gnu.classpath.Configuration;
 
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.Vector;
 
 /**
@@ -54,22 +57,50 @@
  */
 final class VMNetworkInterface
 {
+  String name;
+  Set addresses;
+
+  VMNetworkInterface(String name)
+  {
+    this.name = name;
+    addresses = new HashSet();
+  }
+  
   static
-    {
-      if (Configuration.INIT_LOAD_LIBRARY)
-       System.loadLibrary("javanet");
-    }
+  {
+    if (Configuration.INIT_LOAD_LIBRARY)
+      System.loadLibrary("javanet");
+    
+    initIds();
+  }
+  
+  private static native void initIds();
 
   /**
-   * Returns a Vector of InetAddresses. The returned value will be
-   * 'condensed', meaning that all elements with the same interface
-   * name will be collapesed into one InetAddress for that name
-   * containing all addresses before the returning the result to the
-   * user. This means the native method can be implemented in a naive
-   * way mapping each address/interface to a name even if that means
-   * that the Vector contains multiple InetAddresses with the same
-   * interface name.
+   * Return a list of VM network interface objects.
+   *
+   * @return The list of network interfaces.
+   * @throws SocketException
    */
-  public static native Vector getInterfaces()
+  public static native VMNetworkInterface[] getVMInterfaces()
     throws SocketException;
+  
+  private void addAddress(ByteBuffer addr)
+    throws SocketException, UnknownHostException
+  {
+    if (addr.remaining() == 4)
+      {
+        byte[] ipv4 = new byte[4];
+        addr.get(ipv4);
+        addresses.add(Inet4Address.getByAddress(ipv4));
+      }
+    else if (addr.remaining() == 16)
+      {
+        byte[] ipv6 = new byte[16];
+        addr.get(ipv6);
+        addresses.add(Inet6Address.getByAddress(ipv6));
+      }
+    else
+      throw new SocketException("invalid interface address");
+  }
 }
/* netif.c -- functions for playing with network interfaces.
   Copyright (C) 2006  Free Software Foundation, Inc.

This file is a part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version.  */

/*
 * Functions in this file are based on "Unix Network Programming
 * Volume 1: The Sockets Networking API," 3rd edition, by W. Richard
 * Stevens, Bill Fenner, and Andrew M. Rudoff.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <string.h>

#include <jni.h>
#include <jcl.h>

#include <netif.h>

struct if_msghdr *
cpnet_rt_iflist (JNIEnv *env, size_t *len)
{
#ifdef HAVE_SYSCTL
  int mib[6];
  struct if_msghdr *buf;

  mib[0] = CTL_NET;
  mib[1] = AF_ROUTE;
  mib[2] = 0;
  mib[3] = 0;
  mib[4] = NET_RT_IFLIST;
  mib[5] = 0;

  if (sysctl (mib, 6, NULL, len, NULL, 0) == -1)
    {
      JCL_ThrowException (env, "java/io/IOException", strerror (errno));
      return NULL;
    }

  buf = JCL_malloc (env, *len);
  if (buf == NULL)
    return NULL;

  if (sysctl (mib, 6, buf, len, NULL, 0) == -1)
    {
      JCL_ThrowException (env, "java/io/IOException", strerror (errno));
      JCL_free (env, buf);
      return NULL;
    }

  return buf;
#else
  (void) env;
  (void) len;
  return NULL;
#endif
}

#define ROUND_UP(a, sz) (((a) & ((sz) - 1)) ? (1 + ((a) | ((sz) - 1))) : (a))

#define NEXT_SA(sa) ((caddr_t) (sa) + ((sa)->sa_len \
                                       ? ROUND_UP((sa)->sa_len, sizeof 
(u_long)) : \
                                       sizeof (u_long)))

void
cpnet_get_rtaddrs (int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
  int i;

  for (i = 0; i < RTAX_MAX; i++)
    {
      if (addrs & (1 << i))
        {
          rti_info[i] = sa;
          sa = (struct sockaddr *) NEXT_SA(sa);
        }
      else
        rti_info[i] = NULL;
    }
}
/* netif.h -- network interface operations.
   Copyright (C) 2006  Free Software Foundation, Inc.

This file is a part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version.  */


#ifndef _NETIF_H_
#define _NETIF_H_

#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <jni.h>

/**
 * Fetch the list of if_msghdr structures for the AF_INET family.
 *
 * \param env    The JNI environment.
 * \param len    A pointer to the size of the allocated interface list.
 * \return A list of 'struct if_msghdr' structures for the interfaces in
 *         the given address family. NULL is returned on error, and an
 *         exception will be thrown (the only checked exception thrown is
 *         java/io/IOException; any other exceptions thrown are unchecked).
 *         This structure is allocated with JCL_malloc, thus it is the
 *         caller's responsibility to free this buffer with JCL_free.
 */
struct if_msghdr *cpnet_rt_iflist (JNIEnv *env, size_t *len);

/**
 * Fetch the routing address info for a socket address.
 */
void cpnet_get_rtaddrs (int addrs, struct sockaddr *sa, struct sockaddr 
**rti_info);

#endif /* _NETIF_H_ */

Reply via email to