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