[kaffe] IPv6 and pure java DNS patch

Timothy Stack stack@cs.utah.edu
Tue Apr 15 12:45:02 2003


--%--multipart-mixed-boundary-1.21652.1050436020--%
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit


hi,

I've attached a patch that adds support for IPv6 and doing DNS lookups in
pure Java using dnsjava.  I'll take care of actually committing it, this
is mostly a heads up before I do that.  Theres a short FAQ and Changelog
entry in the patch, so take a look at those for some more details.

thanks,

tim stack

--%--multipart-mixed-boundary-1.21652.1050436020--%
Content-Type: application/octet-stream
Content-Transfer-Encoding: 7bit
Content-Description: ASCII English text
Content-Disposition: attachment; filename="net.diff"

--- /dev/null	Tue Apr 15 13:18:29 2003
+++ net.ChangeLog	Tue Apr 15 08:23:34 2003
@@ -0,0 +1,84 @@
+2003-04-14 Tim Stack <stack@cs.utah.edu>
+
+	* Makefile.am:
+	Add DNSJAVA_JAR to the BUILD_ENVIRONMENT.
+
+	* configure.in:
+	Add --with-dnsjava option that lets the user specify a dnsjava Jar
+	file from www.xbill.org/dnsjava.
+
+	* FAQ/FAQ.dns:
+	Explanation of DNS stuff in kaffe.
+
+	* include/Arrays.h:
+	Add more unhand_*_array() macros.
+
+	* include/Makefile.am:
+	Add java_net_NativeInetAddressImpl.h and
+	java_net_NetworkInterfaceImpl.h.
+
+	* include/errors.h:
+	Add JAVA_NET() macro.
+	
+	* libraries/clib/net/InetAddressImpl.c: 
+	Rewrite to use getaddrinfo()/getnameinfo() and support the new
+	InetAddressImpl API.
+
+	* libraries/clib/net/Makefile.am:
+	Change NetworkInterface.c to NetworkInterfaceImpl.c.
+
+	* libraries/clib/net/NetworkInterface.c:
+	Renamed to NetworkInterfaceImpl.c.
+	
+	* libraries/clib/net/NetworkInterfaceImpl.c:
+	Name change and add support for IPv6 addresses.
+
+	* libraries/javalib/Makefile.am:
+	Add support for pure java DNS.  Add Inet4Address/Inet6Address from
+	classpath.  Add NetworkInterfaceImpl.java.
+
+	* libraries/javalib/bootstrap.classlist:
+	Add java/net/NativeInetAddressImpl.class and
+	java/net/NetworkInterfaceImpl.class.
+
+	* libraries/javalib/essential.files:
+	Add java/net/NativeInetAddressImpl.java.
+	
+	* libraries/javalib/rebuildLib.in:
+	Test for zero arguments and exit with zero.  Use the
+	BUILD_ENVIRONMENT for jikes too.
+
+	* libraries/javalib/java/lang/IllegalArgumentException.java:  
+	Add exception chaining.
+
+	* libraries/javalib/java/net/DNSJavaInetAddressImpl.java:
+	InetAddressImpl that uses dnsjava from xbill.org.
+
+	* libraries/javalib/java/net/Inet4Address.java,
+	libraries/javalib/java/net/Inet6Address.java:
+	Merged from GNU classpath and fixed.
+
+	* libraries/javalib/java/net/InetAddress.java:
+	Add support for IPv6 addresses and multiple implementations.
+
+	* libraries/javalib/java/net/InetAddressImpl.java:
+	Changes to support IPv6 and multiple implementations.
+
+	* libraries/javalib/java/net/NativeInetAddressImpl.java:
+	Default native InetAddressImpl.
+
+	* libraries/javalib/java/net/NetworkInterface.java:
+	Move implementation details to NetworkInterfaceImpl.java and
+	detection is now done on every call instead of once at startup.
+
+	* libraries/javalib/java/net/NetworkInterfaceImpl.java:
+	Implementation details for NetworkInterface.java.
+
+	* libraries/javalib/java/net/UnknownHostException.java:
+	Add exception chaining.
+
+	* test/regression/InetAddressTest.java:
+	Simple test for InetAddresses.
+
+	* test/regression/Makefile.am:
+	Add InetAddressTest.java.
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ FAQ/FAQ.dns	Tue Apr 15 13:12:32 2003
@@ -0,0 +1,105 @@
+
+Introduction
+------------
+
+Kaffe is able to perform DNS lookups in two ways, the OS provided
+resolver or a pure Java version that utilizes dnsjava[1].  By default,
+Kaffe will use the native resolvers, however, in some configurations,
+it will cause the whole JVM to block during name lookups.
+Alternatively, by configuring with dnsjava, there are less
+dependencies on the underlying OS and the whole process will not block
+during lookups.
+
+
+Configure Options
+-----------------
+
+  --with-dnsjava=<jar> - Specify a Jar file containing the dnsjava
+			 classes.
+
+
+Properties
+----------
+
+  org.kaffe.dns (get only) - Contains the name of the DNS
+  implementation being used.
+
+
+Examples
+--------
+
+The following code will create a class whose main will do a lookup on
+the first argument and report all the results, along with the DNS
+implementation in use.
+
+>>> BEGIN DNSExample.java
+import java.net.InetAddress;
+
+class DNSExample
+{
+    public static void main(String args[])
+	throws Throwable
+    {
+	InetAddress ia[];
+	int lpc;
+
+	System.out.println("Start query...");
+	ia = InetAddress.getAllByName(args[0]);
+	System.out.println("Query done using: "
+			   + System.getProperty("org.kaffe.dns"));
+	for( lpc = 0; lpc < ia.length; lpc++ )
+	{
+	    System.out.println(ia[lpc].toString());
+	}
+    }
+}
+<<< END DNSExample.java
+
+You can then run the example with a host name that has a mix of IPv4
+and IPv6 addresses.
+
+rory@yale> java DNSExample ns1.ipv6.he.net
+Start query...
+Query done using: java.net.DNSJavaInetAddressImpl
+ns1.ipv6.he.net./64.71.188.2
+ns1.ipv6.he.net./3ffe:81d0:ffff::250:4ff:fe3c:aa95
+
+
+Manifest
+--------
+
+  libraries/javalib/java/net/InetAddress.java - The standard interface
+  to DNS services for IP.
+
+  libraries/javalib/java/net/Inet4Address.java, Inet6Address.java -
+  IPv4 and IPv6 InetAddress implementations pulled from GNU
+  Classpath[2].  These were modified somewhat since the original
+  versions were buggy.
+
+  libraries/javalib/java/net/InetAddressImpl.java - The base class for
+  implementation classes.
+
+  libraries/javalib/java/net/NativeInetAddressImpl.java - The native
+  implementation that uses InetAddressImpl.c.
+
+  libraries/cilb/net/InetAddressImpl.c - The native DNS implementation
+  that uses getaddrinfo()/getnameinfo() when possible and falls back to
+  gethostbyname()/gethostbyaddr().
+
+  libraries/javalib/java/net/DNSJavaInetAddressImpl.java - The pure
+  Java implementation that uses dnsjava[1].
+
+
+References
+----------
+
+[1] A DNS implementation in Java, http://www.xbill.org/dnsjava,
+    Brian Wellington
+
+[2] GNU Classpath, http://www.gnu.org/software/classpath/classpath.html
+
+
+History
+-------
+
+April 15, 2003: Initial version.
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ libraries/clib/net/NetworkInterfaceImpl.c	Mon Apr 14 20:12:37 2003
@@ -0,0 +1,147 @@
+/*
+ * NetworkInterfaceImpl.c
+ * Native implementation of java.net.NetworkInterface functions.
+ *
+ * Copyright (c) 2002, 2003 University of Utah and the Flux Group.
+ * All rights reserved.
+ *
+ * This file is licensed under the terms of the GNU Public License.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * Contributed by the Flux Research Group, Department of Computer Science,
+ * University of Utah, http://www.cs.utah.edu/flux/
+ */
+
+#include "config.h"
+#include "config-std.h"
+#include "config-mem.h"
+#include "config-net.h"
+#include "config-io.h"
+#include "config-hacks.h"
+#include <native.h>
+#include "java_net_NetworkInterfaceImpl.h"
+#include "nets.h"
+#include <arpa/inet.h>
+#include <jsyscall.h>
+#include "../../../kaffe/kaffevm/debug.h"
+
+#include <ifaddrs.h>
+
+struct Hkaffe_util_Ptr *
+java_net_NetworkInterfaceImpl_detectInterfaces(void)
+{
+	struct Hkaffe_util_Ptr *retval = NULL;
+	struct ifaddrs *ifa;
+	errorInfo einfo;
+
+	if( getifaddrs(&ifa) == 0 )
+	{
+		retval = (struct Hkaffe_util_Ptr *)ifa;
+	}
+	else
+	{
+		switch( errno )
+		{
+		case ENOMEM:
+			postOutOfMemory(&einfo);
+			break;
+		case ENOSYS:
+			postExceptionMessage(
+				&einfo,
+				"kaffe.util.NotImplemented",
+				"OS doesn't support getifaddrs()");
+			break;
+		default:
+			postExceptionMessage(
+				&einfo,
+				"java.net.SocketException",
+				"%s",
+				SYS_ERROR(errno));
+			break;
+		}
+		throwError(&einfo);
+	}
+	return( retval );
+}
+
+void
+java_net_NetworkInterfaceImpl_freeInterfaces(struct Hkaffe_util_Ptr *jifa)
+{
+	if( jifa )
+	{
+		freeifaddrs((struct ifaddrs *)jifa);
+	}
+}
+
+struct Hkaffe_util_Ptr *
+java_net_NetworkInterfaceImpl_getNext(struct Hkaffe_util_Ptr *jifa)
+{
+	struct Hkaffe_util_Ptr *retval = NULL;
+	
+	if( jifa )
+	{
+		struct ifaddrs *ifa = (struct ifaddrs *)jifa;
+		
+		retval = (struct Hkaffe_util_Ptr *)ifa->ifa_next;
+	}
+	return( retval );
+}
+
+struct Hjava_lang_String *
+java_net_NetworkInterfaceImpl_getName(struct Hkaffe_util_Ptr *jifa)
+{
+	struct Hjava_lang_String *retval = NULL;
+
+	if( jifa )
+	{
+		struct ifaddrs *ifa = (struct ifaddrs *)jifa;
+		
+		retval = stringC2Java(ifa->ifa_name);
+	}
+	return( retval );
+}
+
+struct Hjava_lang_String *
+java_net_NetworkInterfaceImpl_getIPAddress(struct Hkaffe_util_Ptr *jifa)
+{
+	struct Hjava_lang_String *retval = NULL;
+
+	if( jifa )
+	{
+		struct ifaddrs *ifa = (struct ifaddrs *)jifa;
+		struct sockaddr *sa;
+
+		if( (sa = ifa->ifa_addr) )
+		{
+#define NII_MAX_ADDRESS_SIZE 128
+			char addr[NII_MAX_ADDRESS_SIZE];
+			
+			switch( sa->sa_family )
+			{
+			case AF_INET:
+				inet_ntop(sa->sa_family,
+					  &((struct sockaddr_in *)sa)->
+					  sin_addr,
+					  addr,
+					  NII_MAX_ADDRESS_SIZE);
+				retval = stringC2Java(addr);
+				break;
+#if defined(AF_INET6)
+			case AF_INET6:
+				inet_ntop(sa->sa_family,
+					  &((struct sockaddr_in6 *)sa)->
+					  sin6_addr,
+					  addr,
+					  NII_MAX_ADDRESS_SIZE);
+				retval = stringC2Java(addr);
+				break;
+#endif
+			default:
+				/* XXX What to do? */
+				break;
+			}
+		}
+	}
+	return( retval );
+}
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ libraries/javalib/java/net/DNSJavaInetAddressImpl.java	Tue Apr 15 09:42:47 2003
@@ -0,0 +1,507 @@
+/*
+ * DNSJavaInetAddressImpl.java
+ *
+ * Copyright (c) 2003 The University of Utah and the Flux Group.
+ * All rights reserved.
+ *
+ * @JANOSVM_KAFFE_BASED_LICENSE@
+ */
+
+package java.net;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import java.io.IOException;
+
+import org.xbill.DNS.Name;
+import org.xbill.DNS.Type;
+import org.xbill.DNS.Cache;
+import org.xbill.DNS.RRset;
+import org.xbill.DNS.Rcode;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.ARecord;
+import org.xbill.DNS.Message;
+import org.xbill.DNS.A6Record;
+import org.xbill.DNS.PTRRecord;
+import org.xbill.DNS.AAAARecord;
+import org.xbill.DNS.FindServer;
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.Credibility;
+import org.xbill.DNS.DNAMERecord;
+import org.xbill.DNS.SetResponse;
+import org.xbill.DNS.ExtendedResolver;
+import org.xbill.DNS.TextParseException;
+import org.xbill.DNS.NameTooLongException;
+
+/**
+ * InetAddressImpl that uses DNSJAVA (http://www.xbill.org/dnsjava).
+ */
+final class DNSJavaInetAddressImpl
+    extends InetAddressImpl
+{
+    /**
+     * Suffix used when doing reverse lookups in IPv4 space.
+     */
+    private static final Name IN_ADDR_ARPA;
+
+    /**
+     * Suffix used when doing reverse lookups in IPv6 space.
+     */
+    private static final Name IP6_INT;
+
+    /**
+     * Maximum number of CNAME records to traverse.
+     */
+    private static final int CNAME_MAX = 6;
+
+    static
+    {
+	try
+	{
+	    IN_ADDR_ARPA = Name.fromString("IN-ADDR.ARPA.");
+	    IP6_INT = Name.fromString("IP6.INT.");
+	}
+	catch(TextParseException e)
+	{
+	    throw new ExceptionInInitializerError(e);
+	}
+    }
+
+    /**
+     * Exception thrown when the name server is queried about a non-existent
+     * domain.
+     */
+    static class NXDomainException
+	extends Exception
+    {
+	/**
+	 * Construct an NXDomainException with the given value.
+	 *
+	 * @param s A message describing the problem.
+	 */
+	public NXDomainException(String s)
+	{
+	    super(s);
+	}
+    }
+
+    /*
+     * The Resolver we'll be using.
+     */
+    private final ExtendedResolver er;
+
+    /**
+     * The default search path.
+     */
+    private final Name searchPath[];
+
+    /**
+     * Lookup cache.
+     */
+    private final Cache cache = new Cache();
+
+    /**
+     * @throws UnknownHostException if the super class could not find the DNS
+     * server.
+     */
+    DNSJavaInetAddressImpl()
+	throws UnknownHostException
+    {
+	boolean foundRootPath = false;
+	Name paths[];
+	int lpc;
+
+	this.er = new ExtendedResolver();
+	/*
+	 * Initialize the search path.  First, make sure the root name space is
+	 * part of the path.
+	 */
+	paths = FindServer.searchPath();
+	for( lpc = 0; lpc < paths.length; lpc++ )
+	{
+	    if( paths[lpc].equals(Name.root) )
+	    {
+		foundRootPath = true;
+	    }
+	}
+	if( !foundRootPath )
+	{
+	    /* The root name space is not in the path, add it. */
+	    this.searchPath = new Name[paths.length + 1];
+	    this.searchPath[this.searchPath.length - 1] = Name.root;
+	}
+	else
+	{
+	    this.searchPath = new Name[paths.length];
+	}
+	System.arraycopy(paths, 0,
+			 this.searchPath, 0,
+			 paths.length);
+    }
+
+    /**
+     * Send and process the response to a query.
+     *
+     * @param question The question to ask the name server.
+     * @param reverse True if this is a reverse lookup and the caller expects
+     * PTRRecords or false if they want A*Records.
+     * @param depth Query counter, used to detect loops in CNAME records.
+     * @return An array of Records corresponding to the ones requested.
+     * @throws UnknownHostException if a problem is encountered while handling
+     * the query.
+     * @throws NXDomainException if the query is for a non-existent domain.
+     */
+    private Record[] doQuery(Record question, boolean reverse, int depth)
+	throws UnknownHostException,
+	       NXDomainException
+    {
+	Record retval[] = null;
+	Message query;
+
+	if( depth >= CNAME_MAX )
+	{
+	    /* Break a CNAME loop. */
+	    throw new UnknownHostException("CNAME loop for: "
+					   + question.getName());
+	}
+	
+	query = Message.newQuery(question);
+	try
+	{
+	    Message response;
+	    SetResponse sr;
+
+	    response = this.er.send(query);
+	    switch( response.getHeader().getRcode() )
+	    {
+	    case Rcode.NOERROR:
+		sr = this.cache.addMessage(response);
+
+		if( sr == null )
+		{
+		    sr = this.cache.lookupRecords(question.getName(),
+						  Type.ANY,
+						  Credibility.NORMAL);
+		}
+
+		if( sr.isSuccessful() )
+		{
+		    RRset rrsets[] = sr.answers();
+		    List list = new ArrayList();
+		    int lpc;
+
+		    /* Presumably, we got what we wanted. */
+		    for( lpc = 0; lpc < rrsets.length; lpc++ )
+		    {
+			Iterator it;
+
+			it = rrsets[lpc].rrs();
+			while( it.hasNext() )
+			{
+			    Object record;
+
+			    record = it.next();
+			    /*
+			     * Add only the records the caller is interested
+			     * in...
+			     */
+			    if( !reverse && record instanceof ARecord )
+			    {
+				/* ... IPv4 */
+				list.add(record);
+			    }
+			    else if( !reverse && record instanceof A6Record )
+			    {
+				/* ... IPv6 */
+				list.add(record);
+			    }
+			    else if( !reverse && record instanceof AAAARecord )
+			    {
+				/* ... IPv6 */
+				list.add(record);
+			    }
+			    else if( reverse && record instanceof PTRRecord )
+			    {
+				/* ... reverse lookup */
+				list.add(record);
+			    }
+			}
+		    }
+		    retval = new Record[list.size()];
+		    list.toArray(retval);
+		}
+		else if( sr.isCNAME() )
+		{
+		    CNAMERecord cname = sr.getCNAME();
+
+		    /* Given name is an alias, follow the canonical name. */
+		    retval = this.doQuery(Record.newRecord(cname.getTarget(),
+							   Type.ANY,
+							   DClass.IN),
+					  reverse,
+					  depth + 1);
+		}
+		else if( sr.isNXRRSET() )
+		{
+		    /* The server has the name but no data. */
+		    throw new UnknownHostException("No data for host: "
+						   + question.getName());
+		}
+		else if( sr.isDNAME() )
+		{
+		    DNAMERecord dname = sr.getDNAME();
+		    
+		    /*
+		     * Substitute part of the domain name with one from the
+		     * server.
+		     */
+		    try
+		    {
+			retval = this.doQuery(
+				Record.newRecord(question.getName().
+						 fromDNAME(dname),
+						 Type.ANY,
+						 DClass.IN),
+				reverse,
+				depth + 1);
+		    }
+		    catch(NameTooLongException e)
+		    {
+			throw new UnknownHostException(
+				"Substituting "
+				+ dname.getTarget()
+				+ " for "
+				+ dname.getName()
+				+ " in "
+				+ question.getName()
+				+ " created an illegally long name",
+				e);
+		    }
+		}
+		else
+		{
+		    /* Bad response (or bad handling by us). */
+		    throw new UnknownHostException("Broken name server");
+		}
+		break;
+	    case Rcode.NXDOMAIN:
+		sr = this.cache.addMessage(response);
+		throw new NXDomainException("Unknown host: "
+					    + question.getName());
+	    default:
+		throw new UnknownHostException("Broken name server");
+	    }
+	}
+	catch(IOException e)
+	{
+	    throw new UnknownHostException("Cannot reach name server", e);
+	}
+	return retval;
+    }
+
+    private Record[] doQuery(Record question, boolean reverse)
+	throws NameTooLongException,
+	       UnknownHostException,
+	       NXDomainException
+    {
+	return this.doQuery(question, reverse, 0);
+    }
+    
+    private Record[] doQuery(Name name, Name suffix, boolean reverse)
+	throws NameTooLongException,
+	       UnknownHostException,
+	       NXDomainException
+    {
+	if( suffix != null )
+	{
+	    name = Name.concatenate(name, suffix);
+	}
+	return this.doQuery(Record.newRecord(name, Type.ANY, DClass.IN),
+			    reverse);
+    }
+    
+    private Record[] doQuery(Name name)
+	throws UnknownHostException,
+	       NXDomainException
+    {
+	try
+	{
+	    return this.doQuery(name, (Name)null, false);
+	}
+	catch(NameTooLongException e)
+	{
+	    throw new InternalError(e);
+	}
+    }
+
+    private Record[] doQuery(byte addr[])
+	throws UnknownHostException,
+	       NXDomainException
+    {
+	try
+	{
+	    StringBuffer sb = new StringBuffer();
+	    Name suffix;
+	    int lpc;
+
+	    /* Need to construct a name that is in IP address form. */
+	    switch( addr.length )
+	    {
+	    case 4:
+		for( lpc = addr.length - 1; lpc >= 0; lpc-- )
+		{
+		    sb.append(addr[lpc] & 0xFF);
+		    if( lpc > 0 )
+			sb.append(".");
+		}
+		suffix = IN_ADDR_ARPA;
+		break;
+	    case 16:
+		for( lpc = addr.length - 1; lpc >= 0; lpc-- )
+		{
+		    sb.append(addr[lpc] & 0x0F);
+		    sb.append(".");
+		    sb.append(addr[lpc] & 0xF0);
+		    if( lpc > 0 )
+			sb.append(".");
+		}
+		suffix = IP6_INT;
+		break;
+	    default:
+		throw new InternalError("Cannot handle address length: "
+					+ addr.length);
+	    }
+	    return this.doQuery(Name.fromString(sb.toString()),
+				suffix,
+				true);
+	}
+	catch(TextParseException e)
+	{
+	    throw new InternalError(e);
+	}
+	catch(NameTooLongException e)
+	{
+	    throw new InternalError(e);
+	}
+    }
+
+    byte[][] lookupAllHostAddr(String host)
+	throws UnknownHostException
+    {
+	byte retval[][];
+
+	try
+	{
+	    Name name = Name.fromString(host);
+	    Record answer[] = null;
+	    int lpc;
+	    
+	    if( name.isAbsolute() )
+	    {
+		try
+		{
+		    /*
+		     * Absolute address, don't try it with the suffixes in the
+		     * search path.
+		     */
+		    answer = this.doQuery(name);
+		}
+		catch(NXDomainException e)
+		{
+		    throw new UnknownHostException("Unknown host: "
+						   + host,
+						   e);
+		}
+	    }
+	    else
+	    {
+		/* Relative address, scan the path. */
+		for( lpc = 0;
+		     (lpc < this.searchPath.length) && (answer == null);
+		     lpc++ )
+		{
+		    try
+		    {
+			answer = this.doQuery(name,
+					      this.searchPath[lpc],
+					      false);
+		    }
+		    catch(NameTooLongException e)
+		    {
+			/* Ignore. */
+		    }
+		    catch(NXDomainException e)
+		    {
+			/* Ignore. */
+		    }
+		}
+		if( answer == null )
+		{
+		    throw new UnknownHostException("Unknown host: "
+						   + host);
+		}
+	    }
+
+	    /* Convert the reply to a set of byte arrays. */
+	    retval = new byte[answer.length][];
+	    for( lpc = 0; lpc < answer.length; lpc++ )
+	    {
+		if( answer[lpc] instanceof ARecord )
+		{
+		    String str;
+		    
+		    str = answer[lpc].rdataToString();
+		    retval[lpc] = InetAddress.getByName(str).getAddress();
+		}
+		else if( answer[lpc] instanceof A6Record )
+		{
+		    retval[lpc] = ((A6Record)answer[lpc]).getSuffix().
+			toBytes();
+		}
+		else if( answer[lpc] instanceof AAAARecord )
+		{
+		    retval[lpc] = ((AAAARecord)answer[lpc]).getAddress().
+			toBytes();
+		}
+		else
+		{
+		    throw new InternalError("Unhandled record type: "
+					    + answer[lpc]);
+		}
+	    }
+	}
+	catch(TextParseException e)
+	{
+	    throw new UnknownHostException("Badly formatted host name: "
+					   + host,
+					   e);
+	}
+	return retval;
+    }
+
+    String getHostByAddr(byte addr[])
+	throws UnknownHostException
+    {
+	try
+	{
+	    String retval;
+
+	    retval = this.doQuery(addr)[0].rdataToString();
+	    return retval.substring(0, retval.length() - 1);
+	}
+	catch(NXDomainException e)
+	{
+	    throw new UnknownHostException();
+	}
+    }
+
+    public String toString()
+    {
+	return "DNSJavaInetAddressImpl["
+	    + super.toString()
+	    + "]";
+    }
+}
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ libraries/javalib/java/net/Inet4Address.java	Mon Apr 14 20:17:34 2003
@@ -0,0 +1,302 @@
+/* Inet4Address.java
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is 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, 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; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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. */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.ObjectStreamException;
+
+import java.util.StringTokenizer;
+import java.util.NoSuchElementException;
+
+/**
+ * @author Michael Koch
+ * @date August 3, 2002.
+ */
+
+/*
+ * Written using on-line Java Platform 1.4 API Specification and
+ * RFC 1884 (http://www.ietf.org/rfc/rfc1884.txt),
+ * RFC 1918 (http://www.ietf.org/rfc/rfc1918.txt),
+ * RFC 2365 (http://www.ietf.org/rfc/rfc2365.txt)
+ * Status: Believed complete and correct.
+ */
+
+public final class Inet4Address extends InetAddress
+{
+  static final long serialVersionUID = 7615067291688066509L;
+
+  /**
+   * Convert a string formatted as an IPv4 address into a byte array.
+   *
+   * @param address The address to convert.
+   * @return A byte array containing the converted address.
+   * @throws IllegalArgumentException if the address string does not represent
+   * a properly formatted address.
+   */
+  static byte[] fromString(String address)
+    throws IllegalArgumentException
+  {
+    StringTokenizer st = new StringTokenizer(address, ".");
+    byte retval[] = new byte[4];
+    
+    try
+    {
+      int lpc;
+      
+      for( lpc = 0; lpc < retval.length; lpc++ )
+      {
+	int number;
+
+	number = Integer.parseInt(st.nextToken());
+	if( (number < 0) || (number > 255) )
+	{
+	  throw new IllegalArgumentException("IP address component out of "
+					     + "range: "
+					     + number);
+	}
+	retval[lpc] = (byte)number;
+      }
+      if( st.hasMoreTokens() )
+      {
+	  throw new IllegalArgumentException(
+		"Extraneous data after IP address: "
+		+ address);
+      }
+    }
+    catch(NoSuchElementException e)
+    {
+      throw new IllegalArgumentException(e);
+    }
+    catch(NumberFormatException e)
+    {
+      throw new IllegalArgumentException(e);
+    }
+    return retval;
+  }
+
+  /**
+   * needed for serialization
+   */
+  private Object writeReplace () throws ObjectStreamException
+  {
+    return new InetAddress (addr, hostName);
+  }
+
+  /**
+   * Creates a Inet4Address
+   * 
+   * @param addr The IP address
+   * @param host The Hostname
+   */
+  protected Inet4Address(byte[] addr, String host)
+  {
+    super (addr, host);
+  }
+
+  /**
+   * Checks if the address is a multicast address
+   *
+   * @since 1.1
+   */
+  public boolean isMulticastAddress ()
+  {
+    return (addr [0] & 0xF0) == 0xE0;
+  }
+  
+  /**
+   * Checks if this address is a loopback address
+   */
+  public boolean isLoopbackAddress ()
+  {
+    return addr [0] == 0x7F;
+  }
+ 
+  /**
+   * Checks if this address is a wildcard address
+   *
+   * @since 1.4
+   */
+  public boolean isAnyLocalAddress ()
+  {
+    return super.address == 0;
+  }
+
+  /**
+   * Checks if this address is a link local address
+   * 
+   * @since 1.4
+   */
+  public boolean isLinkLocalAddress ()
+  {
+    // XXX: This seems to not exist with IPv4 addresses
+    return false;
+  }
+
+  /**
+   * Checks if this address is a site local address
+   * 
+   * @since 1.4
+   */
+  public boolean isSiteLocalAddress ()
+  {
+    // 10.0.0.0/8
+    if (addr [0] == 0x0A)
+      return true;
+
+    // XXX: Suns JDK 1.4.1 (on Linux) seems to have a bug here:
+    // it says 172.16.0.0 - 172.255.255.255 are site local addresses
+    //
+    // 172.16.0.0/12
+    if (addr [0] == 0xAC && (addr [1] & 0xF0) == 0x01)
+      return true;
+
+    // 192.168.0.0/16
+    if (addr [0] == 0xC0 && addr [1] == 0xA8)
+      return true;
+   
+    // XXX: Do we need to check more addresses here ?
+    return false;
+  }
+
+  /**
+   * Checks if this multicast address has global scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCGlobal ()
+  {
+    // XXX: This seems to net exist with IPv4 addresses
+    return false;
+  }
+
+  /**
+   * Checks if this multicast address has node scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCNodeLocal ()
+  {
+    // XXX: This seems to net exist with IPv4 addresses
+    return false;
+  }
+  
+  /**
+   * Checks if this multicast address has link scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCLinkLocal ()
+  {
+    if (!isMulticastAddress ())
+      return false;
+    
+    return (addr [0] == 0xE0)
+	   && (addr [1] == 0x00)
+	   && (addr [2] == 0x00);
+  }
+  
+  /**
+   * Checks if this multicast address has site scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCSiteLocal ()
+  {
+    // XXX: This seems to net exist with IPv4 addresses
+    return false;
+  }
+  
+  /**
+   * Checks if this multicast address has organization scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCOrgLocal ()
+  {
+    // XXX: This seems to net exist with IPv4 addresses
+    return false;
+  }
+  
+  /**
+   * Returns the address of the current instance
+   */
+  public byte[] getAddress ()
+  {
+    return (byte[])addr.clone();
+  }
+  
+  /**
+   * Returns the address as string
+   * 
+   * @since 1.0.2
+   */
+  public String getHostAddress ()
+  {
+    StringBuffer sbuf = new StringBuffer (40);
+    int len = addr.length;
+    int i = 0;
+    
+    for ( ;  ; )
+      {
+	sbuf.append (addr [i] & 0xFF);
+	i++;
+	
+	if (i == len)
+	  break;
+	
+	sbuf.append ('.');
+      }
+    
+    return sbuf.toString ();
+  }
+  
+  /**
+   * Computes the hashcode of the instance
+   */
+  public int hashCode ()
+  {
+    int hash = 0;
+    int len = addr.length;
+    int i = len > 4 ? len - 4 : 0;
+    
+    for ( ; i < len;  i++)
+      hash = (hash << 8) | (addr [i] & 0xFF);
+    
+    return hash;
+  }
+} // class Inet4Address
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ libraries/javalib/java/net/Inet6Address.java	Tue Apr 15 09:39:15 2003
@@ -0,0 +1,284 @@
+/* Inet6Address.java
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is 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, 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; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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. */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * @author Michael Koch
+ * @date August 3, 2002.
+ */
+
+/*
+ * Written using on-line Java Platform 1.4 API Specification and
+ * RFC 1884 (http://www.ietf.org/rfc/rfc1884.txt)
+ * Status: Believed complete and correct.
+ */
+
+public final class Inet6Address extends InetAddress
+{
+  static final long serialVersionUID = 6880410070516793377L;
+
+  private static final byte ANY_LOCAL[] = { 0, 0, 0, 0, 0, 0, 0, 0,
+					    0, 0, 0, 0, 0, 0, 0, 0 };
+
+  private static final byte LOOPBACK[] = { 0, 0, 0, 0, 0, 0, 0, 0,
+					   0, 0, 0, 0, 0, 0, 0, 1 };
+
+  private static boolean compareAddresses(byte a1[], byte a2[])
+  {
+    boolean retval = true;
+    int lpc;
+    
+    for( lpc = 0; lpc < a1.length && retval; lpc++ )
+    {
+      retval = (a1[lpc] == a2[lpc]);
+    }
+    return retval;
+  }
+  
+  /**
+   * Needed for serialization
+   */
+  byte[] ipaddress;
+  
+  /**
+   * Create an Inet6Address object
+   *
+   * @param addr The IP address
+   * @param host The hostname
+   */
+  protected Inet6Address (byte[] addr, String host)
+  {
+    super (addr, host);
+    this.ipaddress = addr;
+  }
+
+  /**
+   * Utility routine to check if the InetAddress is an IP multicast address
+   * 
+   * @since 1.1
+   */
+  public boolean isMulticastAddress ()
+  {
+    return ipaddress [0] == 0xFF;
+  }
+ 
+  /**
+   * Utility routine to check if the InetAddress in a wildcard address
+   * 
+   * @since 1.4
+   */
+  public boolean isAnyLocalAddress ()
+  {
+    return compareAddresses(this.ipaddress, ANY_LOCAL);
+  }
+	  
+  /**
+   * Utility routine to check if the InetAddress is a loopback address
+   * 
+   * @since 1.4
+   */
+  public boolean isLoopbackAddress ()
+  {
+    return compareAddresses(this.ipaddress, LOOPBACK);
+  }
+
+  /**
+   * Utility routine to check if the InetAddress is an link local address
+   * 
+   * @since 1.4
+   */
+  public boolean isLinkLocalAddress ()
+  {
+    return ipaddress [0] == 0xFA;
+  }
+
+  /**
+   * Utility routine to check if the InetAddress is a site local address
+   * 
+   * @since 1.4
+   */
+  public boolean isSiteLocalAddress ()
+  {
+    return ipaddress [0] == 0xFB;
+  }
+
+  /**
+   * Utility routine to check if the multicast address has global scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCGlobal ()
+  {
+    if (!isMulticastAddress ())
+      return false;
+    
+    return (ipaddress [1] & 0x0F) == 0xE;
+  }
+
+  /**
+   * Utility routine to check if the multicast address has node scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCNodeLocal ()
+  {
+    if (!isMulticastAddress ())
+      return false;
+    
+    return (ipaddress [1] & 0x0F) == 0x1;
+  }
+
+  /**
+   * Utility routine to check if the multicast address has link scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCLinkLocal ()
+  {
+    if (!isMulticastAddress ())
+      return false;
+    
+    return (ipaddress [1] & 0x0F) == 0x2;
+  }
+
+  /**
+   * Utility routine to check if the multicast address has site scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCSiteLocal ()
+  {
+    if (!isMulticastAddress ())
+      return false;
+    
+    return (ipaddress [1] & 0x0F) == 0x5;
+  }
+
+  /**
+   * Utility routine to check if the multicast address has organization scope
+   * 
+   * @since 1.4
+   */
+  public boolean isMCOrgLocal ()
+  {
+    if (!isMulticastAddress ())
+      return false;
+    
+    return (ipaddress [1] & 0x0F) == 0x8;
+  }
+  
+  /**
+   * Returns the raw IP address of this InetAddress object. The result is in
+   * network byte order: the highest order byte of the address is i
+   * n getAddress()[0]
+   */
+  public byte[] getAddress ()
+  {
+    return ipaddress;
+  }
+  
+  /**
+   * Returns the IP address string in textual presentation
+   */
+  public String getHostAddress ()
+  {
+    StringBuffer sbuf = new StringBuffer (40);
+
+    for (int i = 0; i < 16; i += 2)
+      {
+        int x = ((ipaddress [i] & 0xFF) << 8) | (ipaddress [i + 1] & 0xFF);
+        boolean empty = sbuf.length () == 0;
+	
+        if (empty)
+          {
+            if (i > 0)
+              sbuf.append ("::");
+          }
+        else
+          sbuf.append (':');
+
+        if (x != 0 || i >= 14)
+          sbuf.append (Integer.toHexString (x));
+      }
+   
+    return sbuf.toString ();
+  }
+
+  /**
+   * Returns a hashcode for this IP address
+   */
+  public int hashCode ()
+  {
+    return super.hashCode ();
+  }
+ 
+  /**
+   * Compares this object against the specified object
+   */
+  public boolean equals (Object obj)
+  {
+    if (obj == null || ! (obj instanceof Inet6Address))
+      return false;
+
+    Inet6Address tmp = (Inet6Address) obj;
+
+    return super.equals (tmp)
+      && compareAddresses(this.ipaddress, tmp.ipaddress);
+  }
+  
+  /**
+   * Utility routine to check if the InetAddress is an
+   * IPv4 compatible IPv6 address
+   *
+   * @since 1.4
+   */
+  public boolean isIPv4CompatibleAddress ()
+  {
+    if (ipaddress [0] != 0x00 || ipaddress [1] != 0x00 ||
+        ipaddress [2] != 0x00 || ipaddress [3] != 0x00 ||
+	ipaddress [4] != 0x00 || ipaddress [5] != 0x00 ||
+	ipaddress [6] != 0x00 || ipaddress [7] != 0x00 ||
+	ipaddress [8] != 0x00 || ipaddress [9] != 0x00 ||
+	ipaddress [10] != 0x00 || ipaddress [11] != 0x00)
+      return false;
+
+    return true;
+  }
+}
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ libraries/javalib/java/net/NativeInetAddressImpl.java	Mon Apr 14 20:18:23 2003
@@ -0,0 +1,36 @@
+/*
+ * Java core library component.
+ *
+ * Copyright (c) 1997, 1998
+ *      Transvirtual Technologies, Inc.  All rights reserved.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file.
+ */
+
+package java.net;
+
+/**
+ * InetAddressImpl that uses native functions (getaddrinfo(), getnameinfo()).
+ */
+class NativeInetAddressImpl
+    extends InetAddressImpl
+{
+    native byte[][] lookupAllHostAddr0(String host)
+	throws UnknownHostException;
+
+    byte[][] lookupAllHostAddr(String host)
+	throws UnknownHostException
+    {
+	return this.lookupAllHostAddr0(host);
+    }
+    
+    native String getHostByAddr0(byte addr[])
+	throws UnknownHostException;
+    
+    String getHostByAddr(byte addr[])
+	throws UnknownHostException
+    {
+	return this.getHostByAddr0(addr);
+    }
+}
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ libraries/javalib/java/net/NetworkInterfaceImpl.java	Mon Apr 14 20:18:04 2003
@@ -0,0 +1,168 @@
+/*
+ * NetworkInterfaceImpl.java
+ *
+ * Copyright (c) 2003 University of Utah and the Flux Group.
+ * All rights reserved.
+ *
+ * This file is licensed under the terms of the GNU Public License.
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * Contributed by the Flux Research Group, Department of Computer Science,
+ * University of Utah, http://www.cs.utah.edu/flux/
+ */
+
+package java.net;
+
+import java.util.Hashtable;
+
+/**
+ * Implementation specific functions for querying the set of NetworkInterfaces
+ */
+class NetworkInterfaceImpl
+{
+    static
+    {
+	/* Our native implementation is in kaffenet */
+	System.loadLibrary("net");
+    }
+    
+    /**
+     * Detect the interfaces in this machine.
+     *
+     * @return The native list of interfaces.
+     * @throws SocketException if there is a problem with the native code.
+     */
+    private static native kaffe.util.Ptr detectInterfaces()
+	throws SocketException;
+
+    /**
+     * Free the native objects returned by detectInterfaces.
+     *
+     * @param ifaddrs The pointer returned by detectInterfaces or null.
+     */
+    private static native void freeInterfaces(kaffe.util.Ptr ifaddrs);
+
+    /**
+     * Get the next interface in the native list.
+     *
+     * @param ifaddr The current interface.
+     * @return The next interface in the list or null if there are no more.
+     */
+    private static native kaffe.util.Ptr getNext(kaffe.util.Ptr ifaddr);
+
+    /**
+     * @param ifaddr The current interface.
+     * @return The name encoded in the native object.
+     */
+    private static native String getName(kaffe.util.Ptr ifaddr);
+    
+    /**
+     * @param ifaddr The current interface.
+     * @return The IP address of this interface as a string or null if the
+     * native object doesn't have an IP address.
+     */
+    private static native String getIPAddress(kaffe.util.Ptr ifaddr);
+    
+    /**
+     * The detected interfaces, the table maps names to NetworkInterface
+     * objects.
+     */
+    private final Hashtable detectedInterfaces = new Hashtable();
+    
+    /**
+     * Secondary mapping from InetAddresses to interface names.
+     */
+    private final Hashtable addressToName = new Hashtable();
+
+    /**
+     * Construct a NetworkInterfaceImpl.
+     *
+     * @throws SocketException if there was a problem reading the set of
+     * NetworkInterfaces.
+     */
+    NetworkInterfaceImpl()
+	throws SocketException
+    {
+	kaffe.util.Ptr ifaddrs = null, curr = null;
+
+	try
+	{
+	    /* Detect all the network interfaces. */
+	    curr = ifaddrs = detectInterfaces();
+	    while( curr != null )
+	    {
+		NetworkInterface ni;
+		String name;
+		
+		name = getName(curr);
+		if( (ni = (NetworkInterface)this.detectedInterfaces.get(name))
+		    == null )
+		{
+		    ni = new NetworkInterface(name, name /* XXX */);
+		    this.detectedInterfaces.put(name, ni);
+		}
+		try
+		{
+		    String address;
+
+		    if( (address = getIPAddress(curr)) != null )
+		    {
+			InetAddress ia;
+
+			ia = InetAddress.getByName(address);
+			ni.setPrimaryAddress(ia);
+			this.addressToName.put(ia, ni.getName());
+			ni.getInetAddressesInternal().addElement(ia);
+		    }
+		}
+		catch(UnknownHostException e)
+		{
+		    /* Ignore... */
+		}
+		curr = getNext(curr);
+	    }
+	    this.detectedInterfaces.elements();
+	}
+	finally
+	{
+	    /* Make sure to free the native objects. */
+	    freeInterfaces(ifaddrs);
+	}
+    }
+
+    /**
+     * @return The table of detected interfaces.
+     */
+    Hashtable getDetectedInterfaces()
+    {
+	return this.detectedInterfaces;
+    }
+
+    /**
+     * @return The table that maps InetAddress' to the NIC name.
+     */
+    Hashtable getAddressToName()
+    {
+	return this.addressToName;
+    }
+
+    /**
+     * @param ia An InetAddress to map to a NIC name.
+     * @return The NIC name that has the given address or null if there is no
+     * mapping.
+     */
+    String nameForAddress(InetAddress ia)
+    {
+	return (String)this.addressToName.get(ia);
+    }
+    
+    public String toString()
+    {
+	return "NetworkInterfaceImpl[detectedInterfaces={ "
+	    + this.detectedInterfaces
+	    + " }; addressToName={ "
+	    + this.addressToName
+	    + "]";
+    }
+}
--- /dev/null	Tue Apr 15 13:18:29 2003
+++ test/regression/InetAddressTest.java	Mon Apr 14 20:53:41 2003
@@ -0,0 +1,30 @@
+
+import java.net.InetAddress;
+
+public class InetAddressTest
+{
+    public static void main(String args[])
+	throws Throwable
+    {
+	InetAddress ia;
+
+	ia = InetAddress.getByName(null);
+	System.out.println("(null) = " + ia);
+	
+	ia = InetAddress.getByName("");
+	System.out.println("\"\" = " + ia);
+	
+	ia = InetAddress.getByName("localhost");
+	System.out.println("localhost = " + ia);
+	if( !ia.isLoopbackAddress() )
+	{
+	    System.out.println("Not a loopback?");
+	}
+    }
+}
+
+/* Expected Output:
+(null) = localhost/127.0.0.1
+"" = localhost/127.0.0.1
+localhost = localhost/127.0.0.1
+*/
Index: Makefile.am
===================================================================
RCS file: /cvs/kaffe/kaffe/Makefile.am,v
retrieving revision 1.25
diff -u -r1.25 Makefile.am
--- Makefile.am	21 Feb 2003 09:51:06 -0000	1.25
+++ Makefile.am	15 Apr 2003 19:28:57 -0000
@@ -96,7 +96,7 @@
 		"DEBUG_ENV=$(DEBUG_ENV)" BUILD_ENVIRONMENT-make
 
 BUILD_ENVIRONMENT-make: Makefile
