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