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