-	echo CLASSPATH=\$${CLASSPATH}\''$(PATHSEP)'\'.\''$(PATHSEP)'\'$(top_builddir)/libraries/javalib/rt.jar\''$(PATHSEP)'\'$(top_srcdir)/libraries/javalib/kjc.jar\; export CLASSPATH | sed 's,/,$(DIRSEP),g;s,\\,\\\\,g' > BUILD_ENVIRONMENT.new; \
+	echo CLASSPATH=\$${CLASSPATH}\''$(PATHSEP)'\'.\''$(PATHSEP)'\'$(top_builddir)/libraries/javalib/rt.jar\''$(PATHSEP)'\'$(top_srcdir)/libraries/javalib/kjc.jar\''$(PATHSEP)'\'$(DNSJAVA_JAR)\; export CLASSPATH | sed 's,/,$(DIRSEP),g;s,\\,\\\\,g' > BUILD_ENVIRONMENT.new; \
 	echo KAFFELIBRARYPATH=\$${KAFFELIBRARYPATH+\"\$$KAFFELIBRARYPATH\"\''$(PATHSEP)'\'}`for f in $(JAVA_LIBS); do echo "$$f" | sed 's%/[^/]*$$%%'; done | (tr '\012' ' '; echo) | sed -e 's/ $$//' -e "s/ /\'$(PATHSEP)\'/g"`\; export KAFFELIBRARYPATH >> BUILD_ENVIRONMENT.new; \
 	echo JAVA=$(top_builddir)/kaffe/kaffe/kaffe-bin$(EXEEXT)\; export JAVA >> BUILD_ENVIRONMENT.new
 	rm -f BUILD_ENVIRONMENT
