Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 package java.net;
     27 
     28 import java.io.IOException;
     29 import java.io.InvalidObjectException;
     30 import java.io.ObjectInputStream;
     31 import java.io.ObjectOutputStream;
     32 import java.io.ObjectStreamException;
     33 import java.io.ObjectStreamField;
     34 
     35 /**
     36  *
     37  * This class implements an IP Socket Address (IP address + port number)
     38  * It can also be a pair (hostname + port number), in which case an attempt
     39  * will be made to resolve the hostname. If resolution fails then the address
     40  * is said to be <I>unresolved</I> but can still be used on some circumstances
     41  * like connecting through a proxy.
     42  * <p>
     43  * It provides an immutable object used by sockets for binding, connecting, or
     44  * as returned values.
     45  * <p>
     46  * The <i>wildcard</i> is a special local IP address. It usually means "any"
     47  * and can only be used for {@code bind} operations.
     48  *
     49  * @see java.net.Socket
     50  * @see java.net.ServerSocket
     51  * @since 1.4
     52  */
     53 public class InetSocketAddress
     54     extends SocketAddress
     55 {
     56     // Private implementation class pointed to by all public methods.
     57     private static class InetSocketAddressHolder {
     58         // The hostname of the Socket Address
     59         private String hostname;
     60         // The IP address of the Socket Address
     61         private InetAddress addr;
     62         // The port number of the Socket Address
     63         private int port;
     64 
     65         private InetSocketAddressHolder(String hostname, InetAddress addr, int port) {
     66             this.hostname = hostname;
     67             this.addr = addr;
     68             this.port = port;
     69         }
     70 
     71         private int getPort() {
     72             return port;
     73         }
     74 
     75         private InetAddress getAddress() {
     76             return addr;
     77         }
     78 
     79         private String getHostName() {
     80             if (hostname != null)
     81                 return hostname;
     82             if (addr != null)
     83                 return addr.getHostName();
     84             return null;
     85         }
     86 
     87         private String getHostString() {
     88             if (hostname != null)
     89                 return hostname;
     90             if (addr != null) {
     91                 if (addr.holder().getHostName() != null)
     92                     return addr.holder().getHostName();
     93                 else
     94                     return addr.getHostAddress();
     95             }
     96             return null;
     97         }
     98 
     99         private boolean isUnresolved() {
    100             return addr == null;
    101         }
    102 
    103         @Override
    104         public String toString() {
    105             if (isUnresolved()) {
    106                 return hostname + ":" + port;
    107             } else {
    108                 return addr.toString() + ":" + port;
    109             }
    110         }
    111 
    112         @Override
    113         public final boolean equals(Object obj) {
    114             if (obj == null || !(obj instanceof InetSocketAddressHolder))
    115                 return false;
    116             InetSocketAddressHolder that = (InetSocketAddressHolder)obj;
    117             boolean sameIP;
    118             if (addr != null)
    119                 sameIP = addr.equals(that.addr);
    120             else if (hostname != null)
    121                 sameIP = (that.addr == null) &&
    122                     hostname.equalsIgnoreCase(that.hostname);
    123             else
    124                 sameIP = (that.addr == null) && (that.hostname == null);
    125             return sameIP && (port == that.port);
    126         }
    127 
    128         @Override
    129         public final int hashCode() {
    130             if (addr != null)
    131                 return addr.hashCode() + port;
    132             if (hostname != null)
    133                 return hostname.toLowerCase().hashCode() + port;
    134             return port;
    135         }
    136     }
    137 
    138     private final transient InetSocketAddressHolder holder;
    139 
    140     private static final long serialVersionUID = 5076001401234631237L;
    141 
    142     private static int checkPort(int port) {
    143         if (port < 0 || port > 0xFFFF)
    144             throw new IllegalArgumentException("port out of range:" + port);
    145         return port;
    146     }
    147 
    148     private static String checkHost(String hostname) {
    149         if (hostname == null)
    150             throw new IllegalArgumentException("hostname can't be null");
    151         return hostname;
    152     }
    153 
    154     /**
    155      * @hide internal use only
    156      */
    157     public InetSocketAddress() {
    158         // These will be filled in the native implementation of recvfrom.
    159         holder = new InetSocketAddressHolder(null, null, 0);
    160     }
    161 
    162     /**
    163      * Creates a socket address where the IP address is the wildcard address
    164      * and the port number a specified value.
    165      * <p>
    166      * A valid port value is between 0 and 65535.
    167      * A port number of {@code zero} will let the system pick up an
    168      * ephemeral port in a {@code bind} operation.
    169      * <p>
    170      * @param   port    The port number
    171      * @throws IllegalArgumentException if the port parameter is outside the specified
    172      * range of valid port values.
    173      */
    174     public InetSocketAddress(int port) {
    175       this((InetAddress)null, port);
    176     }
    177 
    178     /**
    179      *
    180      * Creates a socket address from an IP address and a port number.
    181      * <p>
    182      * A valid port value is between 0 and 65535.
    183      * A port number of {@code zero} will let the system pick up an
    184      * ephemeral port in a {@code bind} operation.
    185      * <P>
    186      * A {@code null} address will assign the <i>wildcard</i> address.
    187      * <p>
    188      * @param   addr    The IP address
    189      * @param   port    The port number
    190      * @throws IllegalArgumentException if the port parameter is outside the specified
    191      * range of valid port values.
    192      */
    193     public InetSocketAddress(InetAddress addr, int port) {
    194         holder = new InetSocketAddressHolder(
    195                         null,
    196                         // Android-changed: Return IPv4 address
    197                         // addr == null ? InetAddress.anyLocalAddress() : addr,
    198                         addr == null ? Inet6Address.ANY : addr,
    199                         checkPort(port));
    200     }
    201 
    202     /**
    203      *
    204      * Creates a socket address from a hostname and a port number.
    205      * <p>
    206      * An attempt will be made to resolve the hostname into an InetAddress.
    207      * If that attempt fails, the address will be flagged as <I>unresolved</I>.
    208      * <p>
    209      * If there is a security manager, its {@code checkConnect} method
    210      * is called with the host name as its argument to check the permissiom
    211      * to resolve it. This could result in a SecurityException.
    212      * <P>
    213      * A valid port value is between 0 and 65535.
    214      * A port number of {@code zero} will let the system pick up an
    215      * ephemeral port in a {@code bind} operation.
    216      * <P>
    217      * @param   hostname the Host name
    218      * @param   port    The port number
    219      * @throws IllegalArgumentException if the port parameter is outside the range
    220      * of valid port values, or if the hostname parameter is <TT>null</TT>.
    221      * @throws SecurityException if a security manager is present and
    222      *                           permission to resolve the host name is
    223      *                           denied.
    224      * @see     #isUnresolved()
    225      */
    226     public InetSocketAddress(String hostname, int port) {
    227         checkHost(hostname);
    228         InetAddress addr = null;
    229         String host = null;
    230         try {
    231             addr = InetAddress.getByName(hostname);
    232         } catch(UnknownHostException e) {
    233             host = hostname;
    234         }
    235         holder = new InetSocketAddressHolder(host, addr, checkPort(port));
    236     }
    237 
    238     // private constructor for creating unresolved instances
    239     private InetSocketAddress(int port, String hostname) {
    240         holder = new InetSocketAddressHolder(hostname, null, port);
    241     }
    242 
    243     /**
    244      *
    245      * Creates an unresolved socket address from a hostname and a port number.
    246      * <p>
    247      * No attempt will be made to resolve the hostname into an InetAddress.
    248      * The address will be flagged as <I>unresolved</I>.
    249      * <p>
    250      * A valid port value is between 0 and 65535.
    251      * A port number of {@code zero} will let the system pick up an
    252      * ephemeral port in a {@code bind} operation.
    253      * <P>
    254      * @param   host    the Host name
    255      * @param   port    The port number
    256      * @throws IllegalArgumentException if the port parameter is outside
    257      *                  the range of valid port values, or if the hostname
    258      *                  parameter is <TT>null</TT>.
    259      * @see     #isUnresolved()
    260      * @return  a {@code InetSocketAddress} representing the unresolved
    261      *          socket address
    262      * @since 1.5
    263      */
    264     public static InetSocketAddress createUnresolved(String host, int port) {
    265         return new InetSocketAddress(checkPort(port), checkHost(host));
    266     }
    267 
    268     /**
    269      * @serialField hostname String
    270      * @serialField addr InetAddress
    271      * @serialField port int
    272      */
    273     private static final ObjectStreamField[] serialPersistentFields = {
    274          new ObjectStreamField("hostname", String.class),
    275          new ObjectStreamField("addr", InetAddress.class),
    276          new ObjectStreamField("port", int.class)};
    277 
    278     private void writeObject(ObjectOutputStream out)
    279         throws IOException
    280     {
    281         // Don't call defaultWriteObject()
    282          ObjectOutputStream.PutField pfields = out.putFields();
    283          pfields.put("hostname", holder.hostname);
    284          pfields.put("addr", holder.addr);
    285          pfields.put("port", holder.port);
    286          out.writeFields();
    287      }
    288 
    289     private void readObject(ObjectInputStream in)
    290         throws IOException, ClassNotFoundException
    291     {
    292         // Don't call defaultReadObject()
    293         ObjectInputStream.GetField oisFields = in.readFields();
    294         final String oisHostname = (String)oisFields.get("hostname", null);
    295         final InetAddress oisAddr = (InetAddress)oisFields.get("addr", null);
    296         final int oisPort = oisFields.get("port", -1);
    297 
    298         // Check that our invariants are satisfied
    299         checkPort(oisPort);
    300         if (oisHostname == null && oisAddr == null)
    301             throw new InvalidObjectException("hostname and addr " +
    302                                              "can't both be null");
    303 
    304         InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname,
    305                                                                 oisAddr,
    306                                                                 oisPort);
    307         UNSAFE.putObject(this, FIELDS_OFFSET, h);
    308     }
    309 
    310     private void readObjectNoData()
    311         throws ObjectStreamException
    312     {
    313         throw new InvalidObjectException("Stream data required");
    314     }
    315 
    316     private static final long FIELDS_OFFSET;
    317     private static final sun.misc.Unsafe UNSAFE;
    318     static {
    319         try {
    320             sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
    321             FIELDS_OFFSET = unsafe.objectFieldOffset(
    322                     InetSocketAddress.class.getDeclaredField("holder"));
    323             UNSAFE = unsafe;
    324         } catch (ReflectiveOperationException e) {
    325             throw new Error(e);
    326         }
    327     }
    328 
    329     /**
    330      * Gets the port number.
    331      *
    332      * @return the port number.
    333      */
    334     public final int getPort() {
    335         return holder.getPort();
    336     }
    337 
    338     /**
    339      *
    340      * Gets the {@code InetAddress}.
    341      *
    342      * @return the InetAdress or {@code null} if it is unresolved.
    343      */
    344     public final InetAddress getAddress() {
    345         return holder.getAddress();
    346     }
    347 
    348     /**
    349      * Gets the {@code hostname}.
    350      * Note: This method may trigger a name service reverse lookup if the
    351      * address was created with a literal IP address.
    352      *
    353      * @return  the hostname part of the address.
    354      */
    355     public final String getHostName() {
    356         return holder.getHostName();
    357     }
    358 
    359     /**
    360      * Returns the hostname, or the String form of the address if it
    361      * doesn't have a hostname (it was created using a literal).
    362      * This has the benefit of <b>not</b> attempting a reverse lookup.
    363      *
    364      * @return the hostname, or String representation of the address.
    365      * @since 1.7
    366      */
    367     public final String getHostString() {
    368         return holder.getHostString();
    369     }
    370 
    371     /**
    372      * Checks whether the address has been resolved or not.
    373      *
    374      * @return {@code true} if the hostname couldn't be resolved into
    375      *          an {@code InetAddress}.
    376      */
    377     public final boolean isUnresolved() {
    378         return holder.isUnresolved();
    379     }
    380 
    381     /**
    382      * Constructs a string representation of this InetSocketAddress.
    383      * This String is constructed by calling toString() on the InetAddress
    384      * and concatenating the port number (with a colon). If the address
    385      * is unresolved then the part before the colon will only contain the hostname.
    386      *
    387      * @return  a string representation of this object.
    388      */
    389     @Override
    390     public String toString() {
    391         return holder.toString();
    392     }
    393 
    394     /**
    395      * Compares this object against the specified object.
    396      * The result is {@code true} if and only if the argument is
    397      * not {@code null} and it represents the same address as
    398      * this object.
    399      * <p>
    400      * Two instances of {@code InetSocketAddress} represent the same
    401      * address if both the InetAddresses (or hostnames if it is unresolved) and port
    402      * numbers are equal.
    403      * If both addresses are unresolved, then the hostname & the port number
    404      * are compared.
    405      *
    406      * Note: Hostnames are case insensitive. e.g. "FooBar" and "foobar" are
    407      * considered equal.
    408      *
    409      * @param   obj   the object to compare against.
    410      * @return  {@code true} if the objects are the same;
    411      *          {@code false} otherwise.
    412      * @see java.net.InetAddress#equals(java.lang.Object)
    413      */
    414     @Override
    415     public final boolean equals(Object obj) {
    416         if (obj == null || !(obj instanceof InetSocketAddress))
    417             return false;
    418         return holder.equals(((InetSocketAddress) obj).holder);
    419     }
    420 
    421     /**
    422      * Returns a hashcode for this socket address.
    423      *
    424      * @return  a hash code value for this socket address.
    425      */
    426     @Override
    427     public final int hashCode() {
    428         return holder.hashCode();
    429     }
    430 }
    431