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