1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.net;
19 
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 
23 /**
24  * This class represents a socket endpoint described by a IP address and a port
25  * number. It is a concrete implementation of {@code SocketAddress} for IP.
26  */
27 public class InetSocketAddress extends SocketAddress {
28 
29     private static final long serialVersionUID = 5076001401234631237L;
30 
31     // Exactly one of hostname or addr should be set.
32     private final InetAddress addr;
33     private final String hostname;
34     private final int port;
35 
36     /**
37      * @hide internal use only
38      */
InetSocketAddress()39     public InetSocketAddress() {
40         // These will be filled in the native implementation of recvfrom.
41         this.addr = null;
42         this.hostname = null;
43         this.port = -1;
44     }
45 
46     /**
47      * Creates a socket endpoint with the given port number {@code port} and
48      * no specified address. The range for valid port numbers is between 0 and
49      * 65535 inclusive.
50      *
51      * @param port
52      *            the specified port number to which this socket is bound.
53      */
InetSocketAddress(int port)54     public InetSocketAddress(int port) {
55         this((InetAddress) null, port);
56     }
57 
58     /**
59      * Creates a socket endpoint with the given port number {@code port} and
60      * {@code address}. The range for valid port numbers is between 0 and 65535
61      * inclusive. If {@code address} is {@code null} this socket is bound to the
62      * IPv4 wildcard address.
63      *
64      * @param port
65      *            the specified port number to which this socket is bound.
66      * @param address
67      *            the specified address to which this socket is bound.
68      */
InetSocketAddress(InetAddress address, int port)69     public InetSocketAddress(InetAddress address, int port) {
70         if (port < 0 || port > 65535) {
71             throw new IllegalArgumentException("port=" + port);
72         }
73         this.addr = (address == null) ? Inet4Address.ANY : address;
74         this.hostname = null;
75         this.port = port;
76     }
77 
78     /**
79      * Creates a socket endpoint with the given port number {@code port} and the
80      * hostname {@code host}. The hostname is tried to be resolved and cannot be
81      * {@code null}. The range for valid port numbers is between 0 and 65535
82      * inclusive.
83      *
84      * @param port
85      *            the specified port number to which this socket is bound.
86      * @param host
87      *            the specified hostname to which this socket is bound.
88      */
InetSocketAddress(String host, int port)89     public InetSocketAddress(String host, int port) {
90         this(host, port, true);
91     }
92 
93     /*
94      * Internal constructor for InetSocketAddress(String, int) and
95      * createUnresolved(String, int);
96      */
InetSocketAddress(String hostname, int port, boolean needResolved)97     InetSocketAddress(String hostname, int port, boolean needResolved) {
98         if (hostname == null || port < 0 || port > 65535) {
99             throw new IllegalArgumentException("host=" + hostname + ", port=" + port);
100         }
101 
102         InetAddress addr = null;
103         if (needResolved) {
104             try {
105                 addr = InetAddress.getByName(hostname);
106                 hostname = null;
107             } catch (UnknownHostException ignored) {
108             }
109         }
110         this.addr = addr;
111         this.hostname = hostname;
112         this.port = port;
113     }
114 
115     /**
116      * Creates an {@code InetSocketAddress} without trying to resolve the
117      * hostname into an {@code InetAddress}. The address field is marked as
118      * unresolved.
119      *
120      * @param host
121      *            the specified hostname to which this socket is bound.
122      * @param port
123      *            the specified port number to which this socket is bound.
124      * @return the created InetSocketAddress instance.
125      * @throws IllegalArgumentException
126      *             if the hostname {@code host} is {@code null} or the port is
127      *             not in the range between 0 and 65535.
128      */
createUnresolved(String host, int port)129     public static InetSocketAddress createUnresolved(String host, int port) {
130         return new InetSocketAddress(host, port, false);
131     }
132 
133     /**
134      * Returns this socket address' port.
135      */
getPort()136     public final int getPort() {
137         return port;
138     }
139 
140     /**
141      * Returns this socket address' address.
142      */
getAddress()143     public final InetAddress getAddress() {
144         return addr;
145     }
146 
147     /**
148      * Returns the hostname, doing a reverse DNS lookup on the {@code InetAddress} if no
149      * hostname string was provided at construction time. Use {@link #getHostString} to
150      * avoid the reverse DNS lookup.
151      */
getHostName()152     public final String getHostName() {
153         return (addr != null) ? addr.getHostName() : hostname;
154     }
155 
156     /**
157      * Returns the hostname if known, or the result of {@code InetAddress.getHostAddress}.
158      * Unlike {@link #getHostName}, this method will never cause a DNS lookup.
159      * @since 1.7
160      */
getHostString()161     public final String getHostString() {
162         return (hostname != null) ? hostname : addr.getHostAddress();
163     }
164 
165     /**
166      * Returns whether this socket address is unresolved or not.
167      *
168      * @return {@code true} if this socket address is unresolved, {@code false}
169      *         otherwise.
170      */
isUnresolved()171     public final boolean isUnresolved() {
172         return addr == null;
173     }
174 
175     /**
176      * Returns a string containing the address (or the hostname for an
177      * unresolved {@code InetSocketAddress}) and port number.
178      * For example: {@code "www.google.com/74.125.224.115:80"} or {@code "/127.0.0.1:80"}.
179      */
toString()180     @Override public String toString() {
181         return ((addr != null) ? addr.toString() : hostname) + ":" + port;
182     }
183 
184     /**
185      * Compares two socket endpoints and returns true if they are equal. Two
186      * socket endpoints are equal if the IP address or the hostname of both are
187      * equal and they are bound to the same port.
188      *
189      * @param socketAddr
190      *            the object to be tested for equality.
191      * @return {@code true} if this socket and the given socket object {@code
192      *         socketAddr} are equal, {@code false} otherwise.
193      */
194     @Override
equals(Object socketAddr)195     public final boolean equals(Object socketAddr) {
196         if (this == socketAddr) {
197             return true;
198         }
199         if (!(socketAddr instanceof InetSocketAddress)) {
200             return false;
201         }
202         InetSocketAddress iSockAddr = (InetSocketAddress) socketAddr;
203 
204         // check the ports as we always need to do this
205         if (port != iSockAddr.port) {
206             return false;
207         }
208 
209         // we only use the hostnames in the comparison if the addrs were not
210         // resolved
211         if ((addr == null) && (iSockAddr.addr == null)) {
212             return hostname.equals(iSockAddr.hostname);
213         }
214 
215         // addrs were resolved so use them for the comparison
216         if (addr == null) {
217             // if we are here we know iSockAddr is not null so just return
218             // false
219             return false;
220         }
221         return addr.equals(iSockAddr.addr);
222     }
223 
224     @Override
hashCode()225     public final int hashCode() {
226         if (addr == null) {
227             return hostname.hashCode() + port;
228         }
229         return addr.hashCode() + port;
230     }
231 
readObject(ObjectInputStream stream)232     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
233         stream.defaultReadObject();
234     }
235 }
236