Index: configure.in
===================================================================
RCS file: /cvs/kaffe/kaffe/configure.in,v
retrieving revision 1.188
diff -u -r1.188 configure.in
--- configure.in	11 Mar 2003 08:00:14 -0000	1.188
+++ configure.in	15 Apr 2003 19:28:59 -0000
@@ -336,6 +336,18 @@
 esac
 
 dnl =========================================================================
+dnl Allow user to specify a dnsjava.jar file for class file testing.
+dnl -------------------------------------------------------------------------
+
+AC_ARG_WITH(dnsjava,
+  [  --with-dnsjava=<jar>       Use the specified DNS java Jar file.],
+  [ DNSJAVA_JAR="$withval" ],
+  [ DNSJAVA_JAR="" ])
+
+AC_SUBST(DNSJAVA_JAR)
+AM_CONDITIONAL(HAVE_DNSJAVA, test x"$DNSJAVA_JAR" != x"")
+
+dnl =========================================================================
 dnl Allow support for profiling of C/jitted code
 dnl -------------------------------------------------------------------------
 
@@ -982,6 +994,7 @@
 AC_CHECK_FUNCS([mkdir rmdir])
 AC_CHECK_FUNCS([getcwd chdir getwd gettimeofday ftime time uname getuid])
 AC_CHECK_FUNCS([localtime])
