jdk/src/share/classes/java/net/InetSocketAddress.java

Print this page
rev 5686 : 7201071: InetSocketAddress serialization issue
Reviewed-by: alanb, michaelm, skoivu

*** 1,7 **** /* ! * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 22,34 **** * or visit www.oracle.com if you need additional information or have any * questions. */ package java.net; - import java.io.ObjectInputStream; import java.io.IOException; import java.io.InvalidObjectException; /** * * This class implements an IP Socket Address (IP address + port number) * It can also be a pair (hostname + port number), in which case an attempt --- 22,37 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package java.net; import java.io.IOException; import java.io.InvalidObjectException; + import java.io.ObjectInputStream; + import java.io.ObjectOutputStream; + import java.io.ObjectStreamException; + import java.io.ObjectStreamField; /** * * This class implements an IP Socket Address (IP address + port number) * It can also be a pair (hostname + port number), in which case an attempt
*** 44,70 **** * * @see java.net.Socket * @see java.net.ServerSocket * @since 1.4 */ ! public class InetSocketAddress extends SocketAddress { ! /* The hostname of the Socket Address ! * @serial ! */ ! private String hostname = null; ! /* The IP address of the Socket Address ! * @serial ! */ ! private InetAddress addr = null; ! /* The port number of the Socket Address ! * @serial ! */ private int port; private static final long serialVersionUID = 5076001401234631237L; ! private InetSocketAddress() { } /** * Creates a socket address where the IP address is the wildcard address * and the port number a specified value. --- 47,155 ---- * * @see java.net.Socket * @see java.net.ServerSocket * @since 1.4 */ ! public class InetSocketAddress ! extends SocketAddress ! { ! // Private implementation class pointed to by all public methods. ! private static class InetSocketAddressHolder { ! // The hostname of the Socket Address ! private String hostname; ! // The IP address of the Socket Address ! private InetAddress addr; ! // The port number of the Socket Address private int port; + private InetSocketAddressHolder(String hostname, InetAddress addr, int port) { + this.hostname = hostname; + this.addr = addr; + this.port = port; + } + + private int getPort() { + return port; + } + + private InetAddress getAddress() { + return addr; + } + + private String getHostName() { + if (hostname != null) + return hostname; + if (addr != null) + return addr.getHostName(); + return null; + } + + private String getHostString() { + if (hostname != null) + return hostname; + if (addr != null) { + if (addr.hostName != null) + return addr.hostName; + else + return addr.getHostAddress(); + } + return null; + } + + private boolean isUnresolved() { + return addr == null; + } + + @Override + public String toString() { + if (isUnresolved()) { + return hostname + ":" + port; + } else { + return addr.toString() + ":" + port; + } + } + + @Override + public final boolean equals(Object obj) { + if (obj == null || !(obj instanceof InetSocketAddressHolder)) + return false; + InetSocketAddressHolder that = (InetSocketAddressHolder)obj; + boolean sameIP; + if (addr != null) + sameIP = addr.equals(that.addr); + else if (hostname != null) + sameIP = (that.addr == null) && + hostname.equalsIgnoreCase(that.hostname); + else + sameIP = (that.addr == null) && (that.hostname == null); + return sameIP && (port == that.port); + } + + @Override + public final int hashCode() { + if (addr != null) + return addr.hashCode() + port; + if (hostname != null) + return hostname.toLowerCase().hashCode() + port; + return port; + } + } + + private final transient InetSocketAddressHolder holder; + private static final long serialVersionUID = 5076001401234631237L; ! private static int checkPort(int port) { ! if (port < 0 || port > 0xFFFF) ! throw new IllegalArgumentException("port out of range:" + port); ! return port; ! } ! ! private static String checkHost(String hostname) { ! if (hostname == null) ! throw new IllegalArgumentException("hostname can't be null"); ! return hostname; } /** * Creates a socket address where the IP address is the wildcard address * and the port number a specified value.
*** 95,112 **** * @param port The port number * @throws IllegalArgumentException if the port parameter is outside the specified * range of valid port values. */ public InetSocketAddress(InetAddress addr, int port) { ! if (port < 0 || port > 0xFFFF) { ! throw new IllegalArgumentException("port out of range:" + port); ! } ! this.port = port; ! if (addr == null) ! this.addr = InetAddress.anyLocalAddress(); ! else ! this.addr = addr; } /** * * Creates a socket address from a hostname and a port number. --- 180,193 ---- * @param port The port number * @throws IllegalArgumentException if the port parameter is outside the specified * range of valid port values. */ public InetSocketAddress(InetAddress addr, int port) { ! holder = new InetSocketAddressHolder( ! null, ! addr == null ? InetAddress.anyLocalAddress() : addr, ! checkPort(port)); } /** * * Creates a socket address from a hostname and a port number.
*** 130,152 **** * permission to resolve the host name is * denied. * @see #isUnresolved() */ public InetSocketAddress(String hostname, int port) { ! if (port < 0 || port > 0xFFFF) { ! throw new IllegalArgumentException("port out of range:" + port); ! } ! if (hostname == null) { ! throw new IllegalArgumentException("hostname can't be null"); ! } try { addr = InetAddress.getByName(hostname); } catch(UnknownHostException e) { ! this.hostname = hostname; ! addr = null; } ! this.port = port; } /** * * Creates an unresolved socket address from a hostname and a port number. --- 211,234 ---- * permission to resolve the host name is * denied. * @see #isUnresolved() */ public InetSocketAddress(String hostname, int port) { ! checkHost(hostname); ! InetAddress addr = null; ! String host = null; try { addr = InetAddress.getByName(hostname); } catch(UnknownHostException e) { ! host = hostname; } ! holder = new InetSocketAddressHolder(host, addr, checkPort(port)); ! } ! ! // private constructor for creating unresolved instances ! private InetSocketAddress(int port, String hostname) { ! holder = new InetSocketAddressHolder(hostname, null, port); } /** * * Creates an unresolved socket address from a hostname and a port number.
*** 167,282 **** * @return a <code>InetSocketAddress</code> representing the unresolved * socket address * @since 1.5 */ public static InetSocketAddress createUnresolved(String host, int port) { ! if (port < 0 || port > 0xFFFF) { ! throw new IllegalArgumentException("port out of range:" + port); ! } ! if (host == null) { ! throw new IllegalArgumentException("hostname can't be null"); ! } ! InetSocketAddress s = new InetSocketAddress(); ! s.port = port; ! s.hostname = host; ! s.addr = null; ! return s; } ! private void readObject(ObjectInputStream s) ! throws IOException, ClassNotFoundException { ! s.defaultReadObject(); // Check that our invariants are satisfied ! if (port < 0 || port > 0xFFFF) { ! throw new InvalidObjectException("port out of range:" + port); ! } ! ! if (hostname == null && addr == null) { throw new InvalidObjectException("hostname and addr " + "can't both be null"); } } /** * Gets the port number. * * @return the port number. */ public final int getPort() { ! return port; } /** * * Gets the <code>InetAddress</code>. * * @return the InetAdress or <code>null</code> if it is unresolved. */ public final InetAddress getAddress() { ! return addr; } /** * Gets the <code>hostname</code>. * Note: This method may trigger a name service reverse lookup if the * address was created with a literal IP address. * * @return the hostname part of the address. */ public final String getHostName() { ! if (hostname != null) ! return hostname; ! if (addr != null) ! return addr.getHostName(); ! return null; } /** * Returns the hostname, or the String form of the address if it * doesn't have a hostname (it was created using a literal). ! * This has the benefit of <b>not</b> attemptimg a reverse lookup. * * @return the hostname, or String representation of the address. * @since 1.7 */ public final String getHostString() { ! if (hostname != null) ! return hostname; ! if (addr != null) { ! if (addr.hostName != null) ! return addr.hostName; ! else ! return addr.getHostAddress(); ! } ! return null; } /** * Checks whether the address has been resolved or not. * * @return <code>true</code> if the hostname couldn't be resolved into * an <code>InetAddress</code>. */ public final boolean isUnresolved() { ! return addr == null; } /** * Constructs a string representation of this InetSocketAddress. * This String is constructed by calling toString() on the InetAddress * and concatenating the port number (with a colon). If the address * is unresolved then the part before the colon will only contain the hostname. * * @return a string representation of this object. */ public String toString() { ! if (isUnresolved()) { ! return hostname + ":" + port; ! } else { ! return addr.toString() + ":" + port; ! } } /** * Compares this object against the specified object. * The result is <code>true</code> if and only if the argument is --- 249,385 ---- * @return a <code>InetSocketAddress</code> representing the unresolved * socket address * @since 1.5 */ public static InetSocketAddress createUnresolved(String host, int port) { ! return new InetSocketAddress(checkPort(port), checkHost(host)); } ! /** ! * @serialField hostname String ! * @serialField addr InetAddress ! * @serialField port int ! */ ! private static final ObjectStreamField[] serialPersistentFields = { ! new ObjectStreamField("hostname", String.class), ! new ObjectStreamField("addr", InetAddress.class), ! new ObjectStreamField("port", int.class)}; ! ! private void writeObject(ObjectOutputStream out) ! throws IOException ! { ! // Don't call defaultWriteObject() ! ObjectOutputStream.PutField pfields = out.putFields(); ! pfields.put("hostname", holder.hostname); ! pfields.put("addr", holder.addr); ! pfields.put("port", holder.port); ! out.writeFields(); ! } ! ! private void readObject(ObjectInputStream in) ! throws IOException, ClassNotFoundException ! { ! // Don't call defaultReadObject() ! ObjectInputStream.GetField oisFields = in.readFields(); ! final String oisHostname = (String)oisFields.get("hostname", null); ! final InetAddress oisAddr = (InetAddress)oisFields.get("addr", null); ! final int oisPort = oisFields.get("port", -1); // Check that our invariants are satisfied ! checkPort(oisPort); ! if (oisHostname == null && oisAddr == null) throw new InvalidObjectException("hostname and addr " + "can't both be null"); + + InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname, + oisAddr, + oisPort); + UNSAFE.putObject(this, FIELDS_OFFSET, h); + } + + private void readObjectNoData() + throws ObjectStreamException + { + throw new InvalidObjectException("Stream data required"); + } + + private static final long FIELDS_OFFSET; + private static final sun.misc.Unsafe UNSAFE; + static { + try { + sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe(); + FIELDS_OFFSET = unsafe.objectFieldOffset( + InetSocketAddress.class.getDeclaredField("holder")); + UNSAFE = unsafe; + } catch (ReflectiveOperationException e) { + throw new Error(e); } } /** * Gets the port number. * * @return the port number. */ public final int getPort() { ! return holder.getPort(); } /** * * Gets the <code>InetAddress</code>. * * @return the InetAdress or <code>null</code> if it is unresolved. */ public final InetAddress getAddress() { ! return holder.getAddress(); } /** * Gets the <code>hostname</code>. * Note: This method may trigger a name service reverse lookup if the * address was created with a literal IP address. * * @return the hostname part of the address. */ public final String getHostName() { ! return holder.getHostName(); } /** * Returns the hostname, or the String form of the address if it * doesn't have a hostname (it was created using a literal). ! * This has the benefit of <b>not</b> attempting a reverse lookup. * * @return the hostname, or String representation of the address. * @since 1.7 */ public final String getHostString() { ! return holder.getHostString(); } /** * Checks whether the address has been resolved or not. * * @return <code>true</code> if the hostname couldn't be resolved into * an <code>InetAddress</code>. */ public final boolean isUnresolved() { ! return holder.isUnresolved(); } /** * Constructs a string representation of this InetSocketAddress. * This String is constructed by calling toString() on the InetAddress * and concatenating the port number (with a colon). If the address * is unresolved then the part before the colon will only contain the hostname. * * @return a string representation of this object. */ + @Override public String toString() { ! return holder.toString(); } /** * Compares this object against the specified object. * The result is <code>true</code> if and only if the argument is
*** 295,327 **** * @param obj the object to compare against. * @return <code>true</code> if the objects are the same; * <code>false</code> otherwise. * @see java.net.InetAddress#equals(java.lang.Object) */ public final boolean equals(Object obj) { if (obj == null || !(obj instanceof InetSocketAddress)) return false; ! InetSocketAddress sockAddr = (InetSocketAddress) obj; ! boolean sameIP = false; ! if (this.addr != null) ! sameIP = this.addr.equals(sockAddr.addr); ! else if (this.hostname != null) ! sameIP = (sockAddr.addr == null) && ! this.hostname.equalsIgnoreCase(sockAddr.hostname); ! else ! sameIP = (sockAddr.addr == null) && (sockAddr.hostname == null); ! return sameIP && (this.port == sockAddr.port); } /** * Returns a hashcode for this socket address. * * @return a hash code value for this socket address. */ public final int hashCode() { ! if (addr != null) ! return addr.hashCode() + port; ! if (hostname != null) ! return hostname.toLowerCase().hashCode() + port; ! return port; } } --- 398,419 ---- * @param obj the object to compare against. * @return <code>true</code> if the objects are the same; * <code>false</code> otherwise. * @see java.net.InetAddress#equals(java.lang.Object) */ + @Override public final boolean equals(Object obj) { if (obj == null || !(obj instanceof InetSocketAddress)) return false; ! return holder.equals(((InetSocketAddress) obj).holder); } /** * Returns a hashcode for this socket address. * * @return a hash code value for this socket address. */ + @Override public final int hashCode() { ! return holder.hashCode(); } }