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