diff --git a/make/java/net/FILES_c.gmk b/make/java/net/FILES_c.gmk
index 2eb4daa2cbb689344b059c77dba87dbba965266c..0e638816d1046fe39d3b06af5e9a60d70f7a9a71 100644
--- a/make/java/net/FILES_c.gmk
+++ b/make/java/net/FILES_c.gmk
@@ -39,6 +39,10 @@ FILES_c = \
ResolverConfigurationImpl.c \
DefaultProxySelector.c
+ifeq ($(PLATFORM), solaris)
+ FILES_c += SdpProvider.c
+endif
+
ifeq ($(PLATFORM), linux)
FILES_c += linux_close.c
endif
diff --git a/make/java/net/Makefile b/make/java/net/Makefile
index b9a3defdb8ccae2429ade7227b77a2816bf6ac2f..203b059a3888e9514395af9d135f6a34fe401e63 100644
--- a/make/java/net/Makefile
+++ b/make/java/net/Makefile
@@ -108,11 +108,24 @@ CLASSES.export += java.lang.Integer java.io.FileDescriptor java.net.InetAddressI
#
LOCALE_SET_DEFINITION = jre
-properties: $(LIBDIR) $(LIBDIR)/net.properties
+MISC_FILES = $(LIBDIR) $(LIBDIR)/net.properties
$(LIBDIR)/net.properties: $(SHARE_SRC)/lib/net.properties
@$(RM) $@
$(CP) $< $@
-build: properties
+#
+# SDP configuration template
+#
+ifeq ($(PLATFORM), solaris)
+SDP_PATH = sdp/sdp.conf.template
+SDP_CONF = $(LIBDIR)/$(SDP_PATH)
+$(SDP_CONF): $(PLATFORM_SRC)/lib/$(SDP_PATH)
+ @$(RM) $*
+ $(install-file)
+
+MISC_FILES += $(SDP_CONF)
+endif
+
+build: $(MISC_FILES)
diff --git a/make/java/net/mapfile-vers b/make/java/net/mapfile-vers
index d9803f8f9446c5d5d891aeffaafb43e0c3b1f558..c30803cbfefb9806840a7d5a79ba6039e5588d80 100644
--- a/make/java/net/mapfile-vers
+++ b/make/java/net/mapfile-vers
@@ -90,6 +90,7 @@ SUNWprivate_1.1 {
Java_sun_net_dns_ResolverConfigurationImpl_fallbackDomain0;
Java_sun_net_spi_DefaultProxySelector_init;
Java_sun_net_spi_DefaultProxySelector_getSystemProxy;
+ Java_sun_net_spi_SdpProvider_convert;
NET_AllocSockaddr;
NET_SockaddrToInetAddress;
NET_SockaddrEqualsInetAddress;
diff --git a/make/sun/net/FILES_java.gmk b/make/sun/net/FILES_java.gmk
index 55b6477fc26711e460bb82b9d3b7bd5cde767981..1ab771a37f10cbb53414f4d8ea8356e135fc776f 100644
--- a/make/sun/net/FILES_java.gmk
+++ b/make/sun/net/FILES_java.gmk
@@ -39,6 +39,7 @@ FILES_java = \
sun/net/TransferProtocolClient.java \
sun/net/ConnectionResetException.java \
sun/net/NetProperties.java \
+ sun/net/NetHooks.java \
sun/net/util/IPAddressUtil.java \
sun/net/dns/ResolverConfiguration.java \
sun/net/dns/ResolverConfigurationImpl.java \
@@ -123,3 +124,7 @@ FILES_java = \
ifeq ($(PLATFORM), windows)
FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java
endif
+
+ifeq ($(PLATFORM), solaris)
+ FILES_java += sun/net/spi/SdpProvider.java
+endif
diff --git a/src/share/classes/java/net/AbstractPlainSocketImpl.java b/src/share/classes/java/net/AbstractPlainSocketImpl.java
index 597783bf730628fcf39cac13680ade28120e4e82..18af8d6db64b67b3cc05e409c2383f8bc1976d12 100644
--- a/src/share/classes/java/net/AbstractPlainSocketImpl.java
+++ b/src/share/classes/java/net/AbstractPlainSocketImpl.java
@@ -33,6 +33,7 @@ import java.io.FileDescriptor;
import java.io.ByteArrayOutputStream;
import sun.net.ConnectionResetException;
+import sun.net.NetHooks;
/**
* Default Socket Implementation. This implementation does
@@ -304,6 +305,11 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
*/
synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
+ synchronized (fdLock) {
+ if (!closePending && (socket == null || !socket.isBound())) {
+ NetHooks.beforeTcpConnect(fd, address, port);
+ }
+ }
try {
FileDescriptor fd = acquireFD();
try {
@@ -339,6 +345,11 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
protected synchronized void bind(InetAddress address, int lport)
throws IOException
{
+ synchronized (fdLock) {
+ if (!closePending && (socket == null || !socket.isBound())) {
+ NetHooks.beforeTcpBind(fd, address, lport);
+ }
+ }
socketBind(address, lport);
if (socket != null)
socket.setBound();
diff --git a/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
index b4fcb9c2c30b12ddb0c8979c29d2c744d50f3f26..492319301590ea115c0540502ea56d5e4888b97d 100644
--- a/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
@@ -37,6 +37,7 @@ import java.util.HashSet;
import java.util.Collections;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import sun.net.NetHooks;
/**
* Base implementation of AsynchronousServerSocketChannel.
@@ -131,6 +132,7 @@ abstract class AsynchronousServerSocketChannelImpl
synchronized (stateLock) {
if (localAddress != null)
throw new AlreadyBoundException();
+ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
localAddress = Net.localAddress(fd);
diff --git a/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
index 09637fbae1bd1b93156ee7a81c5005b7a7090aca..84b81a0c8b0bf93f0b0e13826b0259f9e5f3791a 100644
--- a/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
@@ -38,6 +38,7 @@ import java.util.HashSet;
import java.util.Collections;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
+import sun.net.NetHooks;
/**
* Base implementation of AsynchronousSocketChannel
@@ -387,6 +388,7 @@ abstract class AsynchronousSocketChannelImpl
throw new AlreadyBoundException();
InetSocketAddress isa = (local == null) ?
new InetSocketAddress(0) : Net.checkAddress(local);
+ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
localAddress = Net.localAddress(fd);
}
diff --git a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
index d509198aee203ee3318f1328bbe068abfd822b67..0b0e4b6aee24f0d7473d2c49c609ab8e6fbddaff 100644
--- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
@@ -31,6 +31,7 @@ import java.net.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
+import sun.net.NetHooks;
/**
@@ -191,6 +192,7 @@ class ServerSocketChannelImpl
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkListen(isa.getPort());
+ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
Net.listen(fd, backlog < 1 ? 50 : backlog);
synchronized (stateLock) {
diff --git a/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/share/classes/sun/nio/ch/SocketChannelImpl.java
index 20944774d4ee58e06c5f5441a828701abf15b893..ec4f8f5754b05fdb431c67b936e2e88cbf7785a0 100644
--- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
+import sun.net.NetHooks;
/**
@@ -526,6 +527,7 @@ class SocketChannelImpl
throw new AlreadyBoundException();
InetSocketAddress isa = (local == null) ?
new InetSocketAddress(0) : Net.checkAddress(local);
+ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
Net.bind(fd, isa.getAddress(), isa.getPort());
localAddress = Net.localAddress(fd);
}
@@ -577,6 +579,12 @@ class SocketChannelImpl
if (!isOpen()) {
return false;
}
+ // notify hook only if unbound
+ if (localAddress == null) {
+ NetHooks.beforeTcpConnect(fd,
+ isa.getAddress(),
+ isa.getPort());
+ }
readerThread = NativeThread.current();
}
for (;;) {
diff --git a/src/solaris/classes/sun/net/NetHooks.java b/src/solaris/classes/sun/net/NetHooks.java
new file mode 100644
index 0000000000000000000000000000000000000000..f847934190c4231e59a0628b964e5a0a718c837c
--- /dev/null
+++ b/src/solaris/classes/sun/net/NetHooks.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net;
+
+import java.net.InetAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Defines static methods to be invoked prior to binding or connecting TCP sockets.
+ */
+
+public final class NetHooks {
+
+ /**
+ * A provider with hooks to allow sockets be converted prior to binding or
+ * connecting a TCP socket.
+ *
+ *
Concrete implementations of this class should define a zero-argument
+ * constructor and implement the abstract methods specified below.
+ */
+ public static abstract class Provider {
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected Provider() {}
+
+ /**
+ * Invoked prior to binding a TCP socket.
+ */
+ public abstract void implBeforeTcpBind(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException;
+
+ /**
+ * Invoked prior to connecting an unbound TCP socket.
+ */
+ public abstract void implBeforeTcpConnect(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException;
+ }
+
+ /**
+ * For now, we load the SDP provider on Solaris. In the future this may
+ * be changed to use the ServiceLoader facility to allow the deployment of
+ * other providers.
+ */
+ private static Provider loadProvider(final String cn) {
+ return AccessController
+ .doPrivileged(new PrivilegedAction() {
+ @Override public Provider run() {
+ Class c;
+ try {
+ c = (Class)Class.forName(cn, true, null);
+ } catch (ClassNotFoundException x) {
+ throw new AssertionError(x);
+ }
+ try {
+ return c.newInstance();
+ } catch (IllegalAccessException x) {
+ throw new AssertionError(x);
+ } catch (InstantiationException x) {
+ throw new AssertionError(x);
+ }
+ }});
+ }
+ private static final Provider provider = AccessController
+ .doPrivileged(new GetPropertyAction("os.name")).equals("SunOS") ?
+ loadProvider("sun.net.spi.SdpProvider") : null;
+
+ /**
+ * Invoke prior to binding a TCP socket.
+ */
+ public static void beforeTcpBind(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ if (provider != null)
+ provider.implBeforeTcpBind(fdObj, address, port);
+ }
+
+ /**
+ * Invoke prior to connecting an unbound TCP socket.
+ */
+ public static void beforeTcpConnect(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ if (provider != null)
+ provider.implBeforeTcpConnect(fdObj, address, port);
+ }
+}
diff --git a/src/solaris/classes/sun/net/spi/SdpProvider.java b/src/solaris/classes/sun/net/spi/SdpProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ae7d9fa58cd7fb50161b75809d0b00d98aed608
--- /dev/null
+++ b/src/solaris/classes/sun/net/spi/SdpProvider.java
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.spi;
+
+import sun.net.NetHooks;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+import java.util.*;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+/**
+ * A NetHooks provider that converts sockets from the TCP to SDP protocol prior
+ * to binding or connecting.
+ */
+
+public class SdpProvider extends NetHooks.Provider {
+ private static final JavaIOFileDescriptorAccess fdAccess =
+ SharedSecrets.getJavaIOFileDescriptorAccess();
+
+ // maximum port
+ private static final int MAX_PORT = 65535;
+
+ // indicates if SDP is enabled and the rules for when the protocol is used
+ private final boolean enabled;
+ private final List rules;
+
+ // logging for debug purposes
+ private PrintStream log;
+
+ public SdpProvider() {
+ // if this property is not defined then there is nothing to do.
+ String file = System.getProperty("com.sun.sdp.conf");
+ if (file == null) {
+ this.enabled = false;
+ this.rules = null;
+ return;
+ }
+
+ // load configuration file
+ List list = null;
+ if (file != null) {
+ try {
+ list = loadRulesFromFile(file);
+ } catch (IOException e) {
+ fail("Error reading %s: %s", file, e.getMessage());
+ }
+ }
+
+ // check if debugging is enabled
+ PrintStream out = null;
+ String logfile = System.getProperty("com.sun.sdp.debug");
+ if (logfile != null) {
+ out = System.out;
+ if (logfile.length() > 0) {
+ try {
+ out = new PrintStream(logfile);
+ } catch (IOException ignore) { }
+ }
+ }
+
+ this.enabled = !list.isEmpty();
+ this.rules = list;
+ this.log = out;
+ }
+
+ // supported actions
+ private static enum Action {
+ BIND,
+ CONNECT;
+ }
+
+ // a rule for matching a bind or connect request
+ private static interface Rule {
+ boolean match(Action action, InetAddress address, int port);
+ }
+
+ // rule to match port[-end]
+ private static class PortRangeRule implements Rule {
+ private final Action action;
+ private final int portStart;
+ private final int portEnd;
+ PortRangeRule(Action action, int portStart, int portEnd) {
+ this.action = action;
+ this.portStart = portStart;
+ this.portEnd = portEnd;
+ }
+ Action action() {
+ return action;
+ }
+ @Override
+ public boolean match(Action action, InetAddress address, int port) {
+ return (action == this.action &&
+ port >= this.portStart &&
+ port <= this.portEnd);
+ }
+ }
+
+ // rule to match address[/prefix] port[-end]
+ private static class AddressPortRangeRule extends PortRangeRule {
+ private final byte[] addressAsBytes;
+ private final int prefixByteCount;
+ private final byte mask;
+ AddressPortRangeRule(Action action, InetAddress address,
+ int prefix, int port, int end)
+ {
+ super(action, port, end);
+ this.addressAsBytes = address.getAddress();
+ this.prefixByteCount = prefix >> 3;
+ this.mask = (byte)(0xff << (8 - (prefix % 8)));
+ }
+ @Override
+ public boolean match(Action action, InetAddress address, int port) {
+ if (action != action())
+ return false;
+ byte[] candidate = address.getAddress();
+ // same address type?
+ if (candidate.length != addressAsBytes.length)
+ return false;
+ // check bytes
+ for (int i=0; i loadRulesFromFile(String file)
+ throws IOException
+ {
+ Scanner scanner = new Scanner(new File(file));
+ try {
+ List result = new ArrayList();
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine().trim();
+
+ // skip blank lines and comments
+ if (line.length() == 0 || line.charAt(0) == '#')
+ continue;
+
+ // must have 3 fields
+ String[] s = line.split("\\s+");
+ if (s.length != 3) {
+ fail("Malformed line '%s'", line);
+ continue;
+ }
+
+ // first field is the action ("bind" or "connect")
+ Action action = null;
+ for (Action a: Action.values()) {
+ if (s[0].equalsIgnoreCase(a.name())) {
+ action = a;
+ break;
+ }
+ }
+ if (action == null) {
+ fail("Action '%s' not recognized", s[0]);
+ continue;
+ }
+
+ // * port[-end]
+ int[] ports = parsePortRange(s[2]);
+ if (ports.length == 0) {
+ fail("Malformed port range '%s'", s[2]);
+ continue;
+ }
+
+ // match all addresses
+ if (s[1].equals("*")) {
+ result.add(new PortRangeRule(action, ports[0], ports[1]));
+ continue;
+ }
+
+ // hostname | ipaddress[/prefix]
+ int pos = s[1].indexOf('/');
+ try {
+ if (pos < 0) {
+ // hostname or ipaddress (no prefix)
+ InetAddress[] addresses = InetAddress.getAllByName(s[1]);
+ for (InetAddress address: addresses) {
+ int prefix =
+ (address instanceof Inet4Address) ? 32 : 128;
+ result.add(new AddressPortRangeRule(action, address,
+ prefix, ports[0], ports[1]));
+ }
+ } else {
+ // ipaddress/prefix
+ InetAddress address = InetAddress
+ .getByName(s[1].substring(0, pos));
+ int prefix = -1;
+ try {
+ prefix = Integer.parseInt(s[1].substring(pos+1));
+ if (address instanceof Inet4Address) {
+ // must be 1-31
+ if (prefix < 0 || prefix > 32) prefix = -1;
+ } else {
+ // must be 1-128
+ if (prefix < 0 || prefix > 128) prefix = -1;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ if (prefix > 0) {
+ result.add(new AddressPortRangeRule(action,
+ address, prefix, ports[0], ports[1]));
+ } else {
+ fail("Malformed prefix '%s'", s[1]);
+ continue;
+ }
+ }
+ } catch (UnknownHostException uhe) {
+ fail("Unknown host or malformed IP address '%s'", s[1]);
+ continue;
+ }
+ }
+ return result;
+ } finally {
+ scanner.close();
+ }
+ }
+
+ // converts unbound TCP socket to a SDP socket if it matches the rules
+ private void convertTcpToSdpIfMatch(FileDescriptor fdObj,
+ Action action,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ boolean matched = false;
+ for (Rule rule: rules) {
+ if (rule.match(action, address, port)) {
+ int fd = fdAccess.get(fdObj);
+ convert(fd);
+ matched = true;
+ break;
+ }
+ }
+ if (log != null) {
+ String addr = (address instanceof Inet4Address) ?
+ address.getHostAddress() : "[" + address.getHostAddress() + "]";
+ if (matched) {
+ log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port);
+ } else {
+ log.format("%s to %s:%d (no match)\n", action, addr, port);
+ }
+ }
+ }
+
+ @Override
+ public void implBeforeTcpBind(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ if (enabled)
+ convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port);
+ }
+
+ @Override
+ public void implBeforeTcpConnect(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ if (enabled)
+ convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port);
+ }
+
+ // -- native methods --
+ private static native void convert(int fd) throws IOException;
+}
diff --git a/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
index 78ed152d3a1eefc1656b75b5dd886f4f2bbabc0b..e80f202bdff96c2324a63f36d4d82bedc1faab9c 100644
--- a/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
+++ b/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
@@ -32,6 +32,7 @@ import java.util.concurrent.*;
import java.io.IOException;
import java.io.FileDescriptor;
import java.security.AccessController;
+import sun.net.NetHooks;
import sun.security.action.GetPropertyAction;
/**
@@ -305,6 +306,7 @@ class UnixAsynchronousSocketChannelImpl
sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
// check and set state
+ boolean notifyBeforeTcpConnect;
synchronized (stateLock) {
if (state == ST_CONNECTED)
throw new AlreadyConnectedException();
@@ -312,12 +314,16 @@ class UnixAsynchronousSocketChannelImpl
throw new ConnectionPendingException();
state = ST_PENDING;
pendingRemote = remote;
+ notifyBeforeTcpConnect = (localAddress == null);
}
AbstractFuture result = null;
Throwable e = null;
try {
begin();
+ // notify hook if unbound
+ if (notifyBeforeTcpConnect)
+ NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
int n = Net.connect(fd, isa.getAddress(), isa.getPort());
if (n == IOStatus.UNAVAILABLE) {
// connection could not be established immediately
diff --git a/src/solaris/lib/sdp/sdp.conf.template b/src/solaris/lib/sdp/sdp.conf.template
new file mode 100644
index 0000000000000000000000000000000000000000..71cb5c2ce84d0447d2714121efac0b71b7544831
--- /dev/null
+++ b/src/solaris/lib/sdp/sdp.conf.template
@@ -0,0 +1,30 @@
+#
+# Configuration file to enable InfiniBand Sockets Direct Protocol.
+#
+# Each line that does not start with a comment (#) is a rule to indicate when
+# the SDP transport protocol should be used. The format of a rule is as follows:
+# ("bind"|"connect") 1*LWSP-char (hostname|ipaddress["/"prefix]) 1*LWSP-char ("*"|port)["-"("*"|port)]
+#
+# A "bind" rule indicates that the SDP protocol transport should be used when
+# a TCP socket binds to an address/port that matches the rule. A "connect" rule
+# indicates that the SDP protocol transport should be used when an unbound
+# TCP socket attempts to connect to an address/port that matches the rule.
+# Addresses may be specified as hostnames or literal Internet Protocol (IP)
+# addresses. When a literal IP address is used then a prefix length may be used
+# to indicate the number of bits for matching (useful when a block of addresses
+# or subnet is allocated to the InfiniBand fabric).
+
+# Use SDP for all sockets that bind to specific local addresses
+#bind 192.168.1.1 *
+#bind fe80::21b:24ff:fe3d:7896 *
+
+# Use SDP for all sockets that bind to the wildcard address in a port range
+#bind 0.0.0.0 5000-5999
+#bind ::0 5000-5999
+
+# Use SDP when connecting to all application services on 192.168.1.*
+#connect 192.168.1.0/24 1024-*
+
+# Use SDP when connecting to the http server or MySQL database on hpccluster.
+#connect hpccluster.foo.com 80
+#connect hpccluster.foo.com 3306
diff --git a/src/solaris/native/sun/net/spi/SdpProvider.c b/src/solaris/native/sun/net/spi/SdpProvider.c
new file mode 100644
index 0000000000000000000000000000000000000000..00d7f4ba6dc5591d1d4fe671ef50408d5bedc8d4
--- /dev/null
+++ b/src/solaris/native/sun/net/spi/SdpProvider.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include
+#include
+
+#if defined(__solaris__) && !defined(PROTO_SDP)
+#define PROTO_SDP 257
+#endif
+
+#include "jni.h"
+#include "jni_util.h"
+#include "net_util.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+ do { \
+ _result = _cmd; \
+ } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+JNIEXPORT void JNICALL
+Java_sun_net_spi_SdpProvider_convert(JNIEnv *env, jclass cls, jint fd)
+{
+#ifdef PROTO_SDP
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
+ int s = socket(domain, SOCK_STREAM, PROTO_SDP);
+ if (s < 0) {
+ JNU_ThrowIOExceptionWithLastError(env, "socket");
+ } else {
+ int arg, len, res;
+ struct linger linger;
+
+ /* copy socket options that are relevant to SDP */
+ len = sizeof(arg);
+ if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0)
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len);
+ len = sizeof(arg);
+ if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0)
+ setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len);
+ len = sizeof(linger);
+ if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0)
+ setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len);
+
+ RESTARTABLE(dup2(s, fd), res);
+ if (res < 0)
+ JNU_ThrowIOExceptionWithLastError(env, "dup2");
+ RESTARTABLE(close(s), res);
+ }
+#else
+ JNU_ThrowInternalError(env, "should not reach here");
+#endif
+}
diff --git a/src/solaris/native/sun/nio/ch/FileChannelImpl.c b/src/solaris/native/sun/nio/ch/FileChannelImpl.c
index 7b37e6168b81cd1283d47ef8258eb8ae89993ff8..c1c3cc9e82678ae1105705639161ed03b555e48a 100644
--- a/src/solaris/native/sun/nio/ch/FileChannelImpl.c
+++ b/src/solaris/native/sun/nio/ch/FileChannelImpl.c
@@ -231,6 +231,8 @@ Java_sun_nio_ch_FileChannelImpl_transferTo0(JNIEnv *env, jobject this,
if (result < 0) {
if (errno == EAGAIN)
return IOS_UNAVAILABLE;
+ if (errno == EOPNOTSUPP)
+ return IOS_UNSUPPORTED_CASE;
if ((errno == EINVAL) && ((ssize_t)count >= 0))
return IOS_UNSUPPORTED_CASE;
if (errno == EINTR)
diff --git a/src/windows/classes/sun/net/NetHooks.java b/src/windows/classes/sun/net/NetHooks.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d8f60b3a42b9d7c0c63fd0febe0b6796f9ab82f
--- /dev/null
+++ b/src/windows/classes/sun/net/NetHooks.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.net;
+
+import java.net.InetAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * Defines static methods to ensure that any installed net hooks are invoked
+ * prior to binding or connecting TCP sockets.
+ */
+
+public final class NetHooks {
+
+ /**
+ * Invoke prior to binding a TCP socket.
+ */
+ public static void beforeTcpBind(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ // nothing to do
+ }
+
+ /**
+ * Invoke prior to connecting an unbound TCP socket.
+ */
+ public static void beforeTcpConnect(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ // nothing to do
+ }
+}
diff --git a/test/sun/net/sdp/ProbeIB.java b/test/sun/net/sdp/ProbeIB.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac2a4b72d74436cfb81f1db6e2e25f4e4fbbf322
--- /dev/null
+++ b/test/sun/net/sdp/ProbeIB.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.NetworkInterface;
+import java.net.InetAddress;
+import java.util.Scanner;
+import java.util.Enumeration;
+
+/**
+ * Probes for InfiniBand devices plumbed with IP addresses.
+ */
+
+public class ProbeIB {
+ public static void main(String[] args) throws IOException {
+ Scanner s = new Scanner(new File("/etc/path_to_inst"));
+ try {
+ while (s.hasNextLine()) {
+ String line = s.nextLine();
+ if (line.startsWith("#"))
+ continue;
+ String[] fields = line.split("\\s+");
+ if (!fields[2].equals("\"ibd\""))
+ continue;
+ String name = fields[2].substring(1, fields[2].length()-1) + fields[1];
+ NetworkInterface ni = NetworkInterface.getByName(name);
+ if (ni != null) {
+ Enumeration addrs = ni.getInetAddresses();
+ while (addrs.hasMoreElements()) {
+ System.out.println(addrs.nextElement().getHostAddress());
+ }
+ }
+ }
+ } finally {
+ s.close();
+ }
+ }
+}
diff --git a/test/sun/net/sdp/Sanity.java b/test/sun/net/sdp/Sanity.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c8d55e00afa3fa54a11a292f59f332ec77f1e0f
--- /dev/null
+++ b/test/sun/net/sdp/Sanity.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Enumeration;
+
+/**
+ * Sanity check Socket/ServerSocket and each of the stream-oriented channels
+ * on each IP address plumbed to the network adapters.
+ */
+
+public class Sanity {
+ public static void main(String[] args) throws Exception {
+ Enumeration nifs = NetworkInterface.getNetworkInterfaces();
+ while (nifs.hasMoreElements()) {
+ NetworkInterface ni = nifs.nextElement();
+ Enumeration addrs = ni.getInetAddresses();
+ while (addrs.hasMoreElements()) {
+ InetAddress addr = addrs.nextElement();
+ test(addr);
+ }
+ }
+ }
+
+ static void test(InetAddress addr) throws Exception {
+ System.out.println(addr.getHostAddress());
+
+ // ServerSocketChannel.bind
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ try {
+ ssc.bind(new InetSocketAddress(addr, 0));
+ int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
+
+ // SocketChannel.connect (implicit bind)
+ SocketChannel client = SocketChannel.open();
+ try {
+ client.connect(new InetSocketAddress(addr, port));
+ SocketChannel peer = ssc.accept();
+ try {
+ testConnection(Channels.newOutputStream(client),
+ Channels.newInputStream(peer));
+ } finally {
+ peer.close();
+ }
+ } finally {
+ client.close();
+ }
+
+ // SocketChannel.connect (explicit bind)
+ client = SocketChannel.open();
+ try {
+ client.bind(new InetSocketAddress(addr, 0))
+ .connect(new InetSocketAddress(addr, port));
+ ssc.accept().close();
+ } finally {
+ client.close();
+ }
+ } finally {
+ ssc.close();
+ }
+
+ // AsynchronousServerSocketChannel.bind
+ AsynchronousServerSocketChannel server =
+ AsynchronousServerSocketChannel.open();
+ try {
+ server.bind(new InetSocketAddress(addr, 0));
+ int port = ((InetSocketAddress)(server.getLocalAddress())).getPort();
+
+ // AsynchronousSocketChannel.connect (implicit bind)
+ AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
+ try {
+ client.connect(new InetSocketAddress(addr, port)).get();
+ AsynchronousSocketChannel peer = server.accept().get();
+ try {
+ testConnection(Channels.newOutputStream(client),
+ Channels.newInputStream(peer));
+ } finally {
+ peer.close();
+ }
+ } finally {
+ client.close();
+ }
+
+ // AsynchronousSocketChannel.connect (explicit bind)
+ client = AsynchronousSocketChannel.open();
+ try {
+ client.bind(new InetSocketAddress(addr, 0))
+ .connect(new InetSocketAddress(addr, port)).get();
+ server.accept().get().close();
+ } finally {
+ client.close();
+ }
+ } finally {
+ server.close();
+ }
+
+ // ServerSocket.bind
+ ServerSocket ss = new ServerSocket();
+ try {
+ ss.bind(new InetSocketAddress(addr, 0));
+ int port = ss.getLocalPort();
+
+ // Socket.connect (implicit bind)
+ Socket s = new Socket();
+ try {
+ s.connect(new InetSocketAddress(addr, port));
+ Socket peer = ss.accept();
+ try {
+ testConnection(s.getOutputStream(), peer.getInputStream());
+ } finally {
+ peer.close();
+ }
+ } finally {
+ s.close();
+ }
+
+ // Socket.connect (explicit bind)
+ s = new Socket();
+ try {
+ s.bind(new InetSocketAddress(addr, 0));
+ s.connect(new InetSocketAddress(addr, port));
+ ss.accept().close();
+ } finally {
+ s.close();
+ }
+ } finally {
+ ss.close();
+ }
+ }
+
+ static void testConnection(OutputStream out, InputStream in)
+ throws IOException
+ {
+ byte[] msg = "hello".getBytes();
+ out.write(msg);
+
+ byte[] ba = new byte[100];
+ int nread = 0;
+ while (nread < msg.length) {
+ int n = in.read(ba);
+ if (n < 0)
+ throw new IOException("EOF not expected!");
+ nread += n;
+ }
+ }
+}
diff --git a/test/sun/net/sdp/sanity.sh b/test/sun/net/sdp/sanity.sh
new file mode 100644
index 0000000000000000000000000000000000000000..baca9feccef476f71f2aa6fe6c59c7d72c3607ce
--- /dev/null
+++ b/test/sun/net/sdp/sanity.sh
@@ -0,0 +1,72 @@
+#
+# Copyright 2009 Sun Microsystems, Inc. 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.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 4890703
+# @summary Unit test for Solaris SDP support
+# @build ProbeIB Sanity
+# @run shell sanity.sh
+
+# Check we are on Solaris and that SDP is enabled
+OS=`uname -s`
+if [ "$OS" != "SunOS" ]; then
+ echo "This is a Solaris-only test"
+ exit 0
+fi
+SDPADM=/usr/sbin/sdpadm
+if [ ! -f ${SDPADM} ]; then
+ echo "SDP not available"
+ exit 0
+fi
+${SDPADM} status|grep Enabled
+if [ $? != 0 ]; then
+ echo "SDP not enabled"
+ exit 0
+fi
+
+if [ -z "$TESTJAVA" ]; then
+ JAVA=java
+ TESTCLASSES=.
+ TESTSRC=.
+else
+ JAVA="${TESTJAVA}/bin/java"
+fi
+
+CLASSPATH=${TESTCLASSES}:${TESTSRC}
+export CLASSPATH
+
+# Probe for IP addresses plumbed to IB interfaces
+$JAVA -Djava.net.preferIPv4Stack=true ProbeIB > ib_addrs
+
+# Create sdp.conf
+SDPCONF=sdp.conf
+rm ${SDPCONF}
+touch ${SDPCONF}
+cat ib_addrs | while read ADDR
+do
+ echo "bind ${ADDR} *" > ${SDPCONF}
+ echo "connect ${ADDR} *" >> ${SDPCONF}
+done
+
+# Sanity check
+$JAVA -Djava.net.preferIPv4Stack=true -Dcom.sun.sdp.conf=${SDPCONF} -Dcom.sun.sdp.debug Sanity