--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Sun Aug 31 18:32:59 2008 +0100
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Sun Aug 31 18:39:01 2008 +0100
@@ -31,6 +31,7 @@
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
+import java.util.*;
/**
@@ -78,19 +79,16 @@
private int state = ST_UNINITIALIZED;
// Binding
- private SocketAddress localAddress = null;
- private SocketAddress remoteAddress = null;
+ private SocketAddress localAddress;
+ private SocketAddress remoteAddress;
// Input/Output open
private boolean isInputOpen = true;
private boolean isOutputOpen = true;
private boolean readyToConnect = false;
- // Options, created on demand
- private SocketOpts.IP.TCP options = null;
-
// Socket adaptor, created on demand
- private Socket socket = null;
+ private Socket socket;
// -- End of fields protected by stateLock
@@ -114,6 +112,7 @@
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_CONNECTED;
+ this.localAddress = Net.localAddress(fd);
this.remoteAddress = remote;
}
@@ -125,6 +124,98 @@
}
}
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ synchronized (stateLock) {
+ if (!isOpen())
+ return null;
+ return localAddress;
+ }
+ }
+
+ @Override
+ public SocketAddress getConnectedAddress() throws IOException {
+ synchronized (stateLock) {
+ if (!isOpen())
+ return null;
+ return remoteAddress;
+ }
+ }
+
+ @Override
+ public SocketChannel setOption(SocketOption name, Object value)
+ throws IOException
+ {
+ if (name == null)
+ throw new NullPointerException();
+ if (!options().contains(name))
+ throw new IllegalArgumentException("Invalid option name");
+
+ synchronized (stateLock) {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ // special handling for IP_TOS: no-op when IPv6
+ if (name == StandardSocketOption.IP_TOS) {
+ if (!Net.isIPv6Available())
+ Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value);
+ return this;
+ }
+
+ // no options that require special handling
+ Net.setSocketOption(fd, Net.UNSPEC, name, value);
+ return this;
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getOption(SocketOption<T> name)
+ throws IOException
+ {
+ if (name == null)
+ throw new NullPointerException();
+ if (!options().contains(name))
+ throw new IllegalArgumentException("Invalid option name");
+
+ synchronized (stateLock) {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ // special handling for IP_TOS: always return 0 when IPv6
+ if (name == StandardSocketOption.IP_TOS) {
+ return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) :
+ (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name);
+ }
+
+ // no options that require special handling
+ return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+ }
+ }
+
+ private static class LazyInitialization {
+ static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+ private static Set<SocketOption<?>> defaultOptions() {
+ HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
+ set.add(StandardSocketOption.SO_SNDBUF);
+ set.add(StandardSocketOption.SO_RCVBUF);
+ set.add(StandardSocketOption.SO_KEEPALIVE);
+ set.add(StandardSocketOption.SO_REUSEADDR);
+ set.add(StandardSocketOption.SO_LINGER);
+ set.add(StandardSocketOption.TCP_NODELAY);
+ // additional options required by socket adaptor
+ set.add(StandardSocketOption.IP_TOS);
+ set.add(ExtendedSocketOption.SO_OOBINLINE);
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ @Override
+ public final Set<SocketOption<?>> options() {
+ return LazyInitialization.defaultOptions;
+ }
+
private boolean ensureReadOpen() throws ClosedChannelException {
synchronized (stateLock) {
if (!isOpen())
@@ -410,43 +501,8 @@
IOUtil.configureBlocking(fd, block);
}
- public SocketOpts options() {
- synchronized (stateLock) {
- if (options == null) {
- SocketOptsImpl.Dispatcher d
- = new SocketOptsImpl.Dispatcher() {
- int getInt(int opt) throws IOException {
- return Net.getIntOption(fd, opt);
- }
- void setInt(int opt, int arg)
- throws IOException
- {
- Net.setIntOption(fd, opt, arg);
- }
- };
- options = new SocketOptsImpl.IP.TCP(d);
- }
- return options;
- }
- }
-
- public boolean isBound() {
- synchronized (stateLock) {
- if (state == ST_CONNECTED)
- return true;
- return localAddress != null;
- }
- }
-
public SocketAddress localAddress() {
synchronized (stateLock) {
- if (state == ST_CONNECTED &&
- (localAddress == null ||
- ((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress())) {
- // Socket was not bound before connecting or
- // Socket was bound with an "anyLocalAddress"
- localAddress = Net.localAddress(fd);
- }
return localAddress;
}
}
@@ -457,19 +513,25 @@
}
}
- public void bind(SocketAddress local) throws IOException {
+ @Override
+ public SocketChannel bind(SocketAddress local) throws IOException {
synchronized (readLock) {
synchronized (writeLock) {
synchronized (stateLock) {
- ensureOpenAndUnconnected();
+ if (!isOpen())
+ throw new ClosedChannelException();
+ if (state == ST_PENDING)
+ throw new ConnectionPendingException();
if (localAddress != null)
throw new AlreadyBoundException();
- InetSocketAddress isa = Net.checkAddress(local);
+ InetSocketAddress isa = (local == null) ?
+ new InetSocketAddress(0) : Net.checkAddress(local);
Net.bind(fd, isa.getAddress(), isa.getPort());
localAddress = Net.localAddress(fd);
}
}
}
+ return this;
}
public boolean isConnected() {
@@ -496,7 +558,6 @@
}
public boolean connect(SocketAddress sa) throws IOException {
- int trafficClass = 0; // ## Pick up from options
int localPort = 0;
synchronized (readLock) {
@@ -524,13 +585,24 @@
ia = InetAddress.getLocalHost();
n = Net.connect(fd,
ia,
- isa.getPort(),
- trafficClass);
+ isa.getPort());
if ( (n == IOStatus.INTERRUPTED)
&& isOpen())
continue;
break;
}
+
+ synchronized (stateLock) {
+ if (isOpen() && (localAddress == null) ||
+ ((InetSocketAddress)localAddress)
+ .getAddress().isAnyLocalAddress())
+ {
+ // Socket was not bound before connecting or
+ // Socket was bound with an "anyLocalAddress"
+ localAddress = Net.localAddress(fd);
+ }
+ }
+
} finally {
readerCleanup();
end((n > 0) || (n == IOStatus.UNAVAILABLE));
@@ -646,29 +718,37 @@
}
}
- public final static int SHUT_RD = 0;
- public final static int SHUT_WR = 1;
- public final static int SHUT_RDWR = 2;
-
- public void shutdownInput() throws IOException {
+ @Override
+ public SocketChannel shutdownInput() throws IOException {
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
- isInputOpen = false;
- shutdown(fd, SHUT_RD);
- if (readerThread != 0)
- NativeThread.signal(readerThread);
+ if (!isConnected())
+ throw new NotYetConnectedException();
+ if (isInputOpen) {
+ Net.shutdown(fd, Net.SHUT_RD);
+ if (readerThread != 0)
+ NativeThread.signal(readerThread);
+ isInputOpen = false;
+ }
+ return this;
}
}
- public void shutdownOutput() throws IOException {
+ @Override
+ public SocketChannel shutdownOutput() throws IOException {
synchronized (stateLock) {
if (!isOpen())
throw new ClosedChannelException();
- isOutputOpen = false;
- shutdown(fd, SHUT_WR);
- if (writerThread != 0)
- NativeThread.signal(writerThread);
+ if (!isConnected())
+ throw new NotYetConnectedException();
+ if (isOutputOpen) {
+ Net.shutdown(fd, Net.SHUT_WR);
+ if (writerThread != 0)
+ NativeThread.signal(writerThread);
+ isOutputOpen = false;
+ }
+ return this;
}
}
@@ -869,9 +949,6 @@
boolean block, boolean ready)
throws IOException;
- private static native void shutdown(FileDescriptor fd, int how)
- throws IOException;
-
static {
Util.load();
nd = new SocketDispatcher();