+AC_CHECK_FUNCS([getaddrinfo])
 
 AM_ICONV
 LIBS="$LIBS $LIBICONV"
Index: include/Arrays.h
===================================================================
RCS file: /cvs/kaffe/kaffe/include/Arrays.h,v
retrieving revision 1.3
diff -u -r1.3 Arrays.h
--- include/Arrays.h	13 Feb 1999 09:21:55 -0000	1.3
+++ include/Arrays.h	15 Apr 2003 19:28:59 -0000
@@ -29,5 +29,14 @@
 /* Get length of arrays */
 #define	obj_length(_obj)	((_obj)->length)
 #define unhand_array(_arr)	((_arr)->data)
+#define unhand_byte_array(_arr)		((jbyte *)((_arr)->data))
+#define unhand_char_array(_arr)		((jchar *)((_arr)->data))
+#define unhand_double_array(_arr)	((jdouble *)((_arr)->data))
+#define unhand_float_array(_arr)	((jfloat *)((_arr)->data))
+#define unhand_int_array(_arr)		((jint *)((_arr)->data))
+#define unhand_short_array(_arr)	((jshort *)((_arr)->data))
+#define unhand_long_array(_arr)		((jlong *)((_arr)->data))
+#define unhand_array_array(_arr)	((Hjava_lang_Object **)((_arr)->data))
+#define unhand_object_array(_arr)	((Hjava_lang_Object *)((_arr)->data))
 
 #endif
Index: include/Makefile.am
===================================================================
RCS file: /cvs/kaffe/kaffe/include/Makefile.am,v
retrieving revision 1.32
diff -u -r1.32 Makefile.am
--- include/Makefile.am	13 Apr 2003 09:20:33 -0000	1.32
+++ include/Makefile.am	15 Apr 2003 19:28:59 -0000
@@ -70,8 +70,10 @@
 	java_net_DatagramPacket.h \
 	java_net_InetAddress.h \
 	java_net_InetAddressImpl.h \
+	java_net_NativeInetAddressImpl.h \
 	java_net_InetSocketAddress.h \
 	java_net_NetworkInterface.h \
+	java_net_NetworkInterfaceImpl.h \
 	java_net_PlainDatagramSocketImpl.h \
 	java_net_PlainSocketImpl.h \
 	java_net_SocketAddress.h \
Index: include/errors.h
===================================================================
RCS file: /cvs/kaffe/kaffe/include/errors.h,v
retrieving revision 1.6
diff -u -r1.6 errors.h
--- include/errors.h	2 Jun 2002 02:24:03 -0000	1.6
+++ include/errors.h	15 Apr 2003 19:28:59 -0000
@@ -64,6 +64,7 @@
 
 #define JAVA_LANG(NAME)		"java.lang." #NAME
 #define JAVA_IO(NAME)		"java.io." #NAME
+#define JAVA_NET(NAME)		"java.net." #NAME
 
 
 #define NEW_LANG_EXCEPTION(NAME) \
Index: libraries/clib/net/InetAddressImpl.c
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/clib/net/InetAddressImpl.c,v
retrieving revision 1.12
diff -u -r1.12 InetAddressImpl.c
--- libraries/clib/net/InetAddressImpl.c	26 Dec 2000 14:01:48 -0000	1.12
+++ libraries/clib/net/InetAddressImpl.c	15 Apr 2003 19:29:00 -0000
@@ -13,6 +13,7 @@
 #include "config-mem.h"
 #include "config-net.h"
 #include "config-io.h"
+#include <arpa/inet.h>
 #include "../../../kaffe/kaffevm/gtypes.h"
 #include "../../../kaffe/kaffevm/object.h"
 #include <native.h>
@@ -21,132 +22,530 @@
 #include "../../../kaffe/kaffevm/support.h"
 #include "java_net_InetAddress.h"
 #include "java_net_InetAddressImpl.h"
+#include "java_net_NativeInetAddressImpl.h"
 #include "nets.h"
 #include "jsyscall.h"
 
-#define	HOSTNMSZ	80
+#include "baseClasses.h"
+#include "locks.h"
+
+#define	HOSTNMSZ	1024
 
 /*
- * Get localhost name.
+ * Return the inet address family.
  */
-struct Hjava_lang_String*
-java_net_InetAddressImpl_getLocalHostName(struct Hjava_net_InetAddressImpl* none)
+jint
+java_net_InetAddressImpl_getInetFamily(jint kind)
 {
-	char hostname[HOSTNMSZ];
-
-	if (gethostname(hostname, HOSTNMSZ-1) < 0) {
-		strcpy(hostname, "localhost");
+	jint retval = -1;
+	errorInfo einfo;
+	
+	assert(kind > java_net_InetAddressImpl_INET_ADDRESS_MIN);
+	assert(kind < java_net_InetAddressImpl_INET_ADDRESS_MAX);
+	
+	switch( kind )
+	{
+	case java_net_InetAddressImpl_INET_ADDRESS_V4:
+		retval = AF_INET;
+		break;
+#if defined(AF_INET6)
+	case java_net_InetAddressImpl_INET_ADDRESS_V6:
+		retval = AF_INET6;
+		break;
+#endif
+	default:
+		postExceptionMessage(&einfo,
+				     JAVA_LANG(InternalError),
+				     "Unknown family: %d",
+				     kind);
+		throwError(&einfo);
+		break;
 	}
-	return (checkPtr(stringC2Java(hostname)));
+	return( retval );
 }
 
 /*
- * Provide one of my local address (I guess).
+ * Get localhost name.
  */
-void
-java_net_InetAddressImpl_makeAnyLocalAddress(struct Hjava_net_InetAddressImpl* none, struct Hjava_net_InetAddress* this)
+struct Hjava_lang_String*
+java_net_InetAddressImpl_getLocalHostName(void)
 {
-	unhand(this)->hostName = 0;
-	unhand(this)->address = INADDR_ANY;
-	unhand(this)->family = AF_INET;
+	static char hostname[HOSTNMSZ] = "localhost";
+	static iLock *hostLock = 0;
+	
+	struct Hjava_lang_String *retval = 0;
+	int iLockRoot;
+	
+	lockStaticMutex(&hostLock);
+	if( gethostname(hostname, HOSTNMSZ - 1) < 0 )
+	{
+		assert(0);
+	}
+	retval = stringC2Java(hostname);
+	unlockStaticMutex(&hostLock);
+
+	return( checkPtr(retval) );
 }
 
 /*
- * Convert a hostname to the primary host address.
+ * Attempt to convert a string containing an IP address into a byte array.
  */
-jint
-java_net_InetAddressImpl_lookupHostAddr(struct Hjava_net_InetAddressImpl* none, struct Hjava_lang_String* str)
+HArrayOfByte*
+java_net_InetAddressImpl_stringToBits(Hjava_lang_String *jStr)
 {
-	char name[MAXHOSTNAME];
-	struct hostent* ent;
-	int rc;
-
-	stringJava2CBuf(str, name, sizeof(name));
+	HArrayOfByte *retval = NULL;
 
-	rc = KGETHOSTBYNAME(name, &ent);
-	if (rc) {
-		if (ent == (void *)-1) {
-			SignalError("java.io.IOException", SYS_ERROR(rc));
+#define MAX_IPV6_STRING_SIZE 128
+	if( jStr->count < MAX_IPV6_STRING_SIZE )
+	{
+		char str[MAX_IPV6_STRING_SIZE];
+
+		stringJava2CBuf(jStr, str, MAX_IPV6_STRING_SIZE);
+		{
+			struct in_addr ia;
+			
+			if( inet_pton(AF_INET, str, &ia) == 1 )
+			{
+				retval = (HArrayOfByte *)
+					newArray(TYPE_CLASS(TYPE_Byte),
+						 sizeof(ia));
+				memcpy(unhand_byte_array(retval),
+				       &ia,
+				       sizeof(ia));
+			}
 		}
-		else {
-			SignalErrorf("java.net.UnknownHostException", "%s: %s",
-				     SYS_HERROR(rc), name);
+#if defined(AF_INET6)
+		if( retval == NULL )
+		{
+			struct in6_addr ia;
+
+			if( inet_pton(AF_INET6, str, &ia) == 1 )
+			{
+				retval = (HArrayOfByte *)
+					newArray(TYPE_CLASS(TYPE_Byte),
+						 sizeof(ia));
+				memcpy(unhand_byte_array(retval),
+				       &ia,
+				       sizeof(ia));
+			}
 		}
+#endif
 	}
-	return (ntohl(*(jint*)ent->h_addr_list[0]));
+	return( retval );
 }
 
+static iLock *nsLock = 0;
+
 /*
  * Convert a hostname to an array of host addresses.
  */
-HArrayOfInt*
-java_net_InetAddressImpl_lookupAllHostAddr(struct Hjava_net_InetAddressImpl* none, struct Hjava_lang_String* str)
+HArrayOfArray*
+java_net_NativeInetAddressImpl_lookupAllHostAddr0(struct Hjava_net_NativeInetAddressImpl* none, struct Hjava_lang_String* jStr)
 {
+#if defined(HAVE_GETADDRINFO)
+	int index = 0, count = 0, retryCount = 5, rc;
+	struct addrinfo hints, *ai = 0, *curr;
+	HArrayOfArray *retval = 0;
+	int iLockRoot;
+	errorInfo einfo;
+	char *name;
+	
+	name = checkPtr(stringJava2C(jStr));
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+	lockStaticMutex(&nsLock);
+	while( ((rc = getaddrinfo(name, NULL, &hints, &ai)) ==
+		EAI_AGAIN) &&
+	       (retryCount > 0) )
+	{
+		unlockStaticMutex(&nsLock);
+		jthread_sleep(1 * 1000);
+		lockStaticMutex(&nsLock);
+		retryCount -= 1;
+	}
+	unlockStaticMutex(&nsLock);
+	
+	switch( rc )
+	{
+	case 0:
+		/* Count the number of addresses. */
+		curr = ai;
+		while( curr )
+		{
+			switch( curr->ai_family )
+			{
+			case PF_INET:
+#if defined(PF_INET6)
+			case PF_INET6:
+#endif
+				count += 1;
+				break;
+			}
+			curr = curr->ai_next;
+		}
+		
+		retval = (HArrayOfArray *)
+			newArrayChecked(ObjectClass, count, &einfo);
+		curr = ai;
+		while( curr && retval )
+		{
+#if defined(PF_INET6)
+			struct sockaddr_in6 *in6;
+#endif
+			struct sockaddr_in *in4;
+			HArrayOfByte *addr = 0;
+			
+			switch( curr->ai_family )
+			{
+			case PF_INET:
+				in4 = (struct sockaddr_in *)
+					curr->ai_addr;
+				addr = (HArrayOfByte *)newArrayChecked(
+					TYPE_CLASS(TYPE_Byte),
+					sizeof(in4->sin_addr),
+					&einfo);
+				if( addr )
+				{
+					memcpy(unhand_byte_array(addr),
+					       &in4->sin_addr,
+					       sizeof(in4->sin_addr));
+				}
+				else
+				{
+					retval = 0;
+				}
+				break;
+#if defined(PF_INET6)
+			case PF_INET6:
+				in6 = (struct sockaddr_in6 *)
+					curr->ai_addr;
+				addr = (HArrayOfByte *)newArrayChecked(
+					TYPE_CLASS(TYPE_Byte),
+					sizeof(in6->sin6_addr),
+					&einfo);
+				if( addr )
+				{
+					memcpy(unhand_byte_array(addr),
+					       &in6->sin6_addr,
+					       sizeof(in6->sin6_addr));
+				}
+				else
+				{
+					retval = 0;
+				}
+				break;
+#endif
+			default:
+				/* Ignore */
+				break;
+			}
+			if( addr && retval )
+			{
+				unhand_array_array(retval)[index] =
+					&addr->base;
+				index += 1;
+			}
+			curr = curr->ai_next;
+		}
+		break;
+	case EAI_FAIL:
+	case EAI_AGAIN:
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "Unable to contact name server");
+		break;
+	case EAI_NODATA:
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "Unknown host: %s",
+				     name);
+		break;
+	case EAI_MEMORY:
+		postOutOfMemory(&einfo);
+		break;
+	case EAI_SYSTEM:
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "%s: %s",
+				     SYS_ERROR(errno),
+				     name);
+		break;
+		
+	default:
+		postExceptionMessage(&einfo,
+				     JAVA_LANG(InternalError),
+				     "Unhandled getaddrinfo error: %s: %s",
+				     gai_strerror(rc),
+				     name);
+		break;
+	}
+	if( ai )
+	{
+		freeaddrinfo(ai);
+	}
+	gc_free(name);
+	if( !retval )
+	{
+		throwError(&einfo);
+	}
+	return( retval );
+#else
+	HArrayOfArray* retval = 0;
 	char name[MAXHOSTNAME];
 	struct hostent* ent;
-	HArrayOfInt* array;
-	int i;
-	int alength;
-	int rc;
-
-	stringJava2CBuf(str, name, sizeof(name));
-
+	int i, alength, rc;
+	errorInfo einfo;
+	
+	stringJava2CBuf(jStr, name, sizeof(name));
 	rc = KGETHOSTBYNAME(name, &ent);
-	if (rc) {
-		if (ent == (void *)-1) {
-			SignalError("java.io.IOException", SYS_ERROR(rc));
+	if( rc == 0 )
+	{
+		for (alength = 0; ent->h_addr_list[alength]; alength++)
+			;
+		
+		if( (retval = (HArrayOfArray*)
+		     newArrayChecked(ObjectClass,
+				     alength,
+				     &einfo)) == 0 )
+		{
+			postOutOfMemory(&einfo);
+			goto done;
 		}
-		else {
-			SignalErrorf("java.net.UnknownHostException", "%s: %s",
-				     SYS_HERROR(rc), name);
+		
+		for( i = 0; i < alength; i++ )
+		{
+			HArrayOfByte *addr = 0;
+			
+			/* Copy in the network address */
+			if( (addr = (HArrayOfByte *)
+			     newArrayChecked(TYPE_CLASS(TYPE_Byte),
+					     ent->h_length,
+					     &einfo)) == 0 )
+			{
+				postOutOfMemory(&einfo);
+				goto done;
+			}
+			memcpy(unhand_byte_array(addr),
+			       ent->h_addr_list[i],
+			       ent->h_length);
+			
+			unhand_array_array(retval)[i] = &addr->base;
 		}
 	}
-
-	for (alength = 0; ent->h_addr_list[alength]; alength++)
-		;
-
-	array = (HArrayOfInt*)AllocArray(alength, TYPE_Int);
-	assert(array != 0);
-
-	for (i = 0; i < alength; i++) {
-		/* Copy in the network address */
-		unhand_array(array)->body[i] = ntohl(*(jint*)ent->h_addr_list[i]);
+	else
+	{
+		const char *msg;
+		
+		if( ent == (void *)-1 )
+		{
+			msg = SYS_ERROR(rc);
+		}
+		else
+		{
+			msg = SYS_HERROR(rc);
+		}
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "%s: %s",
+				     msg,
+				     name);
+	}
+	
+ done:
+	if( !retval )
+	{
+		throwError(&einfo);
 	}
 
-	return (array);
+	return( retval );
+#endif
 }
 
 /*
  * Convert a network order address into the hostname.
  */
 struct Hjava_lang_String*
-java_net_InetAddressImpl_getHostByAddr(struct Hjava_net_InetAddressImpl* none, jint addr)
+java_net_NativeInetAddressImpl_getHostByAddr0(struct Hjava_net_NativeInetAddressImpl* none, HArrayOfByte *addr)
 {
+#if defined(HAVE_GETADDRINFO)
+	struct Hjava_lang_String *retval = 0;
+#if defined(AF_INET6)
+	struct sockaddr_in6 sa_buf;
+	struct sockaddr_in6 *sin6 = &sa_buf;
+#else
+	struct sockaddr_in sa_buf;
+#endif
+	struct sockaddr_in *sin = (struct sockaddr_in *)&sa_buf;
+	int rc, retryCount = 5;
+	int iLockRoot;
+	errorInfo einfo;
+	char *hostname;
+
+	hostname = gc_malloc(NI_MAXHOST, GC_ALLOC_FIXED);
+	switch( addr->length )
+	{
+	case 4:
+		sin->sin_len = sizeof(struct sockaddr_in);
+		sin->sin_family = AF_INET;
+		sin->sin_port = 0;
+		memcpy(&sin->sin_addr, unhand_byte_array(addr), addr->length);
+		break;
+#if defined(AF_INET6)
+	case 16:
+		sin6->sin6_len = sizeof(struct sockaddr_in6);
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = 0;
+		sin6->sin6_flowinfo = 0;
+		memcpy(&sin6->sin6_addr,
+		       unhand_byte_array(addr),
+		       addr->length);
+		sin6->sin6_scope_id = 0;
+		break;
+#endif
+	default:
+		postExceptionMessage(&einfo,
+				     JAVA_LANG(InternalError),
+				     "Illegal address length: %d",
+				     addr->length);
+		goto done;
+	}
+	lockStaticMutex(&nsLock);
+	while( ((rc = getnameinfo((const struct sockaddr *)&sa_buf,
+				  sin->sin_len,
+				  hostname,
+				  NI_MAXHOST,
+				  NULL,
+				  0,
+				  NI_NAMEREQD)) == EAI_AGAIN) &&
+	       (retryCount > 0) )
+	{
+		unlockStaticMutex(&nsLock);
+		jthread_sleep(1 * 1000);
+		lockStaticMutex(&nsLock);
+		retryCount -= 1;
+	}
+	unlockStaticMutex(&nsLock);
+	switch( rc )
+	{
+	case 0:
+		if( (retval = stringC2Java(hostname)) == 0 )
+		{
+			postOutOfMemory(&einfo);
+		}
+		break;
+	case EAI_FAIL:
+	case EAI_AGAIN:
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "Unable to contact name server");
+		break;
+	case EAI_MEMORY:
+		postOutOfMemory(&einfo);
+		break;
+	case EAI_NONAME:
+		inet_ntop(sin->sin_family,
+			  unhand_byte_array(addr),
+			  hostname,
+			  NI_MAXHOST);
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "Unknown host: %s",
+				     hostname);
+		break;
+	case EAI_SYSTEM:
+		inet_ntop(sin->sin_family,
+			  unhand_byte_array(addr),
+			  hostname,
+			  NI_MAXHOST);
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "%s: %s",
+				     SYS_ERROR(errno),
+				     hostname);
+		break;
+	default:
+		inet_ntop(sin->sin_family,
+			  unhand_byte_array(addr),
+			  hostname,
+			  NI_MAXHOST);
+		postExceptionMessage(&einfo,
+				     JAVA_LANG(InternalError),
+				     "Unhandled getnameinfo error: %s: %s",
+				     gai_strerror(rc),
+				     hostname);
+		break;
+	}
+	gc_free(hostname);
+ done:
+	if( !retval )
+	{
+		throwError(&einfo);
+	}
+	
+	return( retval );
+#else
+	struct Hjava_lang_String *retval = 0;
+	char ipaddr[MAX_IPV6_STRING_SIZE];
 	struct hostent* ent;
-	int rc;
-
-	addr = htonl(addr);
-	rc = KGETHOSTBYADDR((char*)&addr, sizeof(jint), AF_INET, &ent);
-	if (rc) {
-		char ipaddr[16];
-		sprintf(ipaddr, "%3d.%3d.%3d.%3d",
-			/* XXX Make sure it is the right endiannes */
-			(addr >> 24) & 0xff,
-			(addr >> 16) & 0xff,
-			(addr >>  8) & 0xff,
-			(addr)       & 0xff);
-		SignalErrorf("java.net.UnknownHostException", "%s: %s",
-			SYS_HERROR(rc), ipaddr);
+	int family, rc = 0;
+	const char *msg;
+	errorInfo einfo;
+	int iLockRoot;
+	
+	switch( obj_length(addr) )
+	{
+	case 4:
+		family = AF_INET;
+		break;
+#if defined(AF_INET6)
+	case 16:
+		family = AF_INET6;
+		break;
+#endif
+	default:
+		postExceptionMessage(&einfo,
+				     JAVA_LANG(InternalError),
+				     "Illegal address length: %d",
+				     obj_length(addr));
+		goto done;
 	}
-
-	return (checkPtr(stringC2Java((char*)ent->h_name)));
-}
-
-/*
- * Return the inet address family.
- */
-jint
-java_net_InetAddressImpl_getInetFamily(struct Hjava_net_InetAddressImpl* none)
-{
-	return (AF_INET);
+	lockStaticMutex(&nsLock);
+	rc = KGETHOSTBYADDR(unhand_byte_array(addr),
+			    obj_length(addr),
+			    family,
+			    &ent);
+	switch( rc )
+	{
+	case 0:
+		retval = stringC2Java((char *)ent->h_name);
+		break;
+	default:
+		if( ent == (void *)-1 )
+		{
+			msg = SYS_ERROR(rc);
+		}
+		else
+		{
+			msg = SYS_HERROR(rc);
+		}
+		postExceptionMessage(&einfo,
+				     JAVA_NET(UnknownHostException),
+				     "%s: %s",
+				     msg,
+				     inet_ntop(family,
+					       unhand_byte_array(addr),
+					       ipaddr,
+					       sizeof(ipaddr)));
+		break;
+	}
+ done:
+	unlockStaticMutex(&nsLock);
+	if( !retval )
+	{
+		throwError(&einfo);
+	}
+	
+	return( checkPtr(retval) );
+#endif
 }
Index: libraries/clib/net/Makefile.am
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/clib/net/Makefile.am,v
retrieving revision 1.8
diff -u -r1.8 Makefile.am
--- libraries/clib/net/Makefile.am	21 Feb 2003 09:51:09 -0000	1.8
+++ libraries/clib/net/Makefile.am	15 Apr 2003 19:29:00 -0000
@@ -14,7 +14,7 @@
 libnet_la_LIBADD = $(NET_LIBS)  $(top_builddir)/replace/libreplace.la
 libnet_la_SOURCES = \
 	InetAddressImpl.c \
-	NetworkInterface.c \
+	NetworkInterfaceImpl.c \
 	PlainDatagramSocketImpl.c \
 	PlainSocketImpl.c
 
Index: libraries/javalib/Makefile.am
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/Makefile.am,v
retrieving revision 1.98
diff -u -r1.98 Makefile.am
--- libraries/javalib/Makefile.am	26 Feb 2003 21:44:34 -0000	1.98
+++ libraries/javalib/Makefile.am	15 Apr 2003 19:29:01 -0000
@@ -26,6 +26,12 @@
 jrelib_DATA = rt.jar
 toolslib_DATA = kjc.jar
 
+if HAVE_DNSJAVA
+DNSJAVA_InetAddressImpl = java/net/DNSJavaInetAddressImpl.java
+else
+DNSJAVA_InetAddressImpl =
+endif
+
 Klasses_jar_SRCS = \
 	$(gnu_java_lang_SRCS) \
 	$(gnu_java_util_SRCS) \
@@ -834,16 +840,21 @@
 	java/net/DatagramSocket.java \
 	java/net/DatagramSocketImpl.java \
 	java/net/DatagramSocketImplFactory.java \
+	$(DNSJAVA_InetAddressImpl) \
 	java/net/FileNameMap.java \
 	java/net/HttpURLConnection.java \
 	java/net/InetAddress.java \
+	java/net/Inet4Address.java \
+	java/net/Inet6Address.java \
 	java/net/InetAddressImpl.java \
 	java/net/InetSocketAddress.java \
 	java/net/JarURLConnection.java \
 	java/net/MalformedURLException.java \
 	java/net/MulticastSocket.java \
+	java/net/NativeInetAddressImpl.java \
 	java/net/NetPermission.java \
 	java/net/NetworkInterface.java \
+	java/net/NetworkInterfaceImpl.java \
 	java/net/NoRouteToHostException.java \
 	java/net/PasswordAuthentication.java \
 	java/net/PlainDatagramSocketImpl.java \
@@ -2261,6 +2272,7 @@
 	mkdir $(LIBDIR)
 	$(SHELL) $(rebuildLib) @essential.files
 	$(SHELL) $(rebuildLib) @@java_math_files@
+	$(SHELL) $(rebuildLib) $(DNSJAVA_InetAddressImpl)
 	for i in `cat $(srcdir)/profiles/$(PROFILE)/profile` ;  do $(SHELL) $(rebuildLib) @profiles/$(PROFILE)/$$i ; done
 	echo timestamp > $(LIBDIR)/stamp
 
Index: libraries/javalib/bootstrap.classlist
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/bootstrap.classlist,v
retrieving revision 1.11
diff -u -r1.11 bootstrap.classlist
--- libraries/javalib/bootstrap.classlist	21 Feb 2003 09:51:10 -0000	1.11
+++ libraries/javalib/bootstrap.classlist	15 Apr 2003 19:29:02 -0000
@@ -209,8 +209,10 @@
 java/net/DatagramPacket.class
 java/net/InetAddress.class
 java/net/InetAddressImpl.class
+java/net/NativeInetAddressImpl.class
 java/net/InetSocketAddress.class
 java/net/NetworkInterface.class
+java/net/NetworkInterfaceImpl.class
 java/net/PlainDatagramSocketImpl.class
 java/net/PlainSocketImpl.class
 java/net/SocketAddress.class
Index: libraries/javalib/essential.files
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/essential.files,v
retrieving revision 1.2
diff -u -r1.2 essential.files
--- libraries/javalib/essential.files	20 Feb 2003 13:52:08 -0000	1.2
+++ libraries/javalib/essential.files	15 Apr 2003 19:29:02 -0000
@@ -153,6 +153,7 @@
 java/net/InetAddress.java
 java/net/InetAddressImpl.java
 java/net/MalformedURLException.java
+java/net/NativeInetAddressImpl.java
 java/net/NetPermission.java
 java/net/SocketPermission.java
 java/net/UnknownHostException.java
Index: libraries/javalib/rebuildLib.in
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/rebuildLib.in,v
retrieving revision 1.31
diff -u -r1.31 rebuildLib.in
--- libraries/javalib/rebuildLib.in	3 Feb 2003 11:39:46 -0000	1.31
+++ libraries/javalib/rebuildLib.in	15 Apr 2003 19:29:02 -0000
@@ -9,6 +9,10 @@
 # of this file.
 #
 
+if [ -z "$1" ] ; then
+    exit 0
+fi
+
 SRCDIR=${srcdir-`sed -n '/^srcdir *= */ s///p' < Makefile`}
 LIBDIR=${LIBDIR-`sed -n '/^LIBDIR *= */ s///p' < Makefile`}
 LIBDIR=${LIBDIR-lib}
@@ -34,6 +38,7 @@
 	CPATH="${CPATH+-classpath $LIBRARY${CPATH+@PATHSEP@$CPATH}}"
 	CLASSPATH=./Klasses.jar.bootstrap:$CLASSPATH; export CLASSPATH
 else
+	test -f ${TOPBLD}/BUILD_ENVIRONMENT && . ${TOPBLD}/BUILD_ENVIRONMENT
 	JAVAC="$JIKES"
 	CPATH="${CPATH+-classpath $CPATH}"
 #	VERBOSE=${VERBOSE-"-verbose"}
Index: libraries/javalib/java/lang/IllegalArgumentException.java
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/lang/IllegalArgumentException.java,v
retrieving revision 1.1
diff -u -r1.1 IllegalArgumentException.java
--- libraries/javalib/java/lang/IllegalArgumentException.java	14 Jul 1998 14:20:01 -0000	1.1
+++ libraries/javalib/java/lang/IllegalArgumentException.java	15 Apr 2003 19:29:02 -0000
@@ -20,4 +20,12 @@
 public IllegalArgumentException (String s) {
 	super(s);
 }
+    
+public IllegalArgumentException (Throwable th) {
+	super(th);
+}
+
+public IllegalArgumentException (String s, Throwable th) {
+	super(s, th);
+}
 }
Index: libraries/javalib/java/net/InetAddress.java
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/net/InetAddress.java,v
retrieving revision 1.12
diff -u -r1.12 InetAddress.java
--- libraries/javalib/java/net/InetAddress.java	21 Feb 2003 09:51:10 -0000	1.12
+++ libraries/javalib/java/net/InetAddress.java	15 Apr 2003 19:29:02 -0000
@@ -13,197 +13,488 @@
 import java.io.Serializable;
 import java.util.StringTokenizer;
 
-final public class InetAddress
-  implements Serializable {
+/**
+ * Base class for IP addresses.  Implementation details are handled by the
+ * InetAddressImpl class.
+ */
+public class InetAddress
+    implements Serializable
+{
+    private static final long serialVersionUID = 3286316764910316507L;
+
+    private static final int IPV4_LOOPBACK_BITS = 0x7F000001;
+
+    /**
+     * Our handle on the implementation.
+     */
+    private static final InetAddressImpl impl;
+
+    /**
+     * The list of implementation classes, ordered from most to least
+     * desirable.
+     */
+    static final String INET_ADDRESS_IMPLS[] = {
+	"java.net.DNSJavaInetAddressImpl",
+	"java.net.NativeInetAddressImpl",
+    };
+    
+    static
+    {
+	InetAddressImpl iai = null;
+	int lpc;
+
+	for( lpc = 0;
+	     (lpc < INET_ADDRESS_IMPLS.length) && (iai == null);
+	     lpc++ )
+	{
+	    try
+	    {
+		Class cl;
+
+		cl = Class.forName(INET_ADDRESS_IMPLS[lpc]);
+		iai = (InetAddressImpl)cl.newInstance();
+		System.setProperty("org.kaffe.dns", INET_ADDRESS_IMPLS[lpc]);
+	    }
+	    catch(IllegalAccessException e)
+	    {
+		/* Really should not happen. */
+		throw new InternalError(e);
+	    }
+	    catch(ExceptionInInitializerError e)
+	    {
+	    }
+	    catch(InstantiationException e)
+	    {
+	    }
+	    catch(NoClassDefFoundError e)
+	    {
+	    }
+	    catch(ClassNotFoundException e)
+	    {
+	    }
+	}
+	if( iai == null )
+	{
+	    /* Not sure about this error type. */
+	    throw new UnsatisfiedLinkError(
+		"Cannot find working InetAddressImpl");
+	}
+	impl = iai;
+    }
 
-private static final long serialVersionUID = 3286316764910316507L;
+    /**
+     * Convert an IPv4 address encoded in a byte to an integer.
+     *
+     * @param addr The address to convert.
+     * @return The address from addr or zero if the length of addr was not
+     * four.
+     */
+    private static int fromBytes(byte addr[])
+    {
+	int retval = 0;
 
-private static InetAddressImpl impl;
+	if( addr.length == 4 )
+	{
+	    retval = (((addr[0] & 0xFF) << 24) |
+		      ((addr[1] & 0xFF) << 16) |
+		      ((addr[2] & 0xFF) <<  8) |
+		      ((addr[3] & 0xFF)      ));
+	}
+	return retval;
+    }
 
-private String hostName;
-private int address;
-private int family;
+    /**
+     * Convert an IPv4 address encoded as an integer to a byte array.
+     *
+     * @param address The address to convert.
+     * @return A byte array containing the address value in network order.
+     */
+    private static byte[] toBytes(int address)
+    {
+	byte retval[] = new byte[4];
+
+	retval[0] = (byte)((address >> 24) & 0xFF);
+	retval[1] = (byte)((address >> 16) & 0xFF);
+	retval[2] = (byte)((address >>  8) & 0xFF);
+	retval[3] = (byte) (address        & 0xFF);
+	return retval;
+    }
 
-static {
-	impl = new InetAddressImpl();
-}
+    /**
+     * The host name as specified by the user or derived from a DNS lookup.
+     */
+    transient String hostName;
+
+    /**
+     * The IP address encoded as an array.
+     */
+    transient byte addr[];
+
+    /**
+     * The IPv4 address encoded as an integer.
+     */
+    int address;
+
+    /**
+     * The address family.
+     */
+    private int family;
+
+    /**
+     * The designated InetAddress constructor.
+     *
+     * @param addr The IP address.
+     * @param address The IPv4 address encoded as an integer or zero.
+     * @param name The given host name or null if a lookup should eventually be
+     * done.
+     */
+    InetAddress(byte addr[], int address, String name)
+    {
+	this.family = impl.getInetFamily(this instanceof Inet6Address ?
+					 InetAddressImpl.INET_ADDRESS_V6 :
+					 InetAddressImpl.INET_ADDRESS_V4);
+	this.hostName = name;
+	this.addr = addr;
+	this.address = address;
+    }
 
-private InetAddress(String name, int addr) {
-	family = impl.getInetFamily();
-	hostName = name;
-	address = addr;
-}
+    /**
+     * @param addr The IP address.
+     * @param name The given host name or null if a lookup should eventually be
+     * done.
+     */
+    InetAddress(byte addr[], String name)
+    {
+	this(addr, fromBytes(addr), name);
+    }
 
-InetAddress() {
-	family = impl.getInetFamily();
-}
+    /**
+     * @param address The IPv4 address encoded as an integer.
+     * @param name The given host name or null if a lookup should eventually be
+     * done.
+     */
+    InetAddress(int address, String name)
+    {
+	this(toBytes(address), address, name);
+    }
 
-public boolean equals(Object obj) {
-	try
-	{
-		InetAddress ia;
+    /**
+     * Construct an empty InetAddress.
+     */
+    InetAddress()
+    {
+	this(null, 0, null);
+    }
 
-		ia = (InetAddress)obj;
-		if( (this.family == ia.family) &&
-		    (this.address == ia.address) )
+    public static InetAddress[] getAllByName(String host)
+	throws UnknownHostException,
+	       SecurityException
+    {
+	InetAddress retval[];
+	
+	if( host == null || host.equals("") || host.equals("localhost") )
+	{
+	    retval = new InetAddress[] {
+		new Inet4Address(toBytes(IPV4_LOOPBACK_BITS), "localhost"),
+	    };
+	}
+	else
+	{
+	    SecurityManager sm = System.getSecurityManager();
+	    if( sm != null )
+		sm.checkConnect(host, -1);
+
+	    byte ip[] = InetAddressImpl.stringToBits(host);
+	    byte addrs[][];
+	    int lpc;
+
+	    if( ip == null )
+	    {
+		/* Its a host name. */
+		addrs = impl.lookupAllHostAddr(host);
+	    }
+	    else
+	    {
+		/* Its an IP address. */
+		addrs = new byte[][] { ip };
+	    }
+	    retval = new InetAddress[addrs.length];
+	    /* Convert to the correct InetAddress type. */
+	    for( lpc = 0; lpc < addrs.length; lpc++ )
+	    {
+		switch( addrs[lpc].length )
 		{
-			return true;
+		case 4:
+		    retval[lpc] = new Inet4Address(addrs[lpc],
+						   ip == null ?
+						   host :
+						   null);
+		    break;
+		case 16:
+		    retval[lpc] = new Inet6Address(addrs[lpc],
+						   ip == null ?
+						   host :
+						   null);
+		    break;
+		default:
+		    throw new InternalError("Unhandled address length: "
+					    + addrs[lpc].length);
 		}
+	    }
 	}
-	catch(ClassCastException e)
+	return retval;
+    }
+
+    public static InetAddress getByAddress(byte[] addr)
+	throws UnknownHostException
+    {
+	InetAddress retval;
+	
+	switch( addr.length )
 	{
+	case 4:
+	    retval = new Inet4Address(addr, null);
+	    break;
+	case 16:
+	    retval = new Inet6Address(addr, null);
+	    break;
+
+	default:
+	    throw new UnknownHostException("Bad address length: "
+					   + addr.length
+					   + " bytes");
 	}
-	return false;
-}
 
-public byte[] getAddress() {
-	byte result[] = new byte[4];
+	return retval;
+    }
 
-	result[0] = (byte)((address >> 24) & 0xFF);
-	result[1] = (byte)((address >> 16) & 0xFF);
-	result[2] = (byte)((address >>  8) & 0xFF);
-	result[3] = (byte) (address        & 0xFF);
-
-	return (result);
-}
-
-public static InetAddress[] getAllByName(String host) throws UnknownHostException {
-	if (host == null || host.equals("")) {
-		throw new UnknownHostException(host == null ? "" : host);
-	}
-
-	InetAddress[] addrs;
-	if (Character.isDigit(host.charAt(0))) {
-		addrs = new InetAddress[1];
-		addrs[0] = getByName(host);
-	}
-	else {
-		int data[] = impl.lookupAllHostAddr(host);
-		int nr = data.length;
-		addrs = new InetAddress[nr];
-		for (int i = 0; i < nr; i++) {
-			addrs[i] = new InetAddress(host, data[i]);
-		}
+    public static InetAddress getByName(String host)
+	throws UnknownHostException
+    {
+	InetAddress retval = null, addrs[];
+	int lpc;
+
+	addrs = getAllByName(host);
+	/*
+	 * Alas, the spec does not specify _which_ address to return.  So, for
+	 * the sake of backwards compatibility, we'll prefer the first IPv4
+	 * address.
+	 */
+	for( lpc = 0; (lpc < addrs.length) && (retval == null); lpc++ )
+	{
+	    if( addrs[lpc] instanceof Inet4Address )
+	    {
+		retval = addrs[lpc];
+	    }
 	}
-	return (addrs);
-}
+	if( (retval == null) && (addrs.length > 0) )
+	{
+	    /* No IPv4 addresses, use the first IPv6. */
+	    retval = addrs[0];
+	}
+	return retval;
+    }
 
-public static InetAddress getByAddress(byte[] addr) throws UnknownHostException {
-    if (addr.length != 4 && addr.length != 16) {
-	throw new UnknownHostException("bad address length: " + addr.length + " bytes");
-    }
-
-    if (addr.length == 16) {
-	throw new kaffe.util.NotImplemented("Inet6 addresses are not supported.");
-    }
-
-    int address = ((addr[0] & 0xFF) << 24)
-	+ ((addr[1] & 0xFF) << 16)
-	+ ((addr[2] & 0xFF) << 8)
-	+ (addr[3]);
-
-    return new InetAddress(null, address);
-}
-
-public static synchronized InetAddress getByName(String host) throws UnknownHostException {
-	if (host == null || host.equals("")) {
-		return (InetAddress.getLoopback());
-	}
-	int ip;
-	if (!Character.isDigit(host.charAt(0))) {
-		ip = impl.lookupHostAddr(host);
-	}
-	else {
-		ip = 0;
-		StringTokenizer tok = new StringTokenizer(host, ".");
-		while (tok.hasMoreElements()) {
-			String s = tok.nextToken();
-			ip <<= 8;
-			try {
-				ip |= Integer.parseInt(s);
-			}
-			catch (NumberFormatException _) {
-			}
-		}
-		host = null;
+    public static InetAddress getLocalHost()
+	throws UnknownHostException
+    {
+	try
+	{
+	    String name = impl.getLocalHostName();
+	    SecurityManager sm = System.getSecurityManager();
+	    if (sm != null)
+		sm.checkConnect(name, 0);
+	    return InetAddress.getByName(name);
 	}
-	return (new InetAddress(host, ip));
-}
+	catch(SecurityException se)
+	{
+	    return InetAddress.getLoopback();
+	}
+    }
 
-public String getHostAddress() {
-	byte b[] = getAddress();
-	StringBuffer buf = new StringBuffer();
-	buf.append(Integer.toString(b[0] & 0xFF));
-	buf.append(".");
-	buf.append(Integer.toString(b[1] & 0xFF));
-	buf.append(".");
-	buf.append(Integer.toString(b[2] & 0xFF));
-	buf.append(".");
-	buf.append(Integer.toString(b[3] & 0xFF));
-	return (buf.toString());
-}
-
-public String getHostName() {
-	try {
-		if (hostName == null) {
-			hostName = impl.getHostByAddr(address);
-		}
+    public String getHostAddress()
+    {
+	return null;
+    }
+
+    public String getCanonicalHostName()
+    {
+	String retval;
+
+	try
+	{
+	    SecurityManager sm = System.getSecurityManager();
+	    if( sm != null )
+		sm.checkConnect(this.hostName, -1);
+	    
+	    /*
+	     * Since this.hostName can be a local reference (e.g.'foo') we need
+	     * to do a full lookup to get 'foo.bar.com'.
+	     */
+	    retval = impl.getHostByAddr(this.addr);
+
+	    /* XXX Should we call checkConnect on retval? */
+	}
+	catch(UnknownHostException _)
+	{
+	    retval = this.getHostAddress();
 	}
-	catch (UnknownHostException _) {
-		hostName = getHostAddress();
+	catch(SecurityException _)
+	{
+	    retval = this.getHostAddress();
 	}
-	return (hostName);
-}
+	return retval;
+    }
 
-public static InetAddress getLocalHost() throws UnknownHostException {
-	try {
-		String name = impl.getLocalHostName();
+    public String getHostName()
+    {
+	String retval;
+	
+	try
+	{
+	    if( this.hostName == null )
+	    {
+		/* Lookup not done yet... */
+		this.hostName = impl.getHostByAddr(this.addr);
+	    }
+	    retval = this.hostName;
+
+	    try
+	    {
+		/* Make sure its visible to them. */
 		SecurityManager sm = System.getSecurityManager();
-		if (sm != null)
-			sm.checkConnect(name, 0);
-		return (getByName(name));
+		if( sm != null )
+		    sm.checkConnect(this.hostName, -1);
+	    }
+	    catch(SecurityException e)
+	    {
+		retval = this.getHostAddress();
+	    }
 	}
-	catch (SecurityException se) {
-		return (InetAddress.getLoopback());
+	catch(UnknownHostException _)
+	{
+	    /* No joy on the lookup. */
+	    retval = this.hostName = this.getHostAddress();
 	}
-}
+	return retval;
+    }
 
-public int hashCode() {
-	return (address);
-}
+    public boolean isMulticastAddress()
+    {
+	return false;
+    }
 
-public boolean isMulticastAddress() {
-	if ((address & 0xE0000000) == 0xE0000000) {
-		return (true);
+    public boolean isAnyLocalAddress()
+    {
+	return false;
+    }
+
+    public boolean isLoopbackAddress()
+    {
+	return false;
+    }
+
+    public boolean isLinkLocalAddress()
+    {
+	return false;
+    }
+
+    public boolean isSiteLocalAddress()
+    {
+	return false;
+    }
+
+    public boolean isMCGlobal()
+    {
+	return false;
+    }
+
+    public boolean isMCNodeLocal()
+    {
+	return false;
+	
+    }
+
+    public boolean isMCLinkLocal()
+    {
+	return false;
+    }
+
+    public boolean isMCSiteLocal()
+    {
+	return false;
+    }
+
+    public boolean isMCOrgLocal()
+    {
+	return false;
+    }
+
+    public byte[] getAddress()
+    {
+	return null;
+    }
+
+    public int hashCode()
+    {
+	return 0;
+    }
+
+    public boolean equals(Object obj)
+    {
+	try
+	{
+	    InetAddress ia;
+
+	    ia = (InetAddress)obj;
+	    if( (this.family == ia.family) &&
+		(this.address == ia.address) )
+	    {
+		return true;
+	    }
 	}
-	else {
-		return (false);
+	catch(ClassCastException e)
+	{
 	}
-}
-
-public boolean isAnyLocalAddress() {
-	return this.address == 0;
-}
+	return false;
+    }
 
-public String toString() {
+    public String toString()
+    {
 	StringBuffer result = new StringBuffer();
 
-	result.append(getHostName());
+	if( this.hostName == null )
+	{
+	    result.append("");
+	}
+	else
+	{
+	    result.append(this.hostName);
+	}
 	result.append("/");
 	result.append(getHostAddress());
 
-	return (result.toString());
-}
+	return result.toString();
+    }
 
-static InetAddress getLoopback() {
-	return (new InetAddress("loopback", 0x7F000001));
-}
-
-static InetAddress getAnyAddress() {
-	InetAddress a = new InetAddress();
-	impl.makeAnyLocalAddress(a);
-	return (a);
-}
+    static InetAddress getLoopback()
+    {
+	return new InetAddress(IPV4_LOOPBACK_BITS, "localhost");
+    }
 
+    /** JanosVM extension for JSR-121 prototype */
+    /*package*/ InetAddress dup()
+    {
+	InetAddress retval = new InetAddress();
+	
+	retval.hostName = this.hostName == null ? null : new String(this.hostName.toCharArray());
+	retval.address = this.address;
+	retval.family = this.family;
+	return retval;
+    }
 
+    static InetAddress getAnyAddress()
+    {
+	return new InetAddress(new byte[] { 0, 0, 0, 0 }, null);
+    }
 }
Index: libraries/javalib/java/net/InetAddressImpl.java
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/net/InetAddressImpl.java,v
retrieving revision 1.5
diff -u -r1.5 InetAddressImpl.java
--- libraries/javalib/java/net/InetAddressImpl.java	22 Nov 2001 06:21:14 -0000	1.5
+++ libraries/javalib/java/net/InetAddressImpl.java	15 Apr 2003 19:29:02 -0000
@@ -10,18 +10,71 @@
 
 package java.net;
 
+/**
+ * Base class for DNS implementations.
+ */
+abstract class InetAddressImpl
+{
+    public static final int INET_ADDRESS_MIN = 0;
 
-class InetAddressImpl {
+    /**
+     * IPv4 address family.
+     */
+    public static final int INET_ADDRESS_V4 = 1;
 
-static {
+    /**
+     * IPv6 address family.
+     */
+    public static final int INET_ADDRESS_V6 = 2;
+    
+    public static final int INET_ADDRESS_MAX = 3;
+
+    static
+    {
 	System.loadLibrary("net");
-}
+    }
+
+    /**
+     * Map an INET_ADDRESS_V* value to the address family value.
+     *
+     * @param kind One of the INET_ADDRESS_V* constants.
+     * @return The integer representing the address family used by the OS.
+     */
+    static native int getInetFamily(int kind);
+
+    /**
+     * @return The machine's host name.
+     */
+    static native String getLocalHostName();
+
+    /**
+     * Convert an address string to the appropriate address bits.
+     *
+     * @param addr The address string to convert.
+     * @return Null if the string was not in a known format, a four byte array
+     * if it was an IPv4 address, and a sixteen byte array if it was an IPv6
+     * address.
+     */
+    static native byte[] stringToBits(String addr);
 
-native public int getInetFamily();
-native public int[] lookupAllHostAddr(String host) throws UnknownHostException;
-native public int lookupHostAddr(String host) throws UnknownHostException;
-native public String getHostByAddr(int addr) throws UnknownHostException;
-native public String getLocalHostName();
-native public void makeAnyLocalAddress(InetAddress addr);
+    /**
+     * Call back used to map a host name to its addresses.
+     *
+     * @param host The host name to query the DNS server about.
+     * @return An array of byte arrays containing the IP addresses.  Sub-arrays
+     * of length four are IPv4 addresses and length sixteen are IPv6.
+     * @throws UnknownHostException if the DNS lookup failed.
+     */
+    abstract byte[][] lookupAllHostAddr(String host)
+	throws UnknownHostException;
 
+    /**
+     * Call back used to perform a reverse lookup.
+     *
+     * @param addr The IP address to map to a host name.
+     * @return The host name.
+     * @throws UnknownHostException if the DNS lookup failed.
+     */
+    abstract String getHostByAddr(byte addr[])
+	throws UnknownHostException;
 }
Index: libraries/javalib/java/net/NetworkInterface.java
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/net/NetworkInterface.java,v
retrieving revision 1.1
diff -u -r1.1 NetworkInterface.java
--- libraries/javalib/java/net/NetworkInterface.java	21 Feb 2003 09:51:10 -0000	1.1
+++ libraries/javalib/java/net/NetworkInterface.java	15 Apr 2003 19:29:02 -0000
@@ -20,183 +20,76 @@
 
 public final class NetworkInterface
 {
-    /*
-     * This implementation specific stuff should probably be moved elsewhere.
-     * Also, the implementation will not detect changes in the interfaces.
-     * It does the detection at class initialization and saves these objects
-     * in a global variable.
-     */
-
-    /**
-     * The detected interfaces, the table maps names to NetworkInterface
-     * objects.
-     */
-    private static final Hashtable DETECTED_INTERFACES = new Hashtable();
-
     /**
-     * Secondary mapping from InetAddresses to interface names.
+     * XXX Currently, we just create a new NetworkInterfaceImpl for each
+     * request.  It would be nicer to either timeout the cache or check for
+     * diffs before throwing the objects away.
      */
-    private static final Hashtable ADDRESS_TO_NAME = new Hashtable();
-
-    /**
-     * If not null, the SocketException thrown on initialization.
-     */
-    private static SocketException detectException;
-
-    /**
-     * Detect the interfaces in this machine.
-     *
-     * @return The native list of interfaces.
-     * @throws SocketException if there is a problem with the native code.
-     */
-    private static native kaffe.util.Ptr detectInterfaces()
-	throws SocketException;
-
-    /**
-     * Free the native objects returned by detectInterfaces.
-     *
-     * @param ifaddrs The pointer returned by detectInterfaces or null.
-     */
-    private static native void freeInterfaces(kaffe.util.Ptr ifaddrs);
-
-    /**
-     * Get the next interface in the native list.
-     *
-     * @param ifaddr The current interface.
-     * @return The next interface in the list or null if there are no more.
-     */
-    private static native kaffe.util.Ptr getNext(kaffe.util.Ptr ifaddr);
-
-    /**
-     * @param ifaddr The current interface.
-     * @return The name encoded in the native object.
-     */
-    private static native String getName(kaffe.util.Ptr ifaddr);
-    
-    /**
-     * @param ifaddr The current interface.
-     * @return The IPv4 address of this interface as a string or null if the
-     * native object doesn't have an IPv4 address.
-     */
-    private static native String getIPv4Address(kaffe.util.Ptr ifaddr);
-    
-    static
-    {
-	kaffe.util.Ptr ifaddrs = null, curr = null;
-
-	/* Our native implementation is in kaffenet */
-	System.loadLibrary("net");
-
-	try
-	{
-	    /* Detect all the network interfaces. */
-	    curr = ifaddrs = detectInterfaces();
-	    while( curr != null )
-	    {
-		NetworkInterface ni;
-		String name;
-		
-		name = getName(curr);
-		if( (ni = (NetworkInterface)DETECTED_INTERFACES.get(name))
-		    == null )
-		{
-		    ni = new NetworkInterface(name, name /* XXX */);
-		    DETECTED_INTERFACES.put(name, ni);
-		}
-		try
-		{
-		    String address;
-
-		    if( (address = getIPv4Address(curr)) != null )
-		    {
-			InetAddress ia;
-
-			ia = InetAddress.getByName(address);
-			ni.setPrimaryAddress(ia);
-			ADDRESS_TO_NAME.put(ia, ni.getName());
-			ni.getInetAddressesInternal().addElement(ia);
-		    }
-		}
-		catch(UnknownHostException e)
-		{
-		    /* Ignore... */
-		}
-		curr = getNext(curr);
-	    }
-	    DETECTED_INTERFACES.elements();
-	}
-	catch(SocketException e)
-	{
-	    detectException = e;
-	}
-	finally
-	{
-	    /* Make sure to free the native objects. */
-	    freeInterfaces(ifaddrs);
-	}
-    }
     
     public static NetworkInterface getByName(String name)
 	throws SocketException
     {
-	if( detectException == null )
-	{
-	    NetworkInterface retval = null;
-	    
-	    retval = (NetworkInterface)DETECTED_INTERFACES.get(name);
-	    return retval;
-	}
-	else
-	{
-	    throw detectException;
-	}
+	NetworkInterfaceImpl nii = new NetworkInterfaceImpl();
+	NetworkInterface retval;
+	
+	retval = (NetworkInterface)nii.getDetectedInterfaces().get(name);
+	return retval;
     }
 
     public static NetworkInterface getByInetAddress(InetAddress ia)
 	throws SocketException
     {
-	if( detectException == null )
+	NetworkInterfaceImpl nii = new NetworkInterfaceImpl();
+	NetworkInterface retval = null;
+	String name;
+	
+	if( (name = nii.nameForAddress(ia)) != null )
 	{
-	    NetworkInterface retval = null;
-	    String name;
-	    
-	    if( (name = (String)ADDRESS_TO_NAME.get(ia)) != null )
-	    {
-		retval = (NetworkInterface)DETECTED_INTERFACES.get(name);
-	    }
-	    return retval;
-	}
-	else
-	{
-	    throw detectException;
+	    retval = (NetworkInterface)nii.getDetectedInterfaces().get(name);
 	}
+	return retval;
     }
 
     public static Enumeration getNetworkInterfaces()
 	throws SocketException
     {
-	if( detectException == null )
-	{
-	    Enumeration retval = null;
+	NetworkInterfaceImpl nii = new NetworkInterfaceImpl();
+	Enumeration retval = null;
 
-	    if( DETECTED_INTERFACES.size() > 0 )
-	    {
-		retval = DETECTED_INTERFACES.elements();
-	    }
-	    return retval;
-	}
-	else
+	if( nii.getDetectedInterfaces().size() > 0 )
 	{
-	    throw detectException;
+	    retval = nii.getDetectedInterfaces().elements();
 	}
+	return retval;
     }
-    
+
+    /**
+     * The OS provided NIC name.
+     */
     private final String name;
+
+    /**
+     * Same as the above for now.
+     */
     private final String displayName;
+
+    /**
+     * An IPv4 address suitable for identifying this interface.
+     */
     private InetAddress primaryAddress;
+
+    /**
+     * The set of InetAddresses for this interface.
+     */
     private final Vector inetAddresses = new Vector();
-    
-    private NetworkInterface(String name, String displayName)
+
+    /**
+     * Construct a NetworkInterface with the given values.
+     *
+     * @param name The OS provided NIC name.
+     * @param displayName The user-interpretable NIC name.
+     */
+    NetworkInterface(String name, String displayName)
     {
 	this.name = name;
 	this.displayName = displayName;
@@ -225,6 +118,9 @@
 	return this.primaryAddress;
     }
 
+    /**
+     * @return The Vector containing the NetworkInterface's addresses.
+     */
     Vector getInetAddressesInternal()
     {
 	return this.inetAddresses;
Index: libraries/javalib/java/net/UnknownHostException.java
===================================================================
RCS file: /cvs/kaffe/kaffe/libraries/javalib/java/net/UnknownHostException.java,v
retrieving revision 1.3
diff -u -r1.3 UnknownHostException.java
--- libraries/javalib/java/net/UnknownHostException.java	22 Nov 2001 06:21:14 -0000	1.3
+++ libraries/javalib/java/net/UnknownHostException.java	15 Apr 2003 19:29:02 -0000
@@ -20,4 +20,12 @@
 public UnknownHostException (String s) {
 	super(s);
 }
+
+public UnknownHostException (Throwable cause) {
+	super(cause);
+}
+
+public UnknownHostException (String s, Throwable cause) {
+	super(s, cause);
+}
 }
Index: test/regression/Makefile.am
===================================================================
RCS file: /cvs/kaffe/kaffe/test/regression/Makefile.am,v
retrieving revision 1.71
diff -u -r1.71 Makefile.am
--- test/regression/Makefile.am	13 Mar 2003 23:21:07 -0000	1.71
+++ test/regression/Makefile.am	15 Apr 2003 19:29:03 -0000
@@ -138,6 +138,7 @@
 	GetField.java \
 	LostTrampolineFrame.java \
         NetworkInterfaceTest.java \
+        InetAddressTest.java \
         InetSocketAddressTest.java 
 
 TEST_REFLECTION = \

--%--multipart-mixed-boundary-1.21652.1050436020--%--