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