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