InetAddress.java 18.8 KB
Newer Older
Tom Tromey committed
1
/* InetAddress.java -- Class to model an Internet address
2 3
   Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006
   Free Software Foundation, Inc.
Tom Tromey committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

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

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


package java.net;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 * This class models an Internet address.  It does not have a public
 * constructor.  Instead, new instances of this objects are created
 * using the static methods getLocalHost(), getByName(), and
 * getAllByName().
 *
 * <p>This class fulfills the function of the C style functions gethostname(),
 * gethostbyname(), and gethostbyaddr().  It resolves Internet DNS names
 * into their corresponding numeric addresses and vice versa.</p>
 *
 * @author Aaron M. Renn (arenn@urbanophile.com)
 * @author Per Bothner
60
 * @author Gary Benson (gbenson@redhat.com)
Tom Tromey committed
61
 *
62
 * @specnote This class is not final since JDK 1.4
Tom Tromey committed
63 64 65 66 67 68 69 70 71
 */
public class InetAddress implements Serializable
{
  private static final long serialVersionUID = 3286316764910316507L;

  /**
   * Dummy InetAddress, used to bind socket to any (all) network interfaces.
   */
  static InetAddress ANY_IF;
72 73 74 75 76
  static
  {
    byte[] addr;
    try
      {
77
        addr = VMInetAddress.lookupInaddrAny();
78 79 80
      }
    catch (UnknownHostException e)
      {
81 82
        // Make one up and hope it works.
        addr = new byte[] {0, 0, 0, 0};
83 84 85
      }
    try
      {
86
        ANY_IF = getByAddress(addr);
87 88 89
      }
    catch (UnknownHostException e)
      {
90
        throw (InternalError) new InternalError().initCause(e);
91 92 93
      }
    ANY_IF.hostName = ANY_IF.getHostName();
  }
94

Tom Tromey committed
95 96 97 98 99 100 101 102
  /**
   * Stores static localhost address object.
   */
  static InetAddress LOCALHOST;
  static
  {
    try
      {
103
        LOCALHOST = getByAddress("localhost", new byte[] {127, 0, 0, 1});
Tom Tromey committed
104
      }
105
    catch (UnknownHostException e)
Tom Tromey committed
106
      {
107
        throw (InternalError) new InternalError().initCause(e);
Tom Tromey committed
108
      }
109
  }
Tom Tromey committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

  /**
   * The Serialized Form specifies that an int 'address' is saved/restored.
   * This class uses a byte array internally so we'll just do the conversion
   * at serialization time and leave the rest of the algorithm as is.
   */
  private int address;

  /**
   * An array of octets representing an IP address.
   */
  transient byte[] addr;

  /**
   * The name of the host for this address.
   */
  String hostName;

  /**
129
   * Needed for serialization.
Tom Tromey committed
130
   */
131
  private int family;
Tom Tromey committed
132 133

  /**
134 135 136 137 138 139 140
   * Constructor.  Prior to the introduction of IPv6 support in 1.4,
   * methods such as InetAddress.getByName() would return InetAddress
   * objects.  From 1.4 such methods returned either Inet4Address or
   * Inet6Address objects, but for compatibility Inet4Address objects
   * are serialized as InetAddresses.  As such, there are only two
   * places where it is appropriate to invoke this constructor: within
   * subclasses constructors and within Inet4Address.writeReplace().
Tom Tromey committed
141 142 143
   *
   * @param ipaddr The IP number of this address as an array of bytes
   * @param hostname The hostname of this IP address.
144
   * @param family The address family of this IP address.
Tom Tromey committed
145
   */
146
  InetAddress(byte[] ipaddr, String hostname, int family)
Tom Tromey committed
147 148 149
  {
    addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone();
    hostName = hostname;
150
    this.family = family;
Tom Tromey committed
151 152 153 154 155 156 157
  }

  /**
   * Returns true if this address is a multicast address, false otherwise.
   * An address is multicast if the high four bits are "1110".  These are
   * also known as "Class D" addresses.
   *
158 159 160
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
161
   *
Tom Tromey committed
162 163 164 165 166 167
   * @return true if mulitcast, false if not
   *
   * @since 1.1
   */
  public boolean isMulticastAddress()
  {
168
    throw new UnsupportedOperationException();
Tom Tromey committed
169 170 171 172 173
  }

  /**
   * Utility routine to check if the InetAddress in a wildcard address
   *
174 175 176
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
177
   *
Tom Tromey committed
178 179 180 181
   * @since 1.4
   */
  public boolean isAnyLocalAddress()
  {
182
    throw new UnsupportedOperationException();
Tom Tromey committed
183 184 185 186 187
  }

