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 64 private InetSocketAddressHolder(String hostname, InetAddress addr, int port) { 65 this.hostname = hostname; 66 this.addr = addr; 67 this.port = port; 68 } 69 70 private int getPort() { 71 return port; 72 } 73 74 private InetAddress getAddress() { 75 return addr; 76 } 77 78 private String getHostName() { 79 if (hostname != null) 80 return hostname; 81 if (addr != null) 82 return addr.getHostName(); 83 return null; 84 } 85 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 98 private boolean isUnresolved() { 99 return addr == null; 100 } 101 102 @Override 103 public String toString() { 104 if (isUnresolved()) { 105 return hostname + ":" + port; 106 } else { 107 return addr.toString() + ":" + port; 108 } 109 } 110 111 @Override 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 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 @java.io.Serial 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 * Creates a socket address where the IP address is the wildcard address 156 * and the port number a specified value. 157 * <p> 158 * A valid port value is between 0 and 65535. 159 * A port number of {@code zero} will let the system pick up an 160 * ephemeral port in a {@code bind} operation. 161 * 162 * @param port The port number 163 * @throws IllegalArgumentException if the port parameter is outside the specified 164 * range of valid port values. 165 */ 166 public InetSocketAddress(int port) { 167 this(InetAddress.anyLocalAddress(), port); 168 } 169 170 /** 171 * 172 * Creates a socket address from an IP address and a port number. 173 * <p> 174 * A valid port value is between 0 and 65535. 175 * A port number of {@code zero} will let the system pick up an 176 * ephemeral port in a {@code bind} operation. 177 * <P> 178 * A {@code null} address will assign the <i>wildcard</i> address. 179 * 180 * @param addr The IP address 181 * @param port The port number 182 * @throws IllegalArgumentException if the port parameter is outside the specified 183 * range of valid port values. 184 */ 185 public InetSocketAddress(InetAddress addr, int port) { 186 holder = new InetSocketAddressHolder( 187 null, 188 addr == null ? InetAddress.anyLocalAddress() : addr, 189 checkPort(port)); 190 } 191 192 /** 193 * 194 * Creates a socket address from a hostname and a port number. 195 * <p> 196 * An attempt will be made to resolve the hostname into an InetAddress. 197 * If that attempt fails, the address will be flagged as <I>unresolved</I>. 198 * <p> 199 * If there is a security manager, its {@code checkConnect} method 200 * is called with the host name as its argument to check the permission 201 * to resolve it. This could result in a SecurityException. 202 * <P> 203 * A valid port value is between 0 and 65535. 204 * A port number of {@code zero} will let the system pick up an 205 * ephemeral port in a {@code bind} operation. 206 * 207 * @param hostname the Host name 208 * @param port The port number 209 * @throws IllegalArgumentException if the port parameter is outside the range 210 * of valid port values, or if the hostname parameter is {@code null}. 211 * @throws SecurityException if a security manager is present and 212 * permission to resolve the host name is 213 * denied. 214 * @see #isUnresolved() 215 */ 216 public InetSocketAddress(String hostname, int port) { 217 checkHost(hostname); 218 InetAddress addr = null; 219 String host = null; 220 try { 221 addr = InetAddress.getByName(hostname); 222 } catch(UnknownHostException e) { 223 host = hostname; 224 } 225 holder = new InetSocketAddressHolder(host, addr, checkPort(port)); 226 } 227 228 // private constructor for creating unresolved instances 229 private InetSocketAddress(int port, String hostname) { 230 holder = new InetSocketAddressHolder(hostname, null, port); 231 } 232 233 /** 234 * 235 * Creates an unresolved socket address from a hostname and a port number. 236 * <p> 237 * No attempt will be made to resolve the hostname into an InetAddress. 238 * The address will be flagged as <I>unresolved</I>. 239 * <p> 240 * A valid port value is between 0 and 65535. 241 * A port number of {@code zero} will let the system pick up an 242 * ephemeral port in a {@code bind} operation. 243 * 244 * @param host the Host name 245 * @param port The port number 246 * @throws IllegalArgumentException if the port parameter is outside 247 * the range of valid port values, or if the hostname 248 * parameter is {@code null}. 249 * @see #isUnresolved() 250 * @return an {@code InetSocketAddress} representing the unresolved 251 * socket address 252 * @since 1.5 253 */ 254 public static InetSocketAddress createUnresolved(String host, int port) { 255 return new InetSocketAddress(checkPort(port), checkHost(host)); 256 } 257 258 /** 259 * @serialField hostname String 260 * @serialField addr InetAddress 261 * @serialField port int 262 */ 263 @java.io.Serial 264 private static final ObjectStreamField[] serialPersistentFields = { 265 new ObjectStreamField("hostname", String.class), 266 new ObjectStreamField("addr", InetAddress.class), 267 new ObjectStreamField("port", int.class)}; 268 269 @java.io.Serial 270 private void writeObject(ObjectOutputStream out) 271 throws IOException 272 { 273 // Don't call defaultWriteObject() 274 ObjectOutputStream.PutField pfields = out.putFields(); 275 pfields.put("hostname", holder.hostname); 276 pfields.put("addr", holder.addr); 277 pfields.put("port", holder.port); 278 out.writeFields(); 279 } 280 281 @java.io.Serial 282 private void readObject(ObjectInputStream in) 283 throws IOException, ClassNotFoundException 284 { 285 // Don't call defaultReadObject() 286 ObjectInputStream.GetField oisFields = in.readFields(); 287 final String oisHostname = (String)oisFields.get("hostname", null); 288 final InetAddress oisAddr = (InetAddress)oisFields.get("addr", null); 289 final int oisPort = oisFields.get("port", -1); 290 291 // Check that our invariants are satisfied 292 checkPort(oisPort); 293 if (oisHostname == null && oisAddr == null) 294 throw new InvalidObjectException("hostname and addr " + 295 "can't both be null"); 296 297 InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname, 298 oisAddr, 299 oisPort); 300 UNSAFE.putReference(this, FIELDS_OFFSET, h); 301 } 302 303 @java.io.Serial 304 private void readObjectNoData() 305 throws ObjectStreamException 306 { 307 throw new InvalidObjectException("Stream data required"); 308 } 309 310 private static final jdk.internal.misc.Unsafe UNSAFE 311 = jdk.internal.misc.Unsafe.getUnsafe(); 312 private static final long FIELDS_OFFSET 313 = UNSAFE.objectFieldOffset(InetSocketAddress.class, "holder"); 314 315 /** 316 * Gets the port number. 317 * 318 * @return the port number. 319 */ 320 public final int getPort() { 321 return holder.getPort(); 322 } 323 324 /** 325 * Gets the {@code InetAddress}. 326 * 327 * @return the InetAddress or {@code null} if it is unresolved. 328 */ 329 public final InetAddress getAddress() { 330 return holder.getAddress(); 331 } 332 333 /** 334 * Gets the {@code hostname}. 335 * Note: This method may trigger a name service reverse lookup if the 336 * address was created with a literal IP address. 337 * 338 * @return the hostname part of the address. 339 */ 340 public final String getHostName() { 341 return holder.getHostName(); 342 } 343 344 /** 345 * Returns the hostname, or the String form of the address if it 346 * doesn't have a hostname (it was created using a literal). 347 * This has the benefit of <b>not</b> attempting a reverse lookup. 348 * 349 * @return the hostname, or String representation of the address. 350 * @since 1.7 351 */ 352 public final String getHostString() { 353 return holder.getHostString(); 354 } 355 356 /** 357 * Checks whether the address has been resolved or not. 358 * 359 * @return {@code true} if the hostname couldn't be resolved into 360 * an {@code InetAddress}. 361 */ 362 public final boolean isUnresolved() { 363 return holder.isUnresolved(); 364 } 365 366 /** 367 * Constructs a string representation of this InetSocketAddress. 368 * This String is constructed by calling toString() on the InetAddress 369 * and concatenating the port number (with a colon). If the address 370 * is unresolved then the part before the colon will only contain the hostname. 371 * 372 * @return a string representation of this object. 373 */ 374 @Override 375 public String toString() { 376 return holder.toString(); 377 } 378 379 /** 380 * Compares this object against the specified object. 381 * The result is {@code true} if and only if the argument is 382 * not {@code null} and it represents the same address as 383 * this object. 384 * <p> 385 * Two instances of {@code InetSocketAddress} represent the same 386 * address if both the InetAddresses (or hostnames if it is unresolved) and port 387 * numbers are equal. 388 * If both addresses are unresolved, then the hostname and the port number 389 * are compared. 390 * 391 * Note: Hostnames are case insensitive. e.g. "FooBar" and "foobar" are 392 * considered equal. 393 * 394 * @param obj the object to compare against. 395 * @return {@code true} if the objects are the same; 396 * {@code false} otherwise. 397 * @see java.net.InetAddress#equals(java.lang.Object) 398 */ 399 @Override 400 public final boolean equals(Object obj) { 401 if (obj == null || !(obj instanceof InetSocketAddress)) 402 return false; 403 return holder.equals(((InetSocketAddress) obj).holder); 404 } 405 406 /** 407 * Returns a hashcode for this socket address. 408 * 409 * @return a hash code value for this socket address. 410 */ 411 @Override 412 public final int hashCode() { 413 return holder.hashCode(); 414 } 415 }