# HG changeset patch # User robm # Date 1352819613 0 # Node ID 46582c3c96b3fdd43b58761c3869ce55fad1c755 # Parent ee4632a30696050ebd5c014fb3da64112ab48dd3 7201071: InetSocketAddress serialization issue Reviewed-by: chegar diff --git a/src/share/classes/java/net/InetSocketAddress.java b/src/share/classes/java/net/InetSocketAddress.java --- jdk/src/share/classes/java/net/InetSocketAddress.java +++ jdk/src/share/classes/java/net/InetSocketAddress.java @@ -24,9 +24,12 @@ */ package java.net; -import java.io.ObjectInputStream; import java.io.IOException; import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.ObjectStreamField; /** * @@ -46,24 +49,106 @@ import java.io.InvalidObjectException; * @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; +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 InetSocketAddress() { + 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 @@ -97,14 +182,10 @@ public class InetSocketAddress extends S * 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; + holder = new InetSocketAddressHolder( + null, + addr == null ? InetAddress.anyLocalAddress() : addr, + checkPort(port)); } /** @@ -132,19 +213,20 @@ public class InetSocketAddress extends S * @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"); - } + checkHost(hostname); + InetAddress addr = null; + String host = null; try { addr = InetAddress.getByName(hostname); } catch(UnknownHostException e) { - this.hostname = hostname; - addr = null; + host = hostname; } - this.port = port; + 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); } /** @@ -169,31 +251,67 @@ public class InetSocketAddress extends S * @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; + 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 s) - throws IOException, ClassNotFoundException { - s.defaultReadObject(); + 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 - if (port < 0 || port > 0xFFFF) { - throw new InvalidObjectException("port out of range:" + port); - } - - if (hostname == null && addr == null) { + 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 (NoSuchFieldException e) { + throw new Error(e); } } @@ -203,7 +321,7 @@ public class InetSocketAddress extends S * @return the port number. */ public final int getPort() { - return port; + return holder.getPort(); } /** @@ -213,7 +331,7 @@ public class InetSocketAddress extends S * @return the InetAdress or null if it is unresolved. */ public final InetAddress getAddress() { - return addr; + return holder.getAddress(); } /** @@ -222,11 +340,7 @@ public class InetSocketAddress extends S * @return the hostname part of the address. */ public final String getHostName() { - if (hostname != null) - return hostname; - if (addr != null) - return addr.getHostName(); - return null; + return holder.getHostName(); } /** @@ -238,15 +352,7 @@ public class InetSocketAddress extends S * @since 1.6 */ final String getHostString() { - if (hostname != null) - return hostname; - if (addr != null) { - if (addr.hostName != null) - return addr.hostName; - else - return addr.getHostAddress(); - } - return null; + return holder.getHostString(); } /** @@ -256,7 +362,7 @@ public class InetSocketAddress extends S * an InetAddress. */ public final boolean isUnresolved() { - return addr == null; + return holder.isUnresolved(); } /** @@ -267,12 +373,9 @@ public class InetSocketAddress extends S * * @return a string representation of this object. */ + @Override public String toString() { - if (isUnresolved()) { - return hostname + ":" + port; - } else { - return addr.toString() + ":" + port; - } + return holder.toString(); } /** @@ -295,16 +398,7 @@ public class InetSocketAddress extends S 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.equals(sockAddr.hostname); - else - sameIP = (sockAddr.addr == null) && (sockAddr.hostname == null); - return sameIP && (this.port == sockAddr.port); + return holder.equals(((InetSocketAddress) obj).holder); } /** @@ -312,11 +406,8 @@ public class InetSocketAddress extends S * * @return a hash code value for this socket address. */ + @Override public final int hashCode() { - if (addr != null) - return addr.hashCode() + port; - if (hostname != null) - return hostname.hashCode() + port; - return port; + return holder.hashCode(); } } diff --git a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java --- jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -239,7 +239,7 @@ class DatagramChannelImpl synchronized (writeLock) { ensureOpen(); - InetSocketAddress isa = (InetSocketAddress)target; + InetSocketAddress isa = Net.checkAddress(target); InetAddress ia = isa.getAddress(); if (ia == null) throw new IOException("Target address not resolved"); @@ -250,9 +250,9 @@ class DatagramChannelImpl SecurityManager sm = System.getSecurityManager(); if (sm != null) { if (ia.isMulticastAddress()) { - sm.checkMulticast(isa.getAddress()); + sm.checkMulticast(ia); } else { - sm.checkConnect(isa.getAddress().getHostAddress(), + sm.checkConnect(ia.getHostAddress(), isa.getPort()); } } @@ -272,7 +272,7 @@ class DatagramChannelImpl return 0; writerThread = NativeThread.current(); do { - n = send(fd, src, target); + n = send(fd, src, isa); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -283,7 +283,7 @@ class DatagramChannelImpl } } - private int send(FileDescriptor fd, ByteBuffer src, SocketAddress target) + private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target) throws IOException { if (src instanceof DirectBuffer) @@ -315,7 +315,7 @@ class DatagramChannelImpl } private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb, - SocketAddress target) + InetSocketAddress target) throws IOException { int pos = bb.position(); @@ -324,7 +324,7 @@ class DatagramChannelImpl int rem = (pos <= lim ? lim - pos : 0); int written = send0(fd, ((DirectBuffer)bb).address() + pos, - rem, target); + rem, target.getAddress(), target.getPort()); if (written > 0) bb.position(pos + written); return written; @@ -703,8 +703,8 @@ class DatagramChannelImpl boolean connected) throws IOException; - private native int send0(FileDescriptor fd, long address, int len, - SocketAddress sa) + private native int send0(FileDescriptor fd, long address, + int len, InetAddress addr, int port) throws IOException; static { diff --git a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c --- jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c +++ jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c @@ -46,8 +46,6 @@ #include "sun_nio_ch_DatagramChannelImpl.h" -static jfieldID isa_addrID; /* address in java.net.InetSocketAddress */ -static jfieldID isa_portID; /* port in java.net.InetSocketAddress */ static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ @@ -61,9 +59,6 @@ Java_sun_nio_ch_DatagramChannelImpl_init isa_class = (*env)->NewGlobalRef(env, clazz); isa_ctorID = (*env)->GetMethodID(env, clazz, "", "(Ljava/net/InetAddress;I)V"); - isa_addrID = (*env)->GetFieldID(env, clazz, "addr", - "Ljava/net/InetAddress;"); - isa_portID = (*env)->GetFieldID(env, clazz, "port", "I"); clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl"); dci_senderID = (*env)->GetFieldID(env, clazz, "sender", @@ -198,16 +193,15 @@ Java_sun_nio_ch_DatagramChannelImpl_rece JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, - jobject fdo, jlong address, - jint len, jobject dest) + jobject fdo, jlong address, + jint len, jobject destAddress, + jint destPort) { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); SOCKADDR sa; int sa_len = SOCKADDR_LEN; jint n = 0; - jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID); - jint destPort = (*env)->GetIntField(env, dest, isa_portID); if (len > MAX_PACKET_LEN) { len = MAX_PACKET_LEN; diff --git a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c --- jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c +++ jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c @@ -34,8 +34,6 @@ #include "net_util.h" #include -static jfieldID isa_addrID; /* address in java.net.InetSocketAddress */ -static jfieldID isa_portID; /* port in java.net.InetSocketAddress */ static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */ static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */ @@ -87,9 +85,6 @@ Java_sun_nio_ch_DatagramChannelImpl_init isa_class = (*env)->NewGlobalRef(env, clazz); isa_ctorID = (*env)->GetMethodID(env, clazz, "", "(Ljava/net/InetAddress;I)V"); - isa_addrID = (*env)->GetFieldID(env, clazz, "addr", - "Ljava/net/InetAddress;"); - isa_portID = (*env)->GetFieldID(env, clazz, "port", "I"); clazz = (*env)->FindClass(env, "sun/nio/ch/DatagramChannelImpl"); dci_senderID = (*env)->GetFieldID(env, clazz, "sender", @@ -268,17 +263,14 @@ Java_sun_nio_ch_DatagramChannelImpl_rece JNIEXPORT jint JNICALL Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this, - jobject fdo, jlong address, - jint len, jobject dest) + jobject fdo, jlong address, jint len, + jobject destAddress, jint destPort) { jint fd = fdval(env, fdo); void *buf = (void *)jlong_to_ptr(address); SOCKETADDRESS psa; int sa_len = sizeof(psa); jint rv = 0; - jobject destAddress = (*env)->GetObjectField(env, dest, isa_addrID); - jint destPort = (*env)->GetIntField(env, dest, isa_portID); - if (NET_InetAddressToSockaddr(env, destAddress, destPort, (struct sockaddr *)&psa, diff --git a/test/java/nio/channels/DatagramChannel/SendToUnresolved.java b/test/java/nio/channels/DatagramChannel/SendToUnresolved.java --- jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java +++ jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java @@ -44,6 +44,8 @@ public class SendToUnresolved { throw new RuntimeException("Expected exception not thrown"); } catch (IOException e) { // Correct result + } catch (UnresolvedAddressException e) { + // Correct result } dc.close(); }