  /**
   * Utility routine to check if the InetAddress is a loopback address
   *
188 189 190
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
191
   *
Tom Tromey committed
192 193 194 195
   * @since 1.4
   */
  public boolean isLoopbackAddress()
  {
196
    throw new UnsupportedOperationException();
Tom Tromey committed
197 198 199 200 201
  }

  /**
   * Utility routine to check if InetAddress is a link local address
   *
202 203 204
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
205
   *
Tom Tromey committed
206 207 208 209
   * @since 1.4
   */
  public boolean isLinkLocalAddress()
  {
210
    throw new UnsupportedOperationException();
Tom Tromey committed
211 212 213 214 215
  }

  /**
   * Utility routine to check if InetAddress is a site local address
   *
216 217 218
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
219
   *
Tom Tromey committed
220 221 222 223
   * @since 1.4
   */
  public boolean isSiteLocalAddress()
  {
224
    throw new UnsupportedOperationException();
Tom Tromey committed
225 226 227 228 229
  }

  /**
   * Utility routine to check if InetAddress is a global multicast address
   *
230 231 232
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
233
   *
Tom Tromey committed
234 235 236 237
   * @since 1.4
   */
  public boolean isMCGlobal()
  {
238
    throw new UnsupportedOperationException();
Tom Tromey committed
239 240 241 242 243
  }

  /**
   * Utility routine to check if InetAddress is a node local multicast address.
   *
244 245 246
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
247
   *
Tom Tromey committed
248 249 250 251
   * @since 1.4
   */
  public boolean isMCNodeLocal()
  {
252
    throw new UnsupportedOperationException();
Tom Tromey committed
253 254 255 256 257
  }

  /**
   * Utility routine to check if InetAddress is a link local multicast address.
   *
258 259 260
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
261
   *
Tom Tromey committed
262 263 264 265
   * @since 1.4
   */
  public boolean isMCLinkLocal()
  {
266
    throw new UnsupportedOperationException();
Tom Tromey committed
267 268 269 270 271
  }

  /**
   * Utility routine to check if InetAddress is a site local multicast address.
   *
272 273 274
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
275
   *
Tom Tromey committed
276 277 278 279
   * @since 1.4
   */
  public boolean isMCSiteLocal()
  {
280
    throw new UnsupportedOperationException();
Tom Tromey committed
281 282 283 284 285 286
  }

  /**
   * Utility routine to check if InetAddress is a organization local
   * multicast address.
   *
287 288 289
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
290
   *
Tom Tromey committed
291 292 293 294
   * @since 1.4
   */
  public boolean isMCOrgLocal()
  {
295
    throw new UnsupportedOperationException();
Tom Tromey committed
296 297 298 299 300 301 302 303 304 305
  }

  /**
   * Returns the hostname for this address.  This will return the IP address
   * as a String if there is no hostname available for this address
   *
   * @return The hostname for this address
   */
  public String getHostName()
  {
306 307
    if (hostName == null)
      hostName = getCanonicalHostName();
Tom Tromey committed
308

309 310 311 312 313 314 315 316
    return hostName;
  }

  /**
   * Returns the canonical hostname represented by this InetAddress
   */
  String internalGetCanonicalHostName()
  {
Tom Tromey committed
317 318
    try
      {
319
        return ResolverCache.getHostByAddr(addr);
Tom Tromey committed
320 321 322
      }
    catch (UnknownHostException e)
      {
323
        return getHostAddress();
Tom Tromey committed
324 325 326 327 328
      }
  }

  /**
   * Returns the canonical hostname represented by this InetAddress
329
   *
Tom Tromey committed
330 331 332 333
   * @since 1.4
   */
  public String getCanonicalHostName()
  {
334 335
    String hostname = internalGetCanonicalHostName();

Tom Tromey committed
336 337 338 339
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      {
        try
340
          {
341
            sm.checkConnect(hostname, -1);
342 343 344 345 346
          }
        catch (SecurityException e)
          {
            return getHostAddress();
          }
Tom Tromey committed
347 348
      }

349
    return hostname;
Tom Tromey committed
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
  }

  /**
   * Returns the IP address of this object as a byte array.
   *
   * @return IP address
   */
  public byte[] getAddress()
  {
    // An experiment shows that JDK1.2 returns a different byte array each
    // time.  This makes sense, in terms of security.
    return (byte[]) addr.clone();
  }

  /**
365
   * Returns the IP address of this object as a String.
Tom Tromey committed
366
   *
367 368 369
   * <p>This method cannot be abstract for backward compatibility reasons. By
   * default it always throws {@link UnsupportedOperationException} unless
   * overridden.</p>
370
   *
Tom Tromey committed
371 372 373 374 375 376
   * @return The IP address of this object in String form
   *
   * @since 1.0.2
   */
  public String getHostAddress()
  {
377
    throw new UnsupportedOperationException();
Tom Tromey committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
  }

  /**
   * Returns a hash value for this address.  Useful for creating hash
   * tables.  Overrides Object.hashCode()
   *
   * @return A hash value for this address.
   */
  public int hashCode()
  {
    // There hashing algorithm is not specified, but a simple experiment
    // shows that it is equal to the address, as a 32-bit big-endian integer.
    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;
  }

  /**
   * Tests this address for equality against another InetAddress.  The two
   * addresses are considered equal if they contain the exact same octets.
   * This implementation overrides Object.equals()
   *
   * @param obj The address to test for equality
   *
   * @return true if the passed in object's address is equal to this one's,
   * false otherwise
   */
  public boolean equals(Object obj)
  {
    if (! (obj instanceof InetAddress))
      return false;

    // "The Java Class Libraries" 2nd edition says "If a machine has
    // multiple names instances of InetAddress for different name of
    // that same machine are not equal.  This is because they have
    // different host names."  This violates the description in the
    // JDK 1.2 API documentation.  A little experimentation
    // shows that the latter is correct.
    byte[] addr2 = ((InetAddress) obj).addr;

    if (addr.length != addr2.length)
      return false;

    for (int i = 0; i < addr.length; i++)
      if (addr[i] != addr2[i])
428
        return false;
Tom Tromey committed
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

    return true;
  }

  /**
   * Converts this address to a String.  This string contains the IP in
   * dotted decimal form. For example: "127.0.0.1"  This method is equivalent
   * to getHostAddress() and overrides Object.toString()
   *
   * @return This address in String form
   */
  public String toString()
  {
    String addr = getHostAddress();
    String host = (hostName != null) ? hostName : "";
    return host + "/" + addr;
  }

  /**
   * Returns an InetAddress object given the raw IP address.
   *
   * The argument is in network byte order: the highest order byte of the
   * address is in getAddress()[0].
   *
   * @param addr The IP address to create the InetAddress object from
   *
   * @exception UnknownHostException If IP address has illegal length
   *
   * @since 1.4
   */
  public static InetAddress getByAddress(byte[] addr)
    throws UnknownHostException
  {
    return getByAddress(null, addr);
  }

  /**
   * Creates an InetAddress based on the provided host name and IP address.
   * No name service is checked for the validity of the address.
   *
   * @param host The hostname of the InetAddress object to create
   * @param addr The IP address to create the InetAddress object from
   *
   * @exception UnknownHostException If IP address is of illegal length
   *
   * @since 1.4
   */
  public static InetAddress getByAddress(String host, byte[] addr)
    throws UnknownHostException
  {
    if (addr.length == 4)
      return new Inet4Address(addr, host);

    if (addr.length == 16)
483
      {
484 485 486 487 488 489 490 491 492 493 494 495
        for (int i = 0; i < 12; i++)
          {
            if (addr[i] != (i < 10 ? 0 : (byte) 0xFF))
              return new Inet6Address(addr, host);
          }

        byte[] ip4addr = new byte[4];
        ip4addr[0] = addr[12];
        ip4addr[1] = addr[13];
        ip4addr[2] = addr[14];
        ip4addr[3] = addr[15];
        return new Inet4Address(ip4addr, host);
496
      }
Tom Tromey committed
497 498 499 500 501

    throw new UnknownHostException("IP address has illegal length");
  }

  /**
502 503 504 505 506 507 508
   * Returns an InetAddress object representing the IP address of
   * the given literal IP address in dotted decimal format such as
   * "127.0.0.1".  This is used by SocketPermission.setHostPort()
   * to parse literal IP addresses without performing a DNS lookup.
   *
   * @param literal The literal IP address to create the InetAddress
   * object from
Tom Tromey committed
509
   *
510 511
   * @return The address of the host as an InetAddress object, or
   * null if the IP address is invalid.
Tom Tromey committed
512
   */
513
  static InetAddress getByLiteral(String literal)
Tom Tromey committed
514
  {
515 516 517
    byte[] address = VMInetAddress.aton(literal);
    if (address == null)
      return null;
518

519
    try
Tom Tromey committed
520
      {
521
        return getByAddress(address);
522 523 524
      }
    catch (UnknownHostException e)
      {
525
        throw (InternalError) new InternalError().initCause(e);
Tom Tromey committed
526 527 528 529 530 531 532 533 534 535 536
      }
  }

  /**
   * Returns an InetAddress object representing the IP address of the given
   * hostname.  This name can be either a hostname such as "www.urbanophile.com"
   * or an IP address in dotted decimal format such as "127.0.0.1".  If the
   * hostname is null or "", the hostname of the local machine is supplied by
   * default.  This method is equivalent to returning the first element in
   * the InetAddress array returned from GetAllByName.
   *
537
   * @param hostname The name of the desired host, or null for the local
Tom Tromey committed
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
   * loopback address.
   *
   * @return The address of the host as an InetAddress object.
   *
   * @exception UnknownHostException If no IP address for the host could
   * be found
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
   */
  public static InetAddress getByName(String hostname)
    throws UnknownHostException
  {
    InetAddress[] addresses = getAllByName(hostname);
    return addresses[0];
  }

  /**
   * Returns an array of InetAddress objects representing all the host/ip
   * addresses of a given host, given the host's name.  This name can be
   * either a hostname such as "www.urbanophile.com" or an IP address in
   * dotted decimal format such as "127.0.0.1".  If the value is null, the
   * hostname of the local machine is supplied by default.
   *
   * @param hostname The name of the desired host, or null for the
   * local loopback address.
   *
   * @return All addresses of the host as an array of InetAddress objects.
   *
   * @exception UnknownHostException If no IP address for the host could
   * be found
   * @exception SecurityException If a security manager exists and its
   * checkConnect method doesn't allow the operation
   */
  public static InetAddress[] getAllByName(String hostname)
    throws UnknownHostException
  {
574 575 576 577
    // If null or the empty string is supplied, the loopback address
    // is returned.
    if (hostname == null || hostname.length() == 0)
      return new InetAddress[] {LOCALHOST};
578

579 580 581 582
    // Check if hostname is an IP address
    InetAddress address = getByLiteral(hostname);
    if (address != null)
      return new InetAddress[] {address};
Tom Tromey committed
583

584 585 586 587
    // Perform security check before resolving
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      sm.checkConnect(hostname, -1);
Tom Tromey committed
588

589 590
    // Resolve the hostname
    byte[][] iplist = ResolverCache.getHostByName(hostname);
Tom Tromey committed
591 592 593
    if (iplist.length == 0)
      throw new UnknownHostException(hostname);

594
    InetAddress[] addresses = new InetAddress[iplist.length];
Tom Tromey committed
595
    for (int i = 0; i < iplist.length; i++)
596
      addresses[i] = getByAddress(hostname, iplist[i]);
Tom Tromey committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612

    return addresses;
  }

  /**
   * Returns an InetAddress object representing the address of the current
   * host.
   *
   * @return The local host's address
   *
   * @exception UnknownHostException If no IP address for the host could
   * be found
   */
  public static InetAddress getLocalHost() throws UnknownHostException
  {
    String hostname = VMInetAddress.getLocalHostname();
613 614
    try
      {
615
        return getByName(hostname);
616 617 618
      }
    catch (SecurityException e)
      {
619
        return LOCALHOST;
620
      }
Tom Tromey committed
621 622
  }

623 624 625
  /**
   * Inet4Address objects are serialized as InetAddress objects.
   * This deserializes them back into Inet4Address objects.
Tom Tromey committed
626
   */
627
  private Object readResolve() throws ObjectStreamException
Tom Tromey committed
628
  {
629
    return new Inet4Address(addr, hostName);
Tom Tromey committed
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
  }

  private void readObject(ObjectInputStream ois)
    throws IOException, ClassNotFoundException
  {
    ois.defaultReadObject();
    addr = new byte[4];
    addr[3] = (byte) address;

    for (int i = 2; i >= 0; --i)
      addr[i] = (byte) (address >>= 8);
  }

  private void writeObject(ObjectOutputStream oos) throws IOException
  {
    // Build a 32 bit address from the last 4 bytes of a 4 byte IPv4 address
    // or a 16 byte IPv6 address.
    int len = addr.length;
    int i = len - 4;

    for (; i < len; i++)
      address = address << 8 | (addr[i] & 0xff);

    oos.defaultWriteObject();
  }
}