Source for java.net.InetAddress

   1: /* InetAddress.java -- Class to model an Internet address
   2:    Copyright (C) 1998, 1999, 2002, 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package java.net;
  40: 
  41: import gnu.classpath.Configuration;
  42: 
  43: import java.io.IOException;
  44: import java.io.ObjectInputStream;
  45: import java.io.ObjectOutputStream;
  46: import java.io.ObjectStreamException;
  47: import java.io.Serializable;
  48: 
  49: /**
  50:  * This class models an Internet address.  It does not have a public
  51:  * constructor.  Instead, new instances of this objects are created
  52:  * using the static methods getLocalHost(), getByName(), and
  53:  * getAllByName().
  54:  *
  55:  * <p>This class fulfills the function of the C style functions gethostname(),
  56:  * gethostbyname(), and gethostbyaddr().  It resolves Internet DNS names
  57:  * into their corresponding numeric addresses and vice versa.</p>
  58:  *
  59:  * @author Aaron M. Renn (arenn@urbanophile.com)
  60:  * @author Per Bothner
  61:  *
  62:  * @specnote This class is not final since JK 1.4
  63:  */
  64: public class InetAddress implements Serializable
  65: {
  66:   private static final long serialVersionUID = 3286316764910316507L;
  67: 
  68:   /**
  69:    * Dummy InetAddress, used to bind socket to any (all) network interfaces.
  70:    */
  71:   static InetAddress ANY_IF;
  72:     
  73:   private static final byte[] loopbackAddress = { 127, 0, 0, 1 };
  74: 
  75:   private static final InetAddress loopback 
  76:     = new Inet4Address(loopbackAddress, "localhost");
  77: 
  78:   private static InetAddress localhost = null;
  79: 
  80:   static
  81:   {
  82:     // load the shared library needed for name resolution
  83:     if (Configuration.INIT_LOAD_LIBRARY)
  84:       System.loadLibrary("javanet");
  85:     
  86:     byte[] zeros = { 0, 0, 0, 0 };
  87:     ANY_IF = new Inet4Address(zeros, "0.0.0.0");
  88:   }
  89: 
  90:   /**
  91:    * The Serialized Form specifies that an int 'address' is saved/restored.
  92:    * This class uses a byte array internally so we'll just do the conversion
  93:    * at serialization time and leave the rest of the algorithm as is.
  94:    */
  95:   private int address;
  96: 
  97:   /**
  98:    * An array of octets representing an IP address.
  99:    */
 100:   transient byte[] addr;
 101: 
 102:   /**
 103:    * The name of the host for this address.
 104:    */
 105:   String hostName;
 106: 
 107:   /**
 108:    * The field 'family' seems to be the AF_ value.
 109:    * FIXME: Much of the code in the other java.net classes does not make
 110:    * use of this family field.  A better implementation would be to make
 111:    * use of getaddrinfo() and have other methods just check the family
 112:    * field rather than examining the length of the address each time.
 113:    */
 114:   int family;
 115: 
 116:   /**
 117:    * Initializes this object's addr instance variable from the passed in
 118:    * byte array.  Note that this constructor is protected and is called
 119:    * only by static methods in this class.
 120:    *
 121:    * @param ipaddr The IP number of this address as an array of bytes
 122:    * @param hostname The hostname of this IP address.
 123:    */
 124:   InetAddress(byte[] ipaddr, String hostname)
 125:   {
 126:     addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone();
 127:     hostName = hostname;
 128:     
 129:     if (ipaddr != null)
 130:       family = getFamily(ipaddr);
 131:   }
 132: 
 133:   /**
 134:    * Returns true if this address is a multicast address, false otherwise.
 135:    * An address is multicast if the high four bits are "1110".  These are
 136:    * also known as "Class D" addresses.
 137:    *
 138:    * @return true if mulitcast, false if not
 139:    *
 140:    * @since 1.1
 141:    */
 142:   public boolean isMulticastAddress()
 143:   {
 144:     // Mask against high order bits of 1110
 145:     if (addr.length == 4)
 146:       return (addr[0] & 0xf0) == 0xe0;
 147: 
 148:     // Mask against high order bits of 11111111
 149:     if (addr.length == 16)
 150:       return addr [0] == (byte) 0xFF;
 151:     
 152:     return false;
 153:   }
 154: 
 155:   /**
 156:    * Utility routine to check if the InetAddress in a wildcard address
 157:    *
 158:    * @since 1.4
 159:    */
 160:   public boolean isAnyLocalAddress()
 161:   {
 162:     // This is the IPv4 implementation.
 163:     // Any class derived from InetAddress should override this.
 164:     return equals(ANY_IF);
 165:   }
 166: 
 167:   /**
 168:    * Utility routine to check if the InetAddress is a loopback address
 169:    *
 170:    * @since 1.4
 171:    */
 172:   public boolean isLoopbackAddress()
 173:   {
 174:     // This is the IPv4 implementation.
 175:     // Any class derived from InetAddress should override this.
 176:     return (addr[0] & 0xff) == 0x7f;
 177:   }
 178: 
 179:   /**
 180:    * Utility routine to check if InetAddress is a link local address
 181:    *
 182:    * @since 1.4
 183:    */
 184:   public boolean isLinkLocalAddress()
 185:   {
 186:     // This is the IPv4 implementation.
 187:     // Any class derived from InetAddress should override this.
 188:     // XXX: This seems to not exist with IPv4 addresses
 189:     return false;
 190:   }
 191: 
 192:   /**
 193:    * Utility routine to check if InetAddress is a site local address
 194:    *
 195:    * @since 1.4
 196:    */
 197:   public boolean isSiteLocalAddress()
 198:   {
 199:     // This is the IPv4 implementation.
 200:     // Any class derived from InetAddress should override this.
 201: 
 202:     // 10.0.0.0/8
 203:     if ((addr[0] & 0xff) == 0x0a)
 204:       return true;
 205: 
 206:     // 172.16.0.0/12
 207:     if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10)
 208:       return true;
 209: 
 210:     // 192.168.0.0/16
 211:     if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8)
 212:       return true;
 213: 
 214:     // XXX: Do we need to check more addresses here ?
 215:     return false;
 216:   }
 217: 
 218:   /**
 219:    * Utility routine to check if InetAddress is a global multicast address
 220:    *
 221:    * @since 1.4
 222:    */
 223:   public boolean isMCGlobal()
 224:   {
 225:     // This is the IPv4 implementation.
 226:     // Any class derived from InetAddress should override this.
 227:     // XXX: This seems to not exist with IPv4 addresses
 228:     return false;
 229:   }
 230: 
 231:   /**
 232:    * Utility routine to check if InetAddress is a node local multicast address.
 233:    *
 234:    * @since 1.4
 235:    */
 236:   public boolean isMCNodeLocal()
 237:   {
 238:     // This is the IPv4 implementation.
 239:     // Any class derived from InetAddress should override this.
 240:     // XXX: This seems to not exist with IPv4 addresses
 241:     return false;
 242:   }
 243: 
 244:   /**
 245:    * Utility routine to check if InetAddress is a link local multicast address.
 246:    *
 247:    * @since 1.4
 248:    */
 249:   public boolean isMCLinkLocal()
 250:   {
 251:     // This is the IPv4 implementation.
 252:     // Any class derived from InetAddress should override this.
 253:     if (! isMulticastAddress())
 254:       return false;
 255: 
 256:     return ((addr[0] & 0xff) == 0xe0
 257:         && (addr[1] & 0xff)  == 0x00
 258:         && (addr[2] & 0xff)  == 0x00);
 259:   }
 260: 
 261:   /**
 262:    * Utility routine to check if InetAddress is a site local multicast address.
 263:    *
 264:    * @since 1.4
 265:    */
 266:   public boolean isMCSiteLocal()
 267:   {
 268:     // This is the IPv4 implementation.
 269:     // Any class derived from InetAddress should override this.
 270:     // XXX: This seems to not exist with IPv4 addresses
 271:     return false;
 272:   }
 273: 
 274:   /**
 275:    * Utility routine to check if InetAddress is a organization local
 276:    * multicast address.
 277:    *
 278:    * @since 1.4
 279:    */
 280:   public boolean isMCOrgLocal()
 281:   {
 282:     // This is the IPv4 implementation.
 283:     // Any class derived from InetAddress should override this.
 284:     // XXX: This seems to not exist with IPv4 addresses
 285:     return false;
 286:   }
 287: 
 288:   /**
 289:    * Returns the hostname for this address.  This will return the IP address
 290:    * as a String if there is no hostname available for this address
 291:    *
 292:    * @return The hostname for this address
 293:    */
 294:   public String getHostName()
 295:   {
 296:     if (hostName != null)
 297:       return hostName;
 298: 
 299:     // Lookup hostname and set field.
 300:     lookup (null, this, false);
 301:     
 302:     return hostName;
 303:   }
 304: 
 305:   /**
 306:    * Returns the canonical hostname represented by this InetAddress
 307:    * 
 308:    * @since 1.4
 309:    */
 310:   public String getCanonicalHostName()
 311:   {
 312:     SecurityManager sm = System.getSecurityManager();
 313:     if (sm != null)
 314:       {
 315:         try
 316:       {
 317:             sm.checkConnect(hostName, -1);
 318:       }
 319:     catch (SecurityException e)
 320:       {
 321:         return getHostAddress();
 322:       }
 323:       }
 324: 
 325:     // Try to find the FDQN now
 326:     InetAddress address;
 327:     byte[] ipaddr = getAddress();
 328: 
 329:     if (ipaddr.length == 16)
 330:       address = new Inet6Address(getAddress(), null);
 331:     else
 332:       address = new Inet4Address(getAddress(), null);
 333: 
 334:     return address.getHostName();
 335:   }
 336: 
 337:   /**
 338:    * Returns the IP address of this object as a byte array.
 339:    *
 340:    * @return IP address
 341:    */
 342:   public byte[] getAddress()
 343:   {
 344:     // An experiment shows that JDK1.2 returns a different byte array each
 345:     // time.  This makes sense, in terms of security.
 346:     return (byte[]) addr.clone();
 347:   }
 348: 
 349:   /* Helper function due to a CNI limitation.  */
 350:   private static InetAddress[] allocArray (int count)
 351:   {
 352:     return new InetAddress [count];
 353:   }
 354: 
 355:   /* Helper function due to a CNI limitation.  */
 356:   private static SecurityException checkConnect (String hostname)
 357:   {
 358:     SecurityManager s = System.getSecurityManager();
 359:     
 360:     if (s == null)
 361:       return null;
 362:     
 363:     try
 364:       {
 365:     s.checkConnect (hostname, -1);
 366:     return null;
 367:       }
 368:     catch (SecurityException ex)
 369:       {
 370:     return ex;
 371:       }
 372:   }
 373: 
 374:   /**
 375:    * Returns the IP address of this object as a String.  The address is in
 376:    * the dotted octet notation, for example, "127.0.0.1".
 377:    *
 378:    * @return The IP address of this object in String form
 379:    *
 380:    * @since 1.0.2
 381:    */
 382:   public String getHostAddress()
 383:   {
 384:     StringBuffer sb = new StringBuffer(40);
 385: 
 386:     int len = addr.length;
 387:     int i = 0;
 388:     
 389:     if (len == 16)
 390:       { // An IPv6 address.
 391:     for ( ; ; i += 2)
 392:       {
 393:         if (i >= 16)
 394:           return sb.toString();
 395:         
 396:         int x = ((addr [i] & 0xFF) << 8) | (addr [i + 1] & 0xFF);
 397:         boolean empty = sb.length() == 0;
 398:         
 399:         if (empty)
 400:           {
 401:         if (i == 10 && x == 0xFFFF)
 402:           { // IPv4-mapped IPv6 address.
 403:             sb.append (":FFFF:");
 404:             break;  // Continue as IPv4 address;
 405:           }
 406:         else if (i == 12)
 407:           { // IPv4-compatible IPv6 address.
 408:             sb.append (':');
 409:             break;  // Continue as IPv4 address.
 410:           }
 411:         else if (i > 0)
 412:           sb.append ("::");
 413:           }
 414:         else
 415:           sb.append (':');
 416:         
 417:         if (x != 0 || i >= 14)
 418:           sb.append (Integer.toHexString (x).toUpperCase());
 419:       }
 420:       }
 421:     
 422:     for ( ; ; )
 423:       {
 424:         sb.append(addr[i] & 0xff);
 425:         i++;
 426:     
 427:         if (i == len)
 428:           break;
 429:     
 430:         sb.append('.');
 431:       }
 432: 
 433:     return sb.toString();
 434:   }
 435: 
 436:   /**
 437:    * Returns a hash value for this address.  Useful for creating hash
 438:    * tables.  Overrides Object.hashCode()
 439:    *
 440:    * @return A hash value for this address.
 441:    */
 442:   public int hashCode()
 443:   {
 444:     // There hashing algorithm is not specified, but a simple experiment
 445:     // shows that it is equal to the address, as a 32-bit big-endian integer.
 446:     int hash = 0;
 447:     int len = addr.length;
 448:     int i = len > 4 ? len - 4 : 0;
 449: 
 450:     for (; i < len; i++)
 451:       hash = (hash << 8) | (addr[i] & 0xff);
 452: 
 453:     return hash;
 454:   }
 455: 
 456:   /**
 457:    * Tests this address for equality against another InetAddress.  The two
 458:    * addresses are considered equal if they contain the exact same octets.
 459:    * This implementation overrides Object.equals()
 460:    *
 461:    * @param obj The address to test for equality
 462:    *
 463:    * @return true if the passed in object's address is equal to this one's,
 464:    * false otherwise
 465:    */
 466:   public boolean equals(Object obj)
 467:   {
 468:     if (! (obj instanceof InetAddress))
 469:       return false;
 470: 
 471:     // "The Java Class Libraries" 2nd edition says "If a machine has
 472:     // multiple names instances of InetAddress for different name of
 473:     // that same machine are not equal.  This is because they have
 474:     // different host names."  This violates the description in the
 475:     // JDK 1.2 API documentation.  A little experimentation
 476:     // shows that the latter is correct.
 477:     byte[] addr2 = ((InetAddress) obj).addr;
 478: 
 479:     if (addr.length != addr2.length)
 480:       return false;
 481: 
 482:     for (int i = 0; i < addr.length; i++)
 483:       if (addr[i] != addr2[i])
 484:     return false;
 485: 
 486:     return true;
 487:   }
 488: 
 489:   /**
 490:    * Converts this address to a String.  This string contains the IP in
 491:    * dotted decimal form. For example: "127.0.0.1"  This method is equivalent
 492:    * to getHostAddress() and overrides Object.toString()
 493:    *
 494:    * @return This address in String form
 495:    */
 496:   public String toString()
 497:   {
 498:     String addr = getHostAddress();
 499:     String host = (hostName != null) ? hostName : "";
 500:     return host + "/" + addr;
 501:   }
 502: 
 503:   /**
 504:    * Returns an InetAddress object given the raw IP address.
 505:    *
 506:    * The argument is in network byte order: the highest order byte of the
 507:    * address is in getAddress()[0].
 508:    *
 509:    * @param addr The IP address to create the InetAddress object from
 510:    *
 511:    * @exception UnknownHostException If IP address has illegal length
 512:    *
 513:    * @since 1.4
 514:    */
 515:   public static InetAddress getByAddress(byte[] addr)
 516:     throws UnknownHostException
 517:   {
 518:     return getByAddress(null, addr);
 519:   }
 520: 
 521:   /**
 522:    * Creates an InetAddress based on the provided host name and IP address.
 523:    * No name service is checked for the validity of the address.
 524:    *
 525:    * @param host The hostname of the InetAddress object to create
 526:    * @param addr The IP address to create the InetAddress object from
 527:    *
 528:    * @exception UnknownHostException If IP address is of illegal length
 529:    *
 530:    * @since 1.4
 531:    */
 532:   public static InetAddress getByAddress(String host, byte[] addr)
 533:     throws UnknownHostException
 534:   {
 535:     if (addr.length == 4)
 536:       return new Inet4Address(addr, host);
 537: 
 538:     if (addr.length == 16)
 539:       return new Inet6Address(addr, host);
 540: 
 541:     throw new UnknownHostException("IP address has illegal length");
 542:   }
 543: 
 544:   /**
 545:    * If hostname is a valid numeric IP address, return the numeric address.
 546:    * Otherwise, return null.
 547:    *
 548:    * @param hostname the name of the host
 549:    */
 550:   private static native byte[] aton(String hostname);
 551: 
 552:   /**
 553:    * Looks up all addresses of a given host.
 554:    *
 555:    * @param hostname the host to lookup
 556:    * @param ipaddr the IP address to lookup
 557:    * @param all return all known addresses for one host
 558:    *
 559:    * @return an array with all found addresses
 560:    */
 561:   private static native InetAddress[] lookup (String hostname,
 562:                                       InetAddress ipaddr, boolean all);
 563: 
 564:   /**
 565:    * Returns tha family type of an IP address.
 566:    *
 567:    * @param addr the IP address
 568:    *
 569:    * @return the family
 570:    */
 571:   private static native int getFamily (byte[] ipaddr);
 572: 
 573:   /**
 574:    * Returns an InetAddress object representing the IP address of the given
 575:    * hostname.  This name can be either a hostname such as "www.urbanophile.com"
 576:    * or an IP address in dotted decimal format such as "127.0.0.1".  If the
 577:    * hostname is null or "", the hostname of the local machine is supplied by
 578:    * default.  This method is equivalent to returning the first element in
 579:    * the InetAddress array returned from GetAllByName.
 580:    *
 581:    * @param hostname The name of the desired host, or null for the local 
 582:    * loopback address.
 583:    *
 584:    * @return The address of the host as an InetAddress object.
 585:    *
 586:    * @exception UnknownHostException If no IP address for the host could
 587:    * be found
 588:    * @exception SecurityException If a security manager exists and its
 589:    * checkConnect method doesn't allow the operation
 590:    */
 591:   public static InetAddress getByName(String hostname)
 592:     throws UnknownHostException
 593:   {
 594:     // If null or the empty string is supplied, the loopback address
 595:     // is returned. Note that this is permitted without a security check.
 596:     if (hostname == null || hostname.length() == 0)
 597:       return loopback;
 598: 
 599:     SecurityManager s = System.getSecurityManager();
 600:     if (s != null)
 601:       s.checkConnect(hostname, -1);
 602: 
 603:     // Assume that the host string is an IP address
 604:     byte[] address = aton(hostname);
 605:     if (address != null)
 606:       {
 607:         if (address.length == 4)
 608:           return new Inet4Address (address, null);
 609:         else if (address.length == 16)
 610:           {
 611:         if ((address [10] == 0xFF) && (address [11] == 0xFF))
 612:           {
 613:         byte[] ip4addr = new byte [4];
 614:         ip4addr [0] = address [12];
 615:         ip4addr [1] = address [13];
 616:         ip4addr [2] = address [14];
 617:         ip4addr [3] = address [15];
 618:         return new Inet4Address (ip4addr, null);
 619:           }
 620:             return new Inet6Address (address, null);
 621:       }
 622:     else
 623:           throw new UnknownHostException ("Address has invalid length");
 624:       }
 625: 
 626:     // Try to resolve the host by DNS
 627:     InetAddress result = new InetAddress(null, null);
 628:     lookup (hostname, result, false);
 629:     return result;
 630:   }
 631: 
 632:   /**
 633:    * Returns an array of InetAddress objects representing all the host/ip
 634:    * addresses of a given host, given the host's name.  This name can be
 635:    * either a hostname such as "www.urbanophile.com" or an IP address in
 636:    * dotted decimal format such as "127.0.0.1".  If the value is null, the
 637:    * hostname of the local machine is supplied by default.
 638:    *
 639:    * @param hostname The name of the desired host, or null for the
 640:    * local loopback address.
 641:    *
 642:    * @return All addresses of the host as an array of InetAddress objects.
 643:    *
 644:    * @exception UnknownHostException If no IP address for the host could
 645:    * be found
 646:    * @exception SecurityException If a security manager exists and its
 647:    * checkConnect method doesn't allow the operation
 648:    */
 649:   public static InetAddress[] getAllByName(String hostname)
 650:     throws UnknownHostException
 651:   {
 652:     // If null or the empty string is supplied, the loopback address
 653:     // is returned. Note that this is permitted without a security check.
 654:     if (hostname == null || hostname.length() == 0)
 655:       return new InetAddress[] {loopback};
 656: 
 657:     SecurityManager s = System.getSecurityManager();
 658:     if (s != null)
 659:       s.checkConnect(hostname, -1);
 660: 
 661:     // Check if hostname is an IP address
 662:     byte[] address = aton (hostname);
 663:     if (address != null)
 664:       {
 665:     InetAddress[] result = new InetAddress [1];
 666:     result [0] = new InetAddress (address, null);
 667:     return result;
 668:       }
 669: 
 670:     // Try to resolve the hostname by DNS
 671:     return lookup (hostname, null, true);
 672:   }
 673: 
 674:   /**
 675:    * This native method looks up the hostname of the local machine
 676:    * we are on.  If the actual hostname cannot be determined, then the
 677:    * value "localhost" will be used.  This native method wrappers the
 678:    * "gethostname" function.
 679:    *
 680:    * @return The local hostname.
 681:    */
 682:   private static native String getLocalHostname();
 683: 
 684:   /**
 685:    * Returns an InetAddress object representing the address of the current
 686:    * host.
 687:    *
 688:    * @return The local host's address
 689:    *
 690:    * @exception UnknownHostException If no IP address for the host could
 691:    * be found
 692:    */
 693:   public static InetAddress getLocalHost() throws UnknownHostException
 694:   {
 695:     SecurityManager s = System.getSecurityManager();
 696:     
 697:     // Experimentation shows that JDK1.2 does cache the result.
 698:     // However, if there is a security manager, and the cached result
 699:     // is other than "localhost", we need to check again.
 700:     if (localhost == null
 701:     || (s != null && ! localhost.isLoopbackAddress()))
 702:       getLocalHost (s);
 703:     
 704:     return localhost;
 705:   }
 706: 
 707:   private static synchronized void getLocalHost (SecurityManager s)
 708:     throws UnknownHostException
 709:   {
 710:     // Check the localhost cache again, now that we've synchronized.
 711:     if (s == null && localhost != null)
 712:       return;
 713:     
 714:     String hostname = getLocalHostname();
 715:     
 716:     if (s != null)
 717:       {
 718:     // "The Java Class Libraries" suggests that if the security
 719:     // manager disallows getting the local host name, then
 720:     // we use the loopback host.
 721:     // However, the JDK 1.2 API claims to throw SecurityException,
 722:     // which seems to suggest SecurityException is *not* caught.
 723:     // In this case, experimentation shows that former is correct.
 724:     try
 725:       {
 726:         // This is wrong, if the name returned from getLocalHostname()
 727:         // is not a fully qualified name.  FIXME.
 728:         s.checkConnect (hostname, -1);
 729:       }
 730:     catch (SecurityException ex)
 731:       {
 732:         hostname = null;
 733:       }
 734:       }
 735:     
 736:     if (hostname != null && hostname.length() != 0)
 737:       {
 738:     try
 739:       {
 740:         localhost = new InetAddress (null, null);
 741:         lookup (hostname, localhost, false);
 742:       }
 743:     catch (Exception ex)
 744:       {
 745:       }
 746:       }
 747:     else
 748:       throw new UnknownHostException();
 749:     
 750:     if (localhost == null)
 751:       localhost = new InetAddress (loopbackAddress, "localhost");
 752:   }
 753: 
 754:   /**
 755:    * Needed for serialization
 756:    */
 757:   private void readResolve() throws ObjectStreamException
 758:   {
 759:     // FIXME: implement this
 760:   }
 761: 
 762:   private void readObject(ObjectInputStream ois)
 763:     throws IOException, ClassNotFoundException
 764:   {
 765:     ois.defaultReadObject();
 766:     addr = new byte[4];
 767:     addr[3] = (byte) address;
 768: 
 769:     for (int i = 2; i >= 0; --i)
 770:       addr[i] = (byte) (address >>= 8);
 771: 
 772:     // Ignore family from serialized data.  Since the saved address is 32 bits
 773:     // the deserialized object will have an IPv4 address i.e. AF_INET family.
 774:     // FIXME: An alternative is to call the aton method on the deserialized
 775:     // hostname to get a new address.  The Serialized Form doc is silent
 776:     // on how these fields are used.
 777:     family = getFamily (addr);
 778:   }
 779: 
 780:   private void writeObject(ObjectOutputStream oos) throws IOException
 781:   {
 782:     // Build a 32 bit address from the last 4 bytes of a 4 byte IPv4 address
 783:     // or a 16 byte IPv6 address.
 784:     int len = addr.length;
 785:     int i = len - 4;
 786: 
 787:     for (; i < len; i++)
 788:       address = address << 8 | (((int) addr[i]) & 0xFF);
 789: 
 790:     oos.defaultWriteObject();
 791:   }
 792: }