7201071: InetSocketAddress serialization issue
Reviewed-by: alanb, michaelm, skoivu
--- a/jdk/src/share/classes/java/net/InetSocketAddress.java Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/share/classes/java/net/InetSocketAddress.java Wed Nov 07 14:26:41 2012 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -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,23 +49,105 @@
* @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;
}
/**
@@ -97,14 +182,10 @@
* 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 @@
* @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 @@
* @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));
}
- private void readObject(ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- s.defaultReadObject();
+ /**
+ * @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
- 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 (ReflectiveOperationException e) {
+ throw new Error(e);
}
}
@@ -203,7 +321,7 @@
* @return the port number.
*/
public final int getPort() {
- return port;
+ return holder.getPort();
}
/**
@@ -213,7 +331,7 @@
* @return the InetAdress or <code>null</code> if it is unresolved.
*/
public final InetAddress getAddress() {
- return addr;
+ return holder.getAddress();
}
/**
@@ -224,31 +342,19 @@
* @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();
}
/**
* 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.
+ * 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() {
- if (hostname != null)
- return hostname;
- if (addr != null) {
- if (addr.hostName != null)
- return addr.hostName;
- else
- return addr.getHostAddress();
- }
- return null;
+ return holder.getHostString();
}
/**
@@ -258,7 +364,7 @@
* an <code>InetAddress</code>.
*/
public final boolean isUnresolved() {
- return addr == null;
+ return holder.isUnresolved();
}
/**
@@ -269,12 +375,9 @@
*
* @return a string representation of this object.
*/
+ @Override
public String toString() {
- if (isUnresolved()) {
- return hostname + ":" + port;
- } else {
- return addr.toString() + ":" + port;
- }
+ return holder.toString();
}
/**
@@ -297,19 +400,11 @@
* <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;
- 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);
+ return holder.equals(((InetSocketAddress) obj).holder);
}
/**
@@ -317,11 +412,8 @@
*
* @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.toLowerCase().hashCode() + port;
- return port;
+ return holder.hashCode();
}
}
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Wed Nov 07 14:26:41 2012 +0000
@@ -421,7 +421,7 @@
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");
@@ -432,9 +432,9 @@
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());
}
}
@@ -454,7 +454,7 @@
return 0;
writerThread = NativeThread.current();
do {
- n = send(fd, src, target);
+ n = send(fd, src, isa);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
synchronized (stateLock) {
@@ -471,7 +471,7 @@
}
}
- private int send(FileDescriptor fd, ByteBuffer src, SocketAddress target)
+ private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
throws IOException
{
if (src instanceof DirectBuffer)
@@ -502,7 +502,7 @@
}
private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
- SocketAddress target)
+ InetSocketAddress target)
throws IOException
{
int pos = bb.position();
@@ -514,7 +514,7 @@
int written;
try {
written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
- rem, target);
+ rem, target.getAddress(), target.getPort());
} catch (PortUnreachableException pue) {
if (isConnected())
throw pue;
@@ -1116,8 +1116,8 @@
boolean connected)
throws IOException;
- private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len,
- SocketAddress sa)
+ private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
+ int len, InetAddress addr, int port)
throws IOException;
static {
--- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpChannelImpl.java Wed Nov 07 14:26:41 2012 +0000
@@ -1026,13 +1026,21 @@
boolean unordered,
int ppid)
throws IOException {
+ InetAddress addr = null; // no preferred address
+ int port = 0;
+ if (target != null) {
+ InetSocketAddress isa = Net.checkAddress(target);
+ addr = isa.getAddress();
+ port = isa.getPort();
+ }
+
int pos = bb.position();
int lim = bb.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
- int written = send0(fd, ((DirectBuffer)bb).address() + pos,
- rem, target, -1 /*121*/, streamNumber, unordered, ppid);
+ int written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, addr,
+ port, -1 /*121*/, streamNumber, unordered, ppid);
if (written > 0)
bb.position(pos + written);
return written;
@@ -1091,7 +1099,7 @@
long address, int length, boolean peek) throws IOException;
static native int send0(int fd, long address, int length,
- SocketAddress target, int assocId, int streamNumber,
+ InetAddress addr, int port, int assocId, int streamNumber,
boolean unordered, int ppid) throws IOException;
private static native int checkConnect(FileDescriptor fd, boolean block,
--- a/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/solaris/classes/sun/nio/ch/sctp/SctpMultiChannelImpl.java Wed Nov 07 14:26:41 2012 +0000
@@ -889,13 +889,20 @@
boolean unordered,
int ppid)
throws IOException {
+ InetAddress addr = null; // no preferred address
+ int port = 0;
+ if (target != null) {
+ InetSocketAddress isa = Net.checkAddress(target);
+ addr = isa.getAddress();
+ port = isa.getPort();
+ }
int pos = bb.position();
int lim = bb.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
- int written = send0(fd, ((DirectBuffer)bb).address() + pos,
- rem, target, assocId, streamNumber, unordered, ppid);
+ int written = send0(fd, ((DirectBuffer)bb).address() + pos, rem, addr,
+ port, assocId, streamNumber, unordered, ppid);
if (written > 0)
bb.position(pos + written);
return written;
@@ -976,13 +983,14 @@
private static int send0(int fd,
long address,
int length,
- SocketAddress target,
+ InetAddress addr,
+ int port,
int assocId,
int streamNumber,
boolean unordered,
int ppid)
throws IOException {
- return SctpChannelImpl.send0(fd, address, length, target, assocId,
+ return SctpChannelImpl.send0(fd, address, length, addr, port, assocId,
streamNumber, unordered, ppid);
}
--- a/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c Wed Nov 07 14:26:41 2012 +0000
@@ -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 @@
isa_class = (*env)->NewGlobalRef(env, clazz);
isa_ctorID = (*env)->GetMethodID(env, clazz, "<init>",
"(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",
@@ -212,15 +207,13 @@
JNIEXPORT jint JNICALL
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
jboolean preferIPv6, jobject fdo, jlong address,
- jint len, jobject dest)
+ 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;
--- a/jdk/src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c Wed Nov 07 14:26:41 2012 +0000
@@ -67,8 +67,6 @@
static jmethodID spc_ctrID; /* sun.nio.ch.sctp.PeerAddressChanged.<init> */
static jclass ss_class; /* sun.nio.ch.sctp.Shutdown */
static jmethodID ss_ctrID; /* sun.nio.ch.sctp.Shutdown.<init> */
-static jfieldID isa_addrID; /* java.net.InetSocketAddress.addr */
-static jfieldID isa_portID; /* java.net.InetSocketAddress.port */
/* defined in SctpNet.c */
jobject SockAddrToInetSocketAddress(JNIEnv* env, struct sockaddr* addr);
@@ -138,13 +136,6 @@
CHECK_NULL(ss_class);
ss_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(I)V");
CHECK_NULL(ss_ctrID);
-
- /* InetSocketAddress */
- cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
- CHECK_NULL(cls);
- isa_addrID = (*env)->GetFieldID(env, cls, "addr", "Ljava/net/InetAddress;");
- CHECK_NULL(isa_addrID);
- isa_portID = (*env)->GetFieldID(env, cls, "port", "I");
}
void getControlData
@@ -509,12 +500,12 @@
/*
* Class: sun_nio_ch_sctp_SctpChannelImpl
* Method: send0
- * Signature: (IJILjava/net/SocketAddress;IIZI)I
+ * Signature: (IJILjava/net/InetAddress;IIIZI)I
*/
JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0
(JNIEnv *env, jclass klass, jint fd, jlong address, jint length,
- jobject saTarget, jint assocId, jint streamNumber, jboolean unordered,
- jint ppid) {
+ jobject targetAddress, jint targetPort, jint assocId, jint streamNumber,
+ jboolean unordered, jint ppid) {
SOCKADDR sa;
int sa_len = sizeof(sa);
ssize_t rv = 0;
@@ -526,17 +517,13 @@
struct controlData cdata[1];
/* SctpChannel:
- * saTarget may contain the preferred address or NULL to use primary,
+ * targetAddress may contain the preferred address or NULL to use primary,
* assocId will always be -1
* SctpMultiChannell:
- * Setup new association, saTarget will contain address, assocId = -1
- * Association already existing, assocId != -1, saTarget = preferred addr
+ * Setup new association, targetAddress will contain address, assocId = -1
+ * Association already existing, assocId != -1, targetAddress = preferred addr
*/
- if (saTarget != NULL /*&& assocId <= 0*/) {
-
- jobject targetAddress = (*env)->GetObjectField(env, saTarget, isa_addrID);
- jint targetPort = (*env)->GetIntField(env, saTarget, isa_portID);
-
+ if (targetAddress != NULL /*&& assocId <= 0*/) {
if (NET_InetAddressToSockaddr(env, targetAddress, targetPort,
(struct sockaddr *)&sa,
&sa_len, JNI_TRUE) != 0) {
--- a/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c Wed Nov 07 14:26:41 2012 +0000
@@ -34,8 +34,6 @@
#include "net_util.h"
#include <winsock2.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 */
@@ -50,9 +48,6 @@
isa_class = (*env)->NewGlobalRef(env, clazz);
isa_ctorID = (*env)->GetMethodID(env, clazz, "<init>",
"(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",
@@ -214,15 +209,14 @@
JNIEXPORT jint JNICALL
Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
jboolean preferIPv6, jobject fdo,
- jlong address, jint len, jobject dest)
+ jlong address, jint len,
+ jobject destAddress, jint destPort)
{
jint fd = fdval(env, fdo);
void *buf = (void *)jlong_to_ptr(address);
SOCKETADDRESS sa;
int sa_len;
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 *)&sa,
--- a/jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java Tue Nov 06 15:30:34 2012 +0400
+++ b/jdk/test/java/nio/channels/DatagramChannel/SendToUnresolved.java Wed Nov 07 14:26:41 2012 +0000
@@ -42,7 +42,7 @@
try {
dc.send(bb, sa);
throw new RuntimeException("Expected exception not thrown");
- } catch (IOException e) {
+ } catch (IOException | UnresolvedAddressException e) {
// Correct result
}
dc.close();