提交 6759a406 编写于 作者: C chegar

7201071: InetSocketAddress serialization issue

Reviewed-by: alanb, michaelm, skoivu
上级 e5159366
/*
* 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 @@ 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;
}
/**
......@@ -97,14 +182,10 @@ public class InetSocketAddress extends SocketAddress {
* 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 SocketAddress {
* @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 SocketAddress {
* @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();
}
// Check that our invariants are satisfied
if (port < 0 || port > 0xFFFF) {
throw new InvalidObjectException("port out of range:" + port);
}
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);
if (hostname == null && addr == null) {
// 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);
}
}
......@@ -203,7 +321,7 @@ public class InetSocketAddress extends SocketAddress {
* @return the port number.
*/
public final int getPort() {
return port;
return holder.getPort();
}
/**
......@@ -213,7 +331,7 @@ public class InetSocketAddress extends SocketAddress {
* @return the InetAdress or <code>null</code> if it is unresolved.
*/
public final InetAddress getAddress() {
return addr;
return holder.getAddress();
}
/**
......@@ -224,31 +342,19 @@ public class InetSocketAddress extends SocketAddress {
* @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 @@ public class InetSocketAddress extends SocketAddress {
* an <code>InetAddress</code>.
*/
public final boolean isUnresolved() {
return addr == null;
return holder.isUnresolved();
}
/**
......@@ -269,12 +375,9 @@ public class InetSocketAddress extends SocketAddress {
*
* @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 @@ public class InetSocketAddress extends SocketAddress {
* <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 @@ public class InetSocketAddress extends SocketAddress {
*
* @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();
}
}
......@@ -421,7 +421,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");
......@@ -432,9 +432,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());
}
}
......@@ -454,7 +454,7 @@ class DatagramChannelImpl
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 @@ 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)
......@@ -502,7 +502,7 @@ class DatagramChannelImpl
}
private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
SocketAddress target)
InetSocketAddress target)
throws IOException
{
int pos = bb.position();
......@@ -514,7 +514,7 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 {
......
......@@ -1026,13 +1026,21 @@ public class SctpChannelImpl extends SctpChannel
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 @@ public class SctpChannelImpl extends SctpChannel
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,
......
......@@ -889,13 +889,20 @@ public class SctpMultiChannelImpl extends SctpMultiChannel
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 @@ public class SctpMultiChannelImpl extends SctpMultiChannel
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);
}
......
......@@ -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_initIDs(JNIEnv *env, jclass clazz)
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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
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;
......
......@@ -67,8 +67,6 @@ static jclass spc_class; /* sun.nio.ch.sctp.PeerAddressChanged */
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 @@ JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_initIDs
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 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_receive0
/*
* 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 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0
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) {
......
......@@ -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 @@ Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz)
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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
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,
......
......@@ -42,7 +42,7 @@ public class SendToUnresolved {
try {
dc.send(bb, sa);
throw new RuntimeException("Expected exception not thrown");
} catch (IOException e) {
} catch (IOException | UnresolvedAddressException e) {
// Correct result
}
dc.close();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册