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();
}
}