changeset 524:343253d05123

4640544: New I/O: Complete socket-channel functionality Reviewed-by: iris, sherman, chegar
author alanb
date Sun, 31 Aug 2008 18:39:01 +0100
parents f9cf71f806eb
children 0a427d0e70a7
files make/java/nio/FILES_java.gmk make/java/nio/Makefile make/java/nio/mapfile-linux make/java/nio/mapfile-solaris make/mksample/nio/Makefile make/mksample/nio/multicast/Makefile src/share/classes/java/net/NetworkInterface.java src/share/classes/java/net/ProtocolFamily.java src/share/classes/java/net/SocketOption.java src/share/classes/java/net/StandardProtocolFamily.java src/share/classes/java/net/StandardSocketOption.java src/share/classes/java/nio/channels/DatagramChannel.java src/share/classes/java/nio/channels/MembershipKey.java src/share/classes/java/nio/channels/MulticastChannel.java src/share/classes/java/nio/channels/NetworkChannel.java src/share/classes/java/nio/channels/ServerSocketChannel.java src/share/classes/java/nio/channels/SocketChannel.java src/share/classes/java/nio/channels/exceptions src/share/classes/java/nio/channels/package-info.java src/share/classes/java/nio/channels/package.html src/share/classes/java/nio/channels/spi/SelectorProvider.java src/share/classes/sun/nio/ch/DatagramChannelImpl.java src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java src/share/classes/sun/nio/ch/ExtendedSocketOption.java src/share/classes/sun/nio/ch/MembershipKeyImpl.java src/share/classes/sun/nio/ch/MembershipRegistry.java src/share/classes/sun/nio/ch/Net.java src/share/classes/sun/nio/ch/OptionAdaptor.java src/share/classes/sun/nio/ch/OptionKey.java src/share/classes/sun/nio/ch/SelectorProviderImpl.java src/share/classes/sun/nio/ch/ServerSocketAdaptor.java src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java src/share/classes/sun/nio/ch/SocketAdaptor.java src/share/classes/sun/nio/ch/SocketChannelImpl.java src/share/classes/sun/nio/ch/SocketOpts.java src/share/classes/sun/nio/ch/SocketOptsImpl.java src/share/classes/sun/nio/ch/exceptions src/share/native/java/net/net_util.c src/share/native/java/net/net_util.h src/share/native/sun/nio/ch/genSocketOptionRegistry.c src/share/sample/nio/multicast/MulticastAddress.java src/share/sample/nio/multicast/Reader.java src/share/sample/nio/multicast/Sender.java src/solaris/native/java/net/net_util_md.c src/solaris/native/sun/nio/ch/DatagramChannelImpl.c src/solaris/native/sun/nio/ch/FileKey.c src/solaris/native/sun/nio/ch/Net.c src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c src/solaris/native/sun/nio/ch/SocketChannelImpl.c src/solaris/native/sun/nio/ch/nio_util.h src/windows/native/java/net/net_util_md.c src/windows/native/sun/nio/ch/DatagramChannelImpl.c src/windows/native/sun/nio/ch/Net.c src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c src/windows/native/sun/nio/ch/SocketChannelImpl.c test/java/nio/channels/DatagramChannel/BasicMulticastTests.java test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java test/java/nio/channels/DatagramChannel/NetworkConfiguration.java test/java/nio/channels/DatagramChannel/SocketOptionTests.java test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java test/java/nio/channels/SocketChannel/SocketOptionTests.java test/java/nio/channels/TestUtil.java test/java/nio/channels/etc/NetworkChannelTests.java
diffstat 63 files changed, 5763 insertions(+), 1658 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/nio/FILES_java.gmk	Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/FILES_java.gmk	Sun Aug 31 18:39:01 2008 +0100
@@ -39,6 +39,9 @@
 	java/nio/channels/FileLock.java \
 	java/nio/channels/GatheringByteChannel.java \
 	java/nio/channels/InterruptibleChannel.java \
+	java/nio/channels/MembershipKey.java \
+	java/nio/channels/MulticastChannel.java \
+	java/nio/channels/NetworkChannel.java \
 	java/nio/channels/ReadableByteChannel.java \
 	java/nio/channels/ScatteringByteChannel.java \
 	java/nio/channels/SelectableChannel.java \
@@ -73,6 +76,7 @@
 	sun/nio/ch/DatagramSocketAdaptor.java \
         sun/nio/ch/DefaultSelectorProvider.java \
 	sun/nio/ch/DirectBuffer.java \
+	sun/nio/ch/ExtendedSocketOption.java \
 	sun/nio/ch/FileChannelImpl.java \
 	sun/nio/ch/FileDispatcher.java \
 	sun/nio/ch/FileKey.java \
@@ -80,12 +84,14 @@
 	sun/nio/ch/IOUtil.java \
 	sun/nio/ch/IOStatus.java \
 	sun/nio/ch/IOVecWrapper.java \
+	sun/nio/ch/MembershipKeyImpl.java \
+	sun/nio/ch/MembershipRegistry.java \
 	sun/nio/ch/NativeDispatcher.java \
 	sun/nio/ch/NativeObject.java \
 	sun/nio/ch/NativeThread.java \
 	sun/nio/ch/NativeThreadSet.java \
 	sun/nio/ch/Net.java \
-	sun/nio/ch/OptionAdaptor.java \
+	sun/nio/ch/OptionKey.java \
 	sun/nio/ch/PipeImpl.java \
 	sun/nio/ch/PollArrayWrapper.java \
 	sun/nio/ch/Reflect.java \
@@ -99,8 +105,7 @@
 	sun/nio/ch/SocketAdaptor.java \
 	sun/nio/ch/SocketChannelImpl.java \
 	sun/nio/ch/SocketDispatcher.java \
-	sun/nio/ch/SocketOpts.java \
-	sun/nio/ch/SocketOptsImpl.java \
+	sun/nio/ch/SocketOptionRegistry.java \
         sun/nio/ch/SourceChannelImpl.java \
 	sun/nio/ch/Util.java \
 	\
@@ -240,6 +245,7 @@
 	java/nio/InvalidMarkException.java \
 	java/nio/ReadOnlyBufferException.java \
 	\
+	java/nio/channels/AlreadyBoundException.java \
 	java/nio/channels/AlreadyConnectedException.java \
 	java/nio/channels/AsynchronousCloseException.java \
 	java/nio/channels/ClosedByInterruptException.java \
@@ -258,14 +264,15 @@
 	java/nio/channels/UnresolvedAddressException.java \
 	java/nio/channels/UnsupportedAddressTypeException.java \
 	\
-	sun/nio/ch/AlreadyBoundException.java \
-	\
 	java/nio/charset/CharacterCodingException.java \
 	java/nio/charset/IllegalCharsetNameException.java \
 	java/nio/charset/UnsupportedCharsetException.java
 
 FILES_gen_csp = sun/nio/cs/StandardCharsets.java
 
-FILES_gen = $(FILES_gen_coder) $(FILES_gen_buffer) $(FILES_gen_ex) $(FILES_gen_csp)
+FILES_gen_sor = sun/nio/ch/SocketOptionRegistry.java
+
+FILES_gen = $(FILES_gen_coder) $(FILES_gen_buffer) $(FILES_gen_ex) \
+    $(FILES_gen_csp) $(FILES_gen_sor)
 
 FILES_java = $(FILES_src) $(FILES_gen)
--- a/make/java/nio/Makefile	Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/Makefile	Sun Aug 31 18:39:01 2008 +0100
@@ -56,18 +56,18 @@
         sun/nio/ch/DevPollSelectorProvider.java \
 	sun/nio/ch/InheritedChannel.java \
         sun/nio/ch/PollSelectorProvider.java \
-        sun/nio/ch/PollSelectorImpl.java 
+        sun/nio/ch/PollSelectorImpl.java
 
 FILES_c += \
         DevPollArrayWrapper.c \
 	InheritedChannel.c \
-        PollArrayWrapper.c \
-	NativeThread.c
+	NativeThread.c \
+        PollArrayWrapper.c
 
 FILES_export += \
 	sun/nio/ch/DevPollArrayWrapper.java \
 	sun/nio/ch/InheritedChannel.java \
-	sun/nio/ch/NativeThread.java 
+	sun/nio/ch/NativeThread.java
 endif # PLATFORM = solaris
 
 ifeq ($(PLATFORM), windows)
@@ -94,14 +94,14 @@
 
 FILES_c += \
 	EPollArrayWrapper.c \
-        PollArrayWrapper.c \
 	InheritedChannel.c \
-	NativeThread.c
+	NativeThread.c \
+        PollArrayWrapper.c
 
 FILES_export += \
         sun/nio/ch/EPollArrayWrapper.java \
 	sun/nio/ch/InheritedChannel.java \
-	sun/nio/ch/NativeThread.java 
+	sun/nio/ch/NativeThread.java
 endif # PLATFORM = linux
 
 # Find platform-specific C source files
@@ -618,12 +618,6 @@
 	@$(RM) $@.temp
 	$(GEN_EX_CMD) $(BUF_SRC)/exceptions $(BUF_GEN)
 
-$(SCH_GEN)/%Exception.java: genExceptions.sh $(SCH_SRC)/exceptions
-	$(prep-target)
-	@$(RM) $@.temp
-	$(GEN_EX_CMD) $(SCH_SRC)/exceptions $(SCH_GEN)
-
-
 #
 # Generated charset-provider classes
 #
@@ -638,4 +632,29 @@
 	  HASHER="$(BOOT_JAVA_CMD) -jar $(HASHER_JARFILE)" \
 	  $(SH) -e genCharsetProvider.sh $(SCS_SRC)/standard-charsets $(SCS_GEN)
 
+#
+# Generated channel implementation classes.
+# C source is compiled in TEMPDIR to avoid turds left by Windows compilers.
+#
+
+GENSOR_SRC = $(SHARE_SRC)/native/sun/nio/ch/genSocketOptionRegistry.c
+
+GENSOR_EXE = $(TEMPDIR)/genSocketOptionRegistry$(EXE_SUFFIX)
+
+SOR_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSOR_SRC) | \
+	$(NAWK) '/^.*Copyright.*Sun/ { print $$3 }') 
+
+$(TEMPDIR)/$(GENSOR_SRC) : $(GENSOR_SRC)
+	$(install-file)
+
+$(GENSOR_EXE) : $(TEMPDIR)/$(GENSOR_SRC)
+	$(prep-target)
+	($(CD) $(TEMPDIR); $(CC) $(CPPFLAGS) $(LDDFLAGS) \
+	   -o genSocketOptionRegistry$(EXE_SUFFIX) $(GENSOR_SRC))
+
+$(SCH_GEN)/SocketOptionRegistry.java: $(GENSOR_EXE)
+	$(prep-target)
+	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(SOR_COPYRIGHT_YEARS) > $@
+	$(GENSOR_EXE) >> $@
+
 .PHONY: sources 
--- a/make/java/nio/mapfile-linux	Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/mapfile-linux	Sun Aug 31 18:39:01 2008 +0100
@@ -1,3 +1,27 @@
+#
+# Copyright 2001-2008 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.
+#
 
 SUNWprivate_1.1 {
 	global:
@@ -61,20 +85,29 @@
 		Java_sun_nio_ch_NativeThread_init;
 		Java_sun_nio_ch_NativeThread_signal;
 		Java_sun_nio_ch_Net_socket0;
-		Java_sun_nio_ch_Net_bind;
-		Java_sun_nio_ch_Net_connect;
+		Java_sun_nio_ch_Net_bind0;
+		Java_sun_nio_ch_Net_connect0;
+		Java_sun_nio_ch_Net_listen;
 		Java_sun_nio_ch_Net_localPort;
 		Java_sun_nio_ch_Net_localInetAddress;
 		Java_sun_nio_ch_Net_getIntOption0;
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
+		Java_sun_nio_ch_Net_isIPv6Available0;
+		Java_sun_nio_ch_Net_joinOrDrop4;
+		Java_sun_nio_ch_Net_blockOrUnblock4;
+		Java_sun_nio_ch_Net_joinOrDrop6;
+		Java_sun_nio_ch_Net_blockOrUnblock6;
+		Java_sun_nio_ch_Net_setInterface4;
+		Java_sun_nio_ch_Net_getInterface4;
+		Java_sun_nio_ch_Net_setInterface6;
+		Java_sun_nio_ch_Net_getInterface6;
+		Java_sun_nio_ch_Net_shutdown;
                 Java_sun_nio_ch_PollArrayWrapper_interrupt;
                 Java_sun_nio_ch_PollArrayWrapper_poll0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
-		Java_sun_nio_ch_ServerSocketChannelImpl_listen;
                 Java_sun_nio_ch_SocketChannelImpl_checkConnect;
-		Java_sun_nio_ch_SocketChannelImpl_shutdown;
 
 	local:
 		*;
--- a/make/java/nio/mapfile-solaris	Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/mapfile-solaris	Sun Aug 31 18:39:01 2008 +0100
@@ -1,3 +1,27 @@
+#
+# Copyright 2001-2008 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.
+#
 
 SUNWprivate_1.1 {
 	global:
@@ -59,20 +83,29 @@
 		Java_sun_nio_ch_NativeThread_init;
 		Java_sun_nio_ch_NativeThread_signal;
 		Java_sun_nio_ch_Net_socket0;
-		Java_sun_nio_ch_Net_bind;
-		Java_sun_nio_ch_Net_connect;
+		Java_sun_nio_ch_Net_bind0;
+		Java_sun_nio_ch_Net_connect0;
+		Java_sun_nio_ch_Net_listen;
 		Java_sun_nio_ch_Net_localPort;
 		Java_sun_nio_ch_Net_localInetAddress;
 		Java_sun_nio_ch_Net_getIntOption0;
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
+		Java_sun_nio_ch_Net_isIPv6Available0;
+		Java_sun_nio_ch_Net_joinOrDrop4;
+		Java_sun_nio_ch_Net_blockOrUnblock4;
+		Java_sun_nio_ch_Net_joinOrDrop6;
+		Java_sun_nio_ch_Net_blockOrUnblock6;
+		Java_sun_nio_ch_Net_setInterface4;
+		Java_sun_nio_ch_Net_getInterface4;
+		Java_sun_nio_ch_Net_setInterface6;
+		Java_sun_nio_ch_Net_getInterface6;
+		Java_sun_nio_ch_Net_shutdown;
                 Java_sun_nio_ch_PollArrayWrapper_interrupt;
                 Java_sun_nio_ch_PollArrayWrapper_poll0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
-		Java_sun_nio_ch_ServerSocketChannelImpl_listen;
                 Java_sun_nio_ch_SocketChannelImpl_checkConnect;
-		Java_sun_nio_ch_SocketChannelImpl_shutdown;
 
 	local:
 		*;
--- a/make/mksample/nio/Makefile	Sun Aug 31 18:32:59 2008 +0100
+++ b/make/mksample/nio/Makefile	Sun Aug 31 18:39:01 2008 +0100
@@ -31,7 +31,7 @@
 PRODUCT = java
 include $(BUILDDIR)/common/Defs.gmk
 
-SUBDIRS = server
+SUBDIRS = multicast server
 all build clean clobber::
 	$(SUBDIRS-loop)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/mksample/nio/multicast/Makefile	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,52 @@
+#
+# Copyright 2007 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.
+#
+
+#
+# Makefile for the nio/multicast sample code
+#
+
+BUILDDIR = ../../..
+
+PRODUCT = java
+
+include $(BUILDDIR)/common/Defs.gmk
+
+SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/multicast
+SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/multicast
+
+SAMPLE_FILES =							\
+	$(SAMPLE_DST_DIR)/Reader.java				\
+	$(SAMPLE_DST_DIR)/Sender.java				\
+	$(SAMPLE_DST_DIR)/MulticastAddress.java
+
+all build: $(SAMPLE_FILES)
+
+$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/%
+	$(install-file)
+
+clean clobber:
+	$(RM) -r $(SAMPLE_DST_DIR)
+
+.PHONY: all build clean clobber
--- a/src/share/classes/java/net/NetworkInterface.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/net/NetworkInterface.java	Sun Aug 31 18:39:01 2008 +0100
@@ -25,7 +25,6 @@
 
 package java.net;
 
-import java.net.SocketException;
 import java.util.Enumeration;
 import java.util.NoSuchElementException;
 import sun.security.action.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/ProtocolFamily.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2007-2008 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 java.net;
+
+/**
+ * Represents a family of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public interface ProtocolFamily {
+    /**
+     * Returns the name of the protocol family.
+     */
+    String name();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/SocketOption.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2007-2008 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 java.net;
+
+/**
+ * A socket option associated with a socket.
+ *
+ * <p> In the {@link java.nio.channels channels} package, the {@link
+ * java.nio.channels.NetworkChannel} interface defines the {@link
+ * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption}
+ * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption}
+ * methods to set and query the channel's socket options.
+ *
+ * @param   <T>     The type of the socket option value.
+ *
+ * @since 1.7
+ *
+ * @see StandardSocketOption
+ */
+
+public interface SocketOption<T> {
+
+    /**
+     * Returns the name of the socket option.
+     */
+    String name();
+
+    /**
+     * Returns the type of the socket option value.
+     */
+    Class<T> type();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/StandardProtocolFamily.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007-2008 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 java.net;
+
+/**
+ * Defines the standard family of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public enum StandardProtocolFamily implements ProtocolFamily {
+
+    /**
+     * Internet Protocol Version 4 (IPv4)
+     */
+    INET,
+
+    /**
+     * Internet Protocol Version 6 (IPv6)
+     */
+    INET6
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/StandardSocketOption.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2007-2008 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 java.net;
+
+/**
+ * Defines the <em>standard</em> socket options.
+ *
+ * <p> The {@link SocketOption#name name} of each socket option defined by this
+ * class is its field name.
+ *
+ * <p> In this release, the socket options defined here are used by {@link
+ * java.nio.channels.NetworkChannel network} channels in the {@link
+ * java.nio.channels channels} package.
+ *
+ * @since 1.7
+ */
+
+public final class StandardSocketOption {
+    private StandardSocketOption() { }
+
+    // -- SOL_SOCKET --
+
+    /**
+     * Allow transmission of broadcast datagrams.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The option is specific to
+     * datagram-oriented sockets sending to {@link java.net.Inet4Address IPv4}
+     * broadcast addresses. When the socket option is enabled then the socket
+     * can be used to send <em>broadcast datagrams</em>.
+     *
+     * <p> The initial value of this socket option is {@code FALSE}. The socket
+     * option may be enabled or disabled at any time. Some operating systems may
+     * require that the Java virtual machine be started with implementation
+     * specific privileges to enable this option or send broadcast datagrams.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc919.txt">RFC&nbsp;929:
+     * Broadcasting Internet Datagrams</a>
+     */
+    public static final SocketOption<Boolean> SO_BROADCAST =
+        new StdSocketOption<Boolean>("SO_BROADCAST", Boolean.class);
+
+    /**
+     * Keep connection alive.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE}
+     * option is enabled the operating system may use a <em>keep-alive</em>
+     * mechanism to periodically probe the other end of a connection when the
+     * connection is otherwise idle. The exact semantics of the keep alive
+     * mechanism is system dependent and therefore unspecified.
+     *
+     * <p> The initial value of this socket option is {@code FALSE}. The socket
+     * option may be enabled or disabled at any time.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122
+     * Requirements for Internet Hosts -- Communication Layers</a>
+     */
+    public static final SocketOption<Boolean> SO_KEEPALIVE =
+        new StdSocketOption<Boolean>("SO_KEEPALIVE", Boolean.class);
+
+    /**
+     * The size of the socket send buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket send buffer in bytes. The socket send buffer is an
+     * output buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections. The value of the socket option is
+     * a <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ. The socket option can be queried to retrieve the actual
+     * size.
+     *
+     * <p> For datagram-oriented sockets, the size of the send buffer may limit
+     * the size of the datagrams that may be sent by the socket. Whether
+     * datagrams larger than the buffer size are sent or discarded is system
+     * dependent.
+     *
+     * <p> The initial/default size of the socket send buffer and the range of
+     * allowable values is system dependent although a negative size is not
+     * allowed. An attempt to set the socket send buffer to larger than its
+     * maximum size causes it to be set to its maximum size.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket send buffer to be changed after the socket is bound is system
+     * dependent.
+     */
+    public static final SocketOption<Integer> SO_SNDBUF =
+        new StdSocketOption<Integer>("SO_SNDBUF", Integer.class);
+
+
+    /**
+     * The size of the socket receive buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket receive buffer in bytes. The socket receive buffer is
+     * an input buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections or decreased to limit the possible
+     * backlog of incoming data. The value of the socket option is a
+     * <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ.
+     *
+     * <p> For datagram-oriented sockets, the size of the receive buffer may
+     * limit the size of the datagrams that can be received. Whether datagrams
+     * larger than the buffer size can be received is system dependent.
+     * Increasing the socket receive buffer may be important for cases where
+     * datagrams arrive in bursts faster than they can be processed.
+     *
+     * <p> In the case of stream-oriented sockets and the TCP/IP protocol, the
+     * size of the socket receive buffer may be used when advertising the size
+     * of the TCP receive window to the remote peer.
+     *
+     * <p> The initial/default size of the socket receive buffer and the range
+     * of allowable values is system dependent although a negative size is not
+     * allowed. An attempt to set the socket receive buffer to larger than its
+     * maximum size causes it to be set to its maximum size.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket receive buffer to be changed after the socket is bound is system
+     * dependent.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1323.txt">RFC&nbsp;1323: TCP
+     * Extensions for High Performance</a>
+     */
+    public static final SocketOption<Integer> SO_RCVBUF =
+        new StdSocketOption<Integer>("SO_RCVBUF", Integer.class);
+
+    /**
+     * Re-use address.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The exact semantics of this
+     * socket option are socket type and system dependent.
+     *
+     * <p> In the case of stream-oriented sockets, this socket option will
+     * usually determine whether the socket can be bound to a socket address
+     * when a previous connection involving that socket address is in the
+     * <em>TIME_WAIT</em> state. On implementations where the semantics differ,
+     * and the socket option is not required to be enabled in order to bind the
+     * socket when a previous connection is in this state, then the
+     * implementation may choose to ignore this option.
+     *
+     * <p> For datagram-oriented sockets the socket option is used to allow
+     * multiple programs bind to the same address. This option should be enabled
+     * when the socket is to be used for Internet Protocol (IP) multicasting.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Changing the value of this socket option
+     * after the socket is bound has no effect. The default value of this
+     * socket option is system dependent.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc793.txt">RFC&nbsp;793: Transmission
+     * Control Protocol</a>
+     */
+    public static final SocketOption<Boolean> SO_REUSEADDR =
+        new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
+
+    /**
+     * Linger on close if data is present.
+     *
+     * <p> The value of this socket option is an {@code Integer} that controls
+     * the action taken when unsent data is queued on the socket and a method
+     * to close the socket is invoked. If the value of the socket option is zero
+     * or greater, then it represents a timeout value, in seconds, known as the
+     * <em>linger interval</em>. The linger interval is the timeout for the
+     * {@code close} method to block while the operating system attempts to
+     * transmit the unsent data or it decides that it is unable to transmit the
+     * data. If the value of the socket option is less than zero then the option
+     * is disabled. In that case the {@code close} method does not wait until
+     * unsent data is transmitted; if possible the operating system will transmit
+     * any unsent data before the connection is closed.
+     *
+     * <p> This socket option is intended for use with sockets that are configured
+     * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode
+     * only. The behavior of the {@code close} method when this option is
+     * enabled on a non-blocking socket is not defined.
+     *
+     * <p> The initial value of this socket option is a negative value, meaning
+     * that the option is disabled. The option may be enabled, or the linger
+     * interval changed, at any time. The maximum value of the linger interval
+     * is system dependent. Setting the linger interval to a value that is
+     * greater than its maximum value causes the linger interval to be set to
+     * its maximum value.
+     */
+    public static final SocketOption<Integer> SO_LINGER =
+        new StdSocketOption<Integer>("SO_LINGER", Integer.class);
+
+
+    // -- IPPROTO_IP --
+
+    /**
+     * The Type of Service (ToS) octet in the Internet Protocol (IP) header.
+     *
+     * <p> The value of this socket option is an {@code Integer}, the least
+     * significant 8 bits of which represents the value of the ToS octet in IP
+     * packets sent by sockets to an {@link StandardProtocolFamily#INET IPv4}
+     * socket. The interpretation of the ToS octet is network specific and
+     * is not defined by this class. Further information on the ToS octet can be
+     * found in <a href="http://www.ietf.org/rfc/rfc1349.txt">RFC&nbsp;1349</a>
+     * and <a href="http://www.ietf.org/rfc/rfc2474.txt">RFC&nbsp;2474</a>. The
+     * value of the socket option is a <em>hint</em>. An implementation may
+     * ignore the value, or ignore specific values.
+     *
+     * <p> The initial/default value of the TOS field in the ToS octet is
+     * implementation specific but will typically be {@code 0}. For
+     * datagram-oriented sockets the option may be configured at any time after
+     * the socket has been bound. The new value of the octet is used when sending
+     * subsequent datagrams. It is system dependent whether this option can be
+     * queried or changed prior to binding the socket.
+     *
+     * <p> The behavior of this socket option on a stream-oriented socket, or an
+     * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this
+     * release.
+     */
+    public static final SocketOption<Integer> IP_TOS =
+        new StdSocketOption<Integer>("IP_TOS", Integer.class);
+
+    /**
+     * The network interface for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is a {@link NetworkInterface} that
+     * represents the outgoing interface for multicast datagrams sent by the
+     * datagram-oriented socket. For {@link StandardProtocolFamily#INET6 IPv6}
+     * sockets then it is system dependent whether setting this option also
+     * sets the outgoing interface for multlicast datagrams sent to IPv4
+     * addresses.
+     *
+     * <p> The initial/default value of this socket option may be {@code null}
+     * to indicate that outgoing interface will be selected by the operating
+     * system, typically based on the network routing tables. An implementation
+     * allows this socket option to be set after the socket is bound. Whether
+     * the socket option can be queried or changed prior to binding the socket
+     * is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     */
+    public static final SocketOption<NetworkInterface> IP_MULTICAST_IF =
+        new StdSocketOption<NetworkInterface>("IP_MULTICAST_IF", NetworkInterface.class);
+
+    /**
+     * The <em>time-to-live</em> for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is an {@code Integer} in the range
+     * <tt>0&nbsp;<=&nbsp;value&nbsp;<=&nbsp;255</tt>. It is used to control
+     * the scope of multicast datagrams sent by the datagram-oriented socket.
+     * In the case of an {@link StandardProtocolFamily#INET IPv4} socket
+     * the option is the time-to-live (TTL) on multicast datagrams sent by the
+     * socket. Datagrams with a TTL of zero are not transmitted on the network
+     * but may be delivered locally. In the case of an {@link
+     * StandardProtocolFamily#INET6 IPv6} socket the option is the
+     * <em>hop limit</em> which is number of <em>hops</em> that the datagram can
+     * pass through before expiring on the network. For IPv6 sockets it is
+     * system dependent whether the option also sets the <em>time-to-live</em>
+     * on multicast datagrams sent to IPv4 addresses.
+     *
+     * <p> The initial/default value of the time-to-live setting is typically
+     * {@code 1}. An implementation allows this socket option to be set after
+     * the socket is bound. Whether the socket option can be queried or changed
+     * prior to binding the socket is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     */
+    public static final SocketOption<Integer> IP_MULTICAST_TTL =
+        new StdSocketOption<Integer>("IP_MULTICAST_TTL", Integer.class);
+
+    /**
+     * Loopback for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that controls
+     * the <em>loopback</em> of multicast datagrams. The value of the socket
+     * option represents if the option is enabled or disabled.
+     *
+     * <p> The exact semantics of this socket options are system dependent.
+     * In particular, it is system dependent whether the loopback applies to
+     * multicast datagrams sent from the socket or received by the socket.
+     * For {@link StandardProtocolFamily#INET6 IPv6} sockets then it is
+     * system dependent whether the option also applies to multicast datagrams
+     * sent to IPv4 addresses.
+     *
+     * <p> The initial/default value of this socket option is {@code TRUE}. An
+     * implementation allows this socket option to be set after the socket is
+     * bound. Whether the socket option can be queried or changed prior to
+     * binding the socket is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     */
+    public static final SocketOption<Boolean> IP_MULTICAST_LOOP =
+        new StdSocketOption<Boolean>("IP_MULTICAST_LOOP", Boolean.class);
+
+
+    // -- IPPROTO_TCP --
+
+    /**
+     * Disable the Nagle algorithm.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The socket option is specific to
+     * stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an algorithm
+     * known as <em>The Nagle Algorithm</em> to coalesce short segments and
+     * improve network efficiency.
+     *
+     * <p> The default value of this socket option is {@code FALSE}. The
+     * socket option should only be enabled in cases where it is known that the
+     * coalescing impacts performance. The socket option may be enabled at any
+     * time. In other words, the Nagle Algorithm can be disabled. Once the option
+     * is enabled, it is system dependent whether it can be subsequently
+     * disabled. In that case, invoking the {@code setOption} method to disable
+     * the option has no effect.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122:
+     * Requirements for Internet Hosts -- Communication Layers</a>
+     */
+    public static final SocketOption<Boolean> TCP_NODELAY =
+        new StdSocketOption<Boolean>("TCP_NODELAY", Boolean.class);
+
+
+    private static class StdSocketOption<T> implements SocketOption<T> {
+        private final String name;
+        private final Class<T> type;
+        StdSocketOption(String name, Class<T> type) {
+            this.name = name;
+            this.type = type;
+        }
+        @Override public String name() { return name; }
+        @Override public Class<T> type() { return type; }
+        @Override public String toString() { return name; }
+    }
+}
--- a/src/share/classes/java/nio/channels/DatagramChannel.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/DatagramChannel.java	Sun Aug 31 18:39:01 2008 +0100
@@ -26,28 +26,21 @@
 package java.nio.channels;
 
 import java.io.IOException;
+import java.net.ProtocolFamily;
 import java.net.DatagramSocket;
+import java.net.SocketOption;
 import java.net.SocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.spi.*;
 
-
 /**
  * A selectable channel for datagram-oriented sockets.
  *
- *
- * <p> Datagram channels are not a complete abstraction of network datagram
- * sockets.  Binding and the manipulation of socket options must be done
- * through an associated {@link java.net.DatagramSocket} object obtained by
- * invoking the {@link #socket() socket} method.  It is not possible to create
- * a channel for an arbitrary, pre-existing datagram socket, nor is it possible
- * to specify the {@link java.net.DatagramSocketImpl} object to be used by a
- * datagram socket associated with a datagram channel.
- *
- * <p> A datagram channel is created by invoking the {@link #open open} method
- * of this class.  A newly-created datagram channel is open but not connected.
- * A datagram channel need not be connected in order for the {@link #send send}
- * and {@link #receive receive} methods to be used.  A datagram channel may be
+ * <p> A datagram channel is created by invoking one of the {@link #open open} methods
+ * of this class. It is not possible to create a channel for an arbitrary,
+ * pre-existing datagram socket. A newly-created datagram channel is open but not
+ * connected. A datagram channel need not be connected in order for the {@link #send
+ * send} and {@link #receive receive} methods to be used.  A datagram channel may be
  * connected, by invoking its {@link #connect connect} method, in order to
  * avoid the overhead of the security checks are otherwise performed as part of
  * every send and receive operation.  A datagram channel must be connected in
@@ -59,11 +52,57 @@
  * disconnected or closed.  Whether or not a datagram channel is connected may
  * be determined by invoking its {@link #isConnected isConnected} method.
  *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Datagram channels support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST} </td>
+ *     <td> Allow transmission of broadcast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_TOS IP_TOS} </td>
+ *     <td> The Type of Service (ToS) octet in the Internet Protocol (IP) header </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF} </td>
+ *     <td> The network interface for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_TTL
+ *       IP_MULTICAST_TTL} </td>
+ *     <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast
+ *       datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP
+ *       IP_MULTICAST_LOOP} </td>
+ *     <td> Loopback for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
  * <p> Datagram channels are safe for use by multiple concurrent threads.  They
  * support concurrent reading and writing, though at most one thread may be
  * reading and at most one thread may be writing at any given time.  </p>
  *
- *
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  * @since 1.4
@@ -71,7 +110,7 @@
 
 public abstract class DatagramChannel
     extends AbstractSelectableChannel
-    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
+    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
 {
 
     /**
@@ -88,7 +127,13 @@
      * java.nio.channels.spi.SelectorProvider#openDatagramChannel()
      * openDatagramChannel} method of the system-wide default {@link
      * java.nio.channels.spi.SelectorProvider} object.  The channel will not be
-     * connected.  </p>
+     * connected.
+     *
+     * <p> The {@link ProtocolFamily ProtocolFamily} of the channel's socket
+     * is platform (and possibly configuration) dependent and therefore unspecified.
+     * The {@link #open(ProtocolFamily) open} allows the protocol family to be
+     * selected when opening a datagram channel, and should be used to open
+     * datagram channels that are intended for Internet Protocol multicasting.
      *
      * @return  A new datagram channel
      *
@@ -100,6 +145,39 @@
     }
 
     /**
+     * Opens a datagram channel.
+     *
+     * <p> The {@code family} parameter is used to specify the {@link
+     * ProtocolFamily}. If the datagram channel is to be used for IP multicasing
+     * then this should correspond to the address type of the multicast groups
+     * that this channel will join.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openDatagramChannel(ProtocolFamily)
+     * openDatagramChannel} method of the system-wide default {@link
+     * java.nio.channels.spi.SelectorProvider} object.  The channel will not be
+     * connected.
+     *
+     * @param   family
+     *          The protocol family
+     *
+     * @return  A new datagram channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the specified protocol family is not supported. For example,
+     *          suppose the parameter is specified as {@link
+     *          java.net.StandardProtocolFamily#INET6 StandardProtocolFamily.INET6}
+     *          but IPv6 is not enabled on the platform.
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since   1.7
+     */
+    public static DatagramChannel open(ProtocolFamily family) throws IOException {
+        return SelectorProvider.provider().openDatagramChannel(family);
+    }
+
+    /**
      * Returns an operation set identifying this channel's supported
      * operations.
      *
@@ -118,6 +196,32 @@
     // -- Socket-specific operations --
 
     /**
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     *
+     * @since 1.7
+     */
+    public abstract DatagramChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+
+    /**
      * Retrieves a datagram socket associated with this channel.
      *
      * <p> The returned object will not declare any public methods that are not
@@ -128,10 +232,10 @@
     public abstract DatagramSocket socket();
 
     /**
-     * Tells whether or not this channel's socket is connected.  </p>
+     * Tells whether or not this channel's socket is connected.
      *
-     * @return  <tt>true</tt> if, and only if, this channel's socket
-     *          is connected
+     * @return  {@code true} if, and only if, this channel's socket
+     *          is {@link #isOpen open} and connected
      */
     public abstract boolean isConnected();
 
@@ -207,6 +311,19 @@
     public abstract DatagramChannel disconnect() throws IOException;
 
     /**
+     * Returns the remote address to which this channel's socket is connected.
+     *
+     * @return  The remote address; {@code null} if the channel is not {@link
+     *          #isOpen open} or the channel's socket is not connected
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketAddress getConnectedAddress() throws IOException;
+
+    /**
      * Receives a datagram via this channel.
      *
      * <p> If a datagram is immediately available, or if this channel is in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/MembershipKey.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2007-2008 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 java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * A token representing the membership of an Internet Protocol (IP) multicast
+ * group.
+ *
+ * <p> A membership key may represent a membership to receive all datagrams sent
+ * to the group, or it may be <em>source-specific</em>, meaning that it
+ * represents a membership that receives only datagrams from a specific source
+ * address. Whether or not a membership key is source-specific may be determined
+ * by invoking its {@link #getSourceAddress() getSourceAddress} method.
+ *
+ * <p> A membership key is valid upon creation and remains valid until the
+ * membership is dropped by invoking the {@link #drop() drop} method, or
+ * the channel is closed. The validity of the membership key may be tested
+ * by invoking its {@link #isValid() isValid} method.
+ *
+ * <p> Where a membership key is not source-specific and the underlying operation
+ * system supports source filtering, then the {@link #block block} and {@link
+ * #unblock unblock} methods can be used to block or unblock multicast datagrams
+ * from particular source addresses.
+ *
+ * @see MulticastChannel
+ *
+ * @since 1.7
+ */
+public abstract class MembershipKey {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected MembershipKey() {
+    }
+
+    /**
+     * Tells whether or not this membership is valid.
+     *
+     * <p> A multicast group membership is valid upon creation and remains
+     * valid until the membership is dropped by invoking the {@link #drop() drop}
+     * method, or the channel is closed.
+     *
+     * @return  {@code true} if this membership key is valid, {@code false}
+     *          otherwise
+     */
+    public abstract boolean isValid();
+
+    /**
+     * Drop membership.
+     *
+     * <p> If the membership key represents a membership to receive all datagrams
+     * then the membership is dropped and the channel will no longer receive any
+     * datagrams sent to the group. If the membership key is source-specific
+     * then the channel will no longer receive datagrams sent to the group from
+     * that source address.
+     *
+     * <p> After membership is dropped it may still be possible to receive
+     * datagrams sent to the group. This can arise when datagrams are waiting to
+     * be received in the socket's receive buffer. After membership is dropped
+     * then the channel may {@link MulticastChannel#join join} the group again
+     * in which case a new membership key is returned.
+     *
+     * <p> Upon return, this membership object will be {@link #isValid() invalid}.
+     * If the multicast group membership is already invalid then invoking this
+     * method has no effect. Once a multicast group membership is invalid,
+     * it remains invalid forever.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract void drop() throws IOException;
+
+    /**
+     * Block multicast datagrams from the given source address.
+     *
+     * <p> If this membership key is not source-specific, and the underlying
+     * operating system supports source filtering, then this method blocks
+     * multicast datagrams from the given source address. If the given source
+     * address is already blocked then this method has no effect.
+     * After a source address is blocked it may still be possible to receive
+     * datagams from that source. This can arise when datagrams are waiting to
+     * be received in the socket's receive buffer.
+     *
+     * @param   source
+     *          The source address to block
+     *
+     * @return  This membership key
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code source} parameter is not a unicast address or
+     *          is not the same address type as the multicast group
+     * @throws  IllegalStateException
+     *          If this membership key is source-specific or is no longer valid
+     * @throws  UnsupportedOperationException
+     *          If the underlying operating system does not support source
+     *          filtering
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract MembershipKey block(InetAddress source) throws IOException;
+
+    /**
+     * Unblock multicast datagrams from the given source address that was
+     * previously blocked using the {@link #block(InetAddress) block} method.
+     *
+     * @param   source
+     *          The source address to unblock
+     *
+     * @return  This membership key
+     *
+     * @throws  IllegalStateException
+     *          If the given source address is not currently blocked or the
+     *          membership key is no longer valid
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract MembershipKey unblock(InetAddress source) throws IOException;
+
+    /**
+     * Returns the channel for which this membership key was created. This
+     * method will continue to return the channel even after the membership
+     * becomes {@link #isValid invalid}.
+     *
+     * @return  the channel
+     */
+    public abstract MulticastChannel getChannel();
+
+    /**
+     * Returns the multicast group for which this membership key was created.
+     * This method will continue to return the group even after the membership
+     * becomes {@link #isValid invalid}.
+     *
+     * @return  the multicast group
+     */
+    public abstract InetAddress getGroup();
+
+    /**
+     * Returns the network interface for which this membership key was created.
+     * This method will continue to return the network interface even after the
+     * membership becomes {@link #isValid invalid}.
+     *
+     * @return  the network interface
+     */
+    public abstract NetworkInterface getNetworkInterface();
+
+    /**
+     * Returns the source address if this membership key is source-specific,
+     * or {@code null} if this membership is not source-specific.
+     *
+     * @return  The source address if this membership key is source-specific,
+     *          otherwise {@code null}
+     */
+    public abstract InetAddress getSourceAddress();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/MulticastChannel.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007-2008 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 java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.net.ProtocolFamily;             // javadoc
+import java.net.StandardProtocolFamily;     // javadoc
+import java.net.StandardSocketOption;       // javadoc
+
+/**
+ * A network channel that supports Internet Protocol (IP) multicasting.
+ *
+ * <p> IP multicasting is the transmission of IP datagrams to members of
+ * a <em>group</em> that is zero or more hosts identified by a single destination
+ * address.
+ *
+ * <p> In the case of a channel to an {@link StandardProtocolFamily#INET IPv4} socket,
+ * the underlying operating system supports <a href="http://www.ietf.org/rfc/rfc2236.txt">
+ * <i>RFC&nbsp;2236: Internet Group Management Protocol, Version 2 (IGMPv2)</i></a>.
+ * It may optionally support source filtering as specified by <a
+ * href="http://www.ietf.org/rfc/rfc3376.txt"> <i>RFC&nbsp;3376: Internet Group
+ * Management Protocol, Version 3 (IGMPv3)</i></a>.
+ * For channels to an {@link StandardProtocolFamily#INET6 IPv6} socket, the equivalent
+ * standards are <a href="http://www.ietf.org/rfc/rfc2710.txt"> <i>RFC&nbsp;2710:
+ * Multicast Listener Discovery (MLD) for IPv6</i></a> and <a
+ * href="http://www.ietf.org/rfc/rfc3810.txt"> <i>RFC&nbsp;3810: Multicast Listener
+ * Discovery Version 2 (MLDv2) for IPv6</i></a>.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface)} method is used to
+ * join a group and receive all multicast datagrams sent to the group. A channel
+ * may join several multicast groups and may join the same group on several
+ * {@link NetworkInterface interfaces}. Membership is dropped by invoking the {@link
+ * MembershipKey#drop drop} method on the returned {@link MembershipKey}. If the
+ * underlying platform supports source filtering then the {@link MembershipKey#block
+ * block} and {@link MembershipKey#unblock unblock} methods can be used to block or
+ * unblock multicast datagrams from particular source addresses.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface,InetAddress)} method
+ * is used to begin receiving datagrams sent to a group whose source address matches
+ * a given source address. This method throws {@link UnsupportedOperationException}
+ * if the underlying platform does not support source filtering.  Membership is
+ * <em>cumulative</em> and this method may be invoked again with the same group
+ * and interface to allow receiving datagrams from other source addresses. The
+ * method returns a {@link MembershipKey} that represents membership to receive
+ * datagrams from the given source address. Invoking the key's {@link
+ * MembershipKey#drop drop} method drops membership so that datagrams from the
+ * source address can no longer be received.
+ *
+ * <h4>Platform dependencies</h4>
+ *
+ * The multicast implementation is intended to map directly to the native
+ * multicasting facility. Consequently, the following items should be considered
+ * when developing an application that receives IP multicast datagrams:
+ *
+ * <ol>
+ *
+ * <li><p> The creation of the channel should specify the {@link ProtocolFamily}
+ * that corresponds to the address type of the multicast groups that the channel
+ * will join. There is no guarantee that a channel to a socket in one protocol
+ * family can join and receive multicast datagrams when the address of the
+ * multicast group corresponds to another protocol family. For example, it is
+ * implementation specific if a channel to an {@link StandardProtocolFamily#INET6 IPv6}
+ * socket can join an {@link StandardProtocolFamily#INET IPv4} multicast group and receive
+ * multicast datagrams sent to the group. </p></li>
+ *
+ * <li><p> The channel's socket should be bound to the {@link
+ * InetAddress#isAnyLocalAddress wildcard} address. If the socket is bound to
+ * a specific address, rather than the wildcard address then it is implementation
+ * specific if multicast datagrams are received by the socket. </p></li>
+ *
+ * <li><p> The {@link StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} option should be
+ * enabled prior to {@link NetworkChannel#bind binding} the socket. This is
+ * required to allow multiple members of the group to bind to the same
+ * address. </p></li>
+ *
+ * </ol>
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *     // join multicast group on this interface, and also use this
+ *     // interface for outgoing multicast datagrams
+ *     NetworkInterface ni = NetworkInterface.getByName("hme0");
+ *
+ *     DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+ *         .setOption(StandardSocketOption.SO_REUSEADDR, true)
+ *         .bind(new InetSocketAddress(5000))
+ *         .setOption(StandardSocketOption.IP_MULTICAST_IF, ni);
+ *
+ *     InetAddress group = InetAddress.getByName("225.4.5.6");
+ *
+ *     MembershipKey key = dc.join(group, ni);
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface MulticastChannel
+    extends NetworkChannel
+{
+    /**
+     * Joins a multicast group to begin receiving all datagrams sent to the group,
+     * returning a membership key.
+     *
+     * <p> If this channel is currently a member of the group on the given
+     * interface to receive all datagrams then the membership key, representing
+     * that membership, is returned. Otherwise this channel joins the group and
+     * the resulting new membership key is returned. The resulting membership key
+     * is not {@link MembershipKey#getSourceAddress source-specific}.
+     *
+     * <p> A multicast channel may join several multicast groups, including
+     * the same group on more than one interface. An implementation may impose a
+     * limit on the number of groups that may be joined at the same time.
+     *
+     * @param   group
+     *          The multicast address to join
+     * @param   interf
+     *          The network interface on which to join the group
+     *
+     * @return  The membership key
+     *
+     * @throws  IllegalArgumentException
+     *          If the group parameter is not a {@link InetAddress#isMulticastAddress
+     *          multicast} address, or the group parameter is an address type
+     *          that is not supported by this channel
+     * @throws  IllegalStateException
+     *          If the channel already has source-specific membership of the
+     *          group on the interface
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is set, and its
+     *          {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+     *          method denies access to the multiast group
+     */
+    MembershipKey join(InetAddress group, NetworkInterface interf)
+        throws IOException;
+
+    /**
+     * Joins a multicast group to begin receiving datagrams sent to the group
+     * from a given source address.
+     *
+     * <p> If this channel is currently a member of the group on the given
+     * interface to receive datagrams from the given source address then the
+     * membership key, representing that membership, is returned. Otherwise this
+     * channel joins the group and the resulting new membership key is returned.
+     * The resulting membership key is {@link MembershipKey#getSourceAddress
+     * source-specific}.
+     *
+     * <p> Membership is <em>cumulative</em> and this method may be invoked
+     * again with the same group and interface to allow receiving datagrams sent
+     * by other source addresses to the group.
+     *
+     * @param   group
+     *          The multicast address to join
+     * @param   interf
+     *          The network interface on which to join the group
+     * @param   source
+     *          The source address
+     *
+     * @return  The membership key
+     *
+     * @throws  IllegalArgumentException
+     *          If the group parameter is not a {@link
+     *          InetAddress#isMulticastAddress multicast} address, the
+     *          source parameter is not a unicast address, the group
+     *          parameter is an address type that is not supported by this channel,
+     *          or the source parameter is not the same address type as the group
+     * @throws  IllegalStateException
+     *          If the channel is currently a member of the group on the given
+     *          interface to receive all datagrams
+     * @throws  UnsupportedOperationException
+     *          If the underlying operation system does not support source filtering
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is set, and its
+     *          {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+     *          method denies access to the multiast group
+     */
+    MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/NetworkChannel.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2007-2008 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 java.nio.channels;
+
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A channel to a network socket.
+ *
+ * <p> A channel that implements this interface is a channel to a network
+ * socket. The {@link #bind(SocketAddress) bind} method is used to bind the
+ * socket to a local {@link SocketAddress address}, the {@link #getLocalAddress()
+ * getLocalAddress} method returns the address that the socket is bound to, and
+ * the {@link #setOption(SocketOption,Object) setOption} and {@link
+ * #getOption(SocketOption) getOption} methods are used to set and query socket
+ * options.  An implementation of this interface should specify the socket options
+ * that it supports.
+ *
+ * <p> The {@link #bind bind} and {@link #setOption setOption} methods that do
+ * not otherwise have a value to return are specified to return the network
+ * channel upon which they are invoked. This allows method invocations to be
+ * chained. Implementations of this interface should specialize the return type
+ * so that method invocations on the implementation class can be chained.
+ *
+ * @since 1.7
+ */
+
+public interface NetworkChannel
+    extends Channel
+{
+    /**
+     * Binds the channel's socket to a local address.
+     *
+     * <p> This method is used to establish an association between the socket and
+     * a local address. Once an association is established then the socket remains
+     * bound until the channel is closed. If the {@code local} parameter has the
+     * value {@code null} then the socket will be bound to an address that is
+     * assigned automatically.
+     *
+     * @param   local
+     *          The address to bind the socket, or {@code null} to bind the socket
+     *          to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException
+     *          If the socket is already bound
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission. An implementation of this interface should specify
+     *          any required permissions.
+     *
+     * @see #getLocalAddress
+     */
+    NetworkChannel bind(SocketAddress local) throws IOException;
+
+    /**
+     * Returns the socket address that this channel's socket is bound to, or
+     * {@code null} if the socket is not bound.
+     *
+     * <p> Where the channel is {@link #bind bound} to an Internet Protocol
+     * socket address then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The socket address that the socket is bound to, or {@code null}
+     *          if the channel is not {@link #isOpen open} or the channel's socket
+     *          is not bound
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    SocketAddress getLocalAddress() throws IOException;
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param   name
+     *          The socket option
+     * @param   value
+     *          The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @return  This channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the socket option is not supported by this channel, or
+     *          the value is not a valid value for this socket option
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see java.net.StandardSocketOption
+     */
+    <T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException;
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param   name
+     *          The socket option
+     *
+     * @return  The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @throws  IllegalArgumentException
+     *          If the socket option is not supported by this channel
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see java.net.StandardSocketOption
+     */
+    <T> T getOption(SocketOption<T> name) throws IOException;
+
+    /**
+     * Returns a set of the socket options supported by this channel.
+     *
+     * <p> This method will continue to return the set of options even after the
+     * channel has been closed.
+     *
+     * @return  A set of the socket options supported by this channel
+     */
+    Set<SocketOption<?>> options();
+}
--- a/src/share/classes/java/nio/channels/ServerSocketChannel.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/ServerSocketChannel.java	Sun Aug 31 18:39:01 2008 +0100
@@ -27,33 +27,44 @@
 
 import java.io.IOException;
 import java.net.ServerSocket;
+import java.net.SocketOption;
 import java.net.SocketAddress;
 import java.nio.channels.spi.*;
 
-
 /**
  * A selectable channel for stream-oriented listening sockets.
  *
- * <p> Server-socket channels are not a complete abstraction of listening
- * network sockets.  Binding and the manipulation of socket options must be
- * done through an associated {@link java.net.ServerSocket} object obtained by
- * invoking the {@link #socket() socket} method.  It is not possible to create
- * a channel for an arbitrary, pre-existing server socket, nor is it possible
- * to specify the {@link java.net.SocketImpl} object to be used by a server
- * socket associated with a server-socket channel.
+ * <p> A server-socket channel is created by invoking the {@link #open() open}
+ * method of this class.  It is not possible to create a channel for an arbitrary,
+ * pre-existing {@link ServerSocket}. A newly-created server-socket channel is
+ * open but not yet bound.  An attempt to invoke the {@link #accept() accept}
+ * method of an unbound server-socket channel will cause a {@link NotYetBoundException}
+ * to be thrown. A server-socket channel can be bound by invoking one of the
+ * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class.
  *
- * <p> A server-socket channel is created by invoking the {@link #open() open}
- * method of this class.  A newly-created server-socket channel is open but not
- * yet bound.  An attempt to invoke the {@link #accept() accept} method of an
- * unbound server-socket channel will cause a {@link NotYetBoundException} to
- * be thrown.  A server-socket channel can be bound by invoking one of the
- * {@link java.net.ServerSocket#bind(java.net.SocketAddress,int) bind} methods
- * of an associated server socket.
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Server-socket channels support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
  *
  * <p> Server-socket channels are safe for use by multiple concurrent threads.
  * </p>
  *
- *
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  * @since 1.4
@@ -61,6 +72,7 @@
 
 public abstract class ServerSocketChannel
     extends AbstractSelectableChannel
+    implements NetworkChannel
 {
 
     /**
@@ -110,6 +122,89 @@
     // -- ServerSocket-specific operations --
 
     /**
+     * Binds the channel's socket to a local address and configures the socket
+     * to listen for connections.
+     *
+     * <p> An invocation of this method is equivalent to the following:
+     * <blockquote><pre>
+     * bind(local, 0);
+     * </pre></blockquote>
+     *
+     * @param   local
+     *          The local address to bind the socket, or {@code null} to bind
+     *          to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     *
+     * @since 1.7
+     */
+    public final ServerSocketChannel bind(SocketAddress local)
+        throws IOException
+    {
+        return bind(local, 0);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket to
+     * listen for connections.
+     *
+     * <p> This method is used to establish an association between the socket and
+     * a local address. Once an association is established then the socket remains
+     * bound until the channel is closed.
+     *
+     * <p> The {@code backlog} parameter is the maximum number of pending
+     * connections on the socket. Its exact semantics are implementation specific.
+     * In particular, an implementation may impose a maximum length or may choose
+     * to ignore the parameter altogther. If the {@code backlog} parameter has
+     * the value {@code 0}, or a negative value, then an implementation specific
+     * default is used.
+     *
+     * @param   local
+     *          The address to bind the socket, or {@code null} to bind to an
+     *          automatically assigned socket address
+     * @param   backlog
+     *          The maximum number of pending connections
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException
+     *          If the socket is already bound
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     *
+     * @since 1.7
+     */
+    public abstract ServerSocketChannel bind(SocketAddress local, int backlog)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    public abstract <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
      * Retrieves a server socket associated with this channel.
      *
      * <p> The returned object will not declare any public methods that are not
--- a/src/share/classes/java/nio/channels/SocketChannel.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/SocketChannel.java	Sun Aug 31 18:39:01 2008 +0100
@@ -27,24 +27,17 @@
 
 import java.io.IOException;
 import java.net.Socket;
+import java.net.SocketOption;
 import java.net.SocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.spi.*;
 
-
 /**
  * A selectable channel for stream-oriented connecting sockets.
  *
- * <p> Socket channels are not a complete abstraction of connecting network
- * sockets.  Binding, shutdown, and the manipulation of socket options must be
- * done through an associated {@link java.net.Socket} object obtained by
- * invoking the {@link #socket() socket} method.  It is not possible to create
- * a channel for an arbitrary, pre-existing socket, nor is it possible to
- * specify the {@link java.net.SocketImpl} object to be used by a socket
- * associated with a socket channel.
- *
  * <p> A socket channel is created by invoking one of the {@link #open open}
- * methods of this class.  A newly-created socket channel is open but not yet
+ * methods of this class.  It is not possible to create a channel for an arbitrary,
+ * pre-existing socket. A newly-created socket channel is open but not yet
  * connected.  An attempt to invoke an I/O operation upon an unconnected
  * channel will cause a {@link NotYetConnectedException} to be thrown.  A
  * socket channel can be connected by invoking its {@link #connect connect}
@@ -59,16 +52,6 @@
  * Whether or not a connection operation is in progress may be determined by
  * invoking the {@link #isConnectionPending isConnectionPending} method.
  *
- * <p> The input and output sides of a socket channel may independently be
- * <i>shut down</i> without actually closing the channel.  Shutting down the
- * input side of a channel by invoking the {@link java.net.Socket#shutdownInput
- * shutdownInput} method of an associated socket object will cause further
- * reads on the channel to return <tt>-1</tt>, the end-of-stream indication.
- * Shutting down the output side of the channel by invoking the {@link
- * java.net.Socket#shutdownOutput shutdownOutput} method of an associated
- * socket object will cause further writes on the channel to throw a {@link
- * ClosedChannelException}.
- *
  * <p> Socket channels support <i>asynchronous shutdown,</i> which is similar
  * to the asynchronous close operation specified in the {@link Channel} class.
  * If the input side of a socket is shut down by one thread while another
@@ -79,6 +62,43 @@
  * channel, then the blocked thread will receive an {@link
  * AsynchronousCloseException}.
  *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Socket channels support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE} </td>
+ *     <td> Keep connection alive </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_LINGER SO_LINGER} </td>
+ *     <td> Linger on close if data is present (when configured in blocking mode
+ *          only) </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#TCP_NODELAY TCP_NODELAY} </td>
+ *     <td> Disable the Nagle algorithm </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
  * <p> Socket channels are safe for use by multiple concurrent threads.  They
  * support concurrent reading and writing, though at most one thread may be
  * reading and at most one thread may be writing at any given time.  The {@link
@@ -87,7 +107,6 @@
  * or write operation while an invocation of one of these methods is in
  * progress will block until that invocation is complete.  </p>
  *
- *
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  * @since 1.4
@@ -95,7 +114,7 @@
 
 public abstract class SocketChannel
     extends AbstractSelectableChannel
-    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
+    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
 {
 
     /**
@@ -192,6 +211,73 @@
     // -- Socket-specific operations --
 
     /**
+     * @throws  ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress on
+     *          this channel
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    @Override
+    public abstract SocketChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    @Override
+    public abstract <T> SocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Shutdown the connection for reading without closing the channel.
+     *
+     * <p> Once shutdown for reading then further reads on the channel will
+     * return {@code -1}, the end-of-stream indication. If the input side of the
+     * connection is already shutdown then invoking this method has no effect.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketChannel shutdownInput() throws IOException;
+
+    /**
+     * Shutdown the connection for writing without closing the channel.
+     *
+     * <p> Once shutdown for writing then further attempts to write to the
+     * channel will throw {@link ClosedChannelException}. If the output side of
+     * the connection is already shutdown then invoking this method has no
+     * effect.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketChannel shutdownOutput() throws IOException;
+
+    /**
      * Retrieves a socket associated with this channel.
      *
      * <p> The returned object will not declare any public methods that are not
@@ -202,10 +288,10 @@
     public abstract Socket socket();
 
     /**
-     * Tells whether or not this channel's network socket is connected.  </p>
+     * Tells whether or not this channel's network socket is connected.
      *
      * @return  <tt>true</tt> if, and only if, this channel's network socket
-     *          is connected
+     *          is {@link #isOpen open} and connected
      */
     public abstract boolean isConnected();
 
@@ -339,6 +425,22 @@
      */
     public abstract boolean finishConnect() throws IOException;
 
+    /**
+     * Returns the remote address to which this channel's socket is connected.
+     *
+     * <p> Where the channel is bound and connected to an Internet Protocol
+     * socket address then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The remote address; {@code null} if the channel is not {@link
+     *          #isOpen open} or the channel's socket is not connected
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketAddress getConnectedAddress() throws IOException;
 
     // -- ByteChannel operations --
 
--- a/src/share/classes/java/nio/channels/exceptions	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/exceptions	Sun Aug 31 18:39:01 2008 +0100
@@ -146,3 +146,14 @@
  * virtual machine, or when another thread is already waiting to lock an
  * overlapping region of the same file." \
  2047812138163068433L
+
+
+SINCE=1.7
+
+SUPER=IllegalStateException
+
+gen AlreadyBoundException "
+ * Unchecked exception thrown when an attempt is made to bind the socket a
+ * network oriented channel that is already bound." \
+ 6796072983322737592L
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/package-info.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2001-2005 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.
+ */
+
+/**
+ * Defines channels, which represent connections to entities that are capable of
+ * performing I/O operations, such as files and sockets; defines selectors, for
+ * multiplexed, non-blocking I/O operations.
+ *
+ * <a name="channels"></a>
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists channels and their descriptions">
+ * <tr><th><p align="left">Channels</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt><i>{@link java.nio.channels.Channel}</i></tt></td>
+ *     <td>A nexus for I/O operations</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ReadableByteChannel}</i></tt></td>
+ *     <td>Can read into a buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.ScatteringByteChannel}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read into a sequence of&nbsp;buffers</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.WritableByteChannel}</i></tt></td>
+ *     <td>Can write from a buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.GatheringByteChannel}</i></tt></td>
+ *     <td>Can write from a sequence of&nbsp;buffers</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ByteChannel}</i></tt></td>
+ *     <td>Can read/write to/from a&nbsp;buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.SeekableByteChannel}</i></tt></td>
+ *     <td>A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.NetworkChannel}</i></tt></td>
+ *     <td>A channel to a network socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.MulticastChannel}</i></tt></td>
+ *     <td>Can join Internet Protocol (IP) multicast groups</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Channels}</tt></td>
+ *     <td>Utility methods for channel/stream interoperation</td></tr>
+ * </table></blockquote>
+ *
+ * <p> A <i>channel</i> represents an open connection to an entity such as a
+ * hardware device, a file, a network socket, or a program component that is
+ * capable of performing one or more distinct I/O operations, for example reading
+ * or writing.  As specified in the {@link java.nio.channels.Channel} interface,
+ * channels are either open or closed, and they are both <i>asynchronously
+ * closeable</i> and <i>interruptible</i>.
+ *
+ * <p> The {@link java.nio.channels.Channel} interface is extended by several
+ * other interfaces.
+ *
+ * <p> The {@link java.nio.channels.ReadableByteChannel} interface specifies a
+ * {@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes
+ * from the channel into a buffer; similarly, the {@link
+ * java.nio.channels.WritableByteChannel} interface specifies a {@link
+ * java.nio.channels.WritableByteChannel#write write} method that writes bytes
+ * from a buffer to the channel. The {@link java.nio.channels.ByteChannel}
+ * interface unifies these two interfaces for the common case of channels that can
+ * both read and write bytes. The {@link java.nio.channels.SeekableByteChannel}
+ * interface extends the {@code ByteChannel} interface with methods to {@link
+ * java.nio.channels.SeekableByteChannel#position() query} and {@link
+ * java.nio.channels.SeekableByteChannel#position(long) modify} the channel's
+ * current position, and its {@link java.nio.channels.SeekableByteChannel#size
+ * size}.
+ *
+ * <p> The {@link java.nio.channels.ScatteringByteChannel} and {@link
+ * java.nio.channels.GatheringByteChannel} interfaces extend the {@link
+ * java.nio.channels.ReadableByteChannel} and {@link
+ * java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link
+ * java.nio.channels.ScatteringByteChannel#read read} and {@link
+ * java.nio.channels.GatheringByteChannel#write write} methods that take a
+ * sequence of buffers rather than a single buffer.
+ *
+ * <p> The {@link java.nio.channels.NetworkChannel} interface specifies methods
+ * to {@link java.nio.channels.NetworkChannel#bind bind} the channel's socket,
+ * obtain the address to which the socket is bound, and methods to {@link
+ * java.nio.channels.NetworkChannel#getOption get} and {@link
+ * java.nio.channels.NetworkChannel#setOption set} socket options. The {@link
+ * java.nio.channels.MulticastChannel} interface specifies methods to join
+ * Internet Protocol (IP) multicast groups.
+ *
+ * <p> The {@link java.nio.channels.Channels} utility class defines static methods
+ * that support the interoperation of the stream classes of the <tt>{@link
+ * java.io}</tt> package with the channel classes of this package.  An appropriate
+ * channel can be constructed from an {@link java.io.InputStream} or an {@link
+ * java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an
+ * {@link java.io.OutputStream} can be constructed from a channel.  A {@link
+ * java.io.Reader} can be constructed that uses a given charset to decode bytes
+ * from a given readable byte channel, and conversely a {@link java.io.Writer} can
+ * be constructed that uses a given charset to encode characters into bytes and
+ * write them to a given writable byte channel.
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists file channels and their descriptions">
+ * <tr><th><p align="left">File channels</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.FileChannel}</tt></td>
+ *     <td>Reads, writes, maps, and manipulates files</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.FileLock}</tt></td>
+ *     <td>A lock on a (region of a) file</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.MappedByteBuffer}/{@link java.nio.MappedBigByteBuffer}&nbsp;&nbsp;</tt></td>
+ *     <td>A direct byte buffer or big byte buffer mapped to a region of a&nbsp;file</td></tr>
+ * </table></blockquote>
+ *
+ * <p> The {@link java.nio.channels.FileChannel} class supports the usual
+ * operations of reading bytes from, and writing bytes to, a channel connected to
+ * a file, as well as those of querying and modifying the current file position
+ * and truncating the file to a specific size.  It defines methods for acquiring
+ * locks on the whole file or on a specific region of a file; these methods return
+ * instances of the {@link java.nio.channels.FileLock} class.  Finally, it defines
+ * methods for forcing updates to the file to be written to the storage device that
+ * contains it, for efficiently transferring bytes between the file and other
+ * channels, and for mapping a region of the file directly into memory.
+ *
+ * <p> A {@code FileChannel} is created by invoking one of its static {@link
+ * java.nio.channels.FileChannel#open open} methods, or by invoking the {@code
+ * getChannel} method of a {@link java.io.FileInputStream}, {@link
+ * java.io.FileOutputStream}, or {@link java.io.RandomAccessFile} to return a
+ * file channel connected to the same underlying file as the <tt>{@link java.io}</tt>
+ * class.
+ *
+ * <a name="multiplex"></a>
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists multiplexed, non-blocking channels and their descriptions">
+ * <tr><th><p align="left">Multiplexed, non-blocking I/O</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.SelectableChannel}</tt></td>
+ *     <td>A channel that can be multiplexed</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.DatagramChannel}</tt></td>
+ *     <td>A channel to a datagram-oriented socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.Pipe.SinkChannel}</tt></td>
+ *     <td>The write end of a pipe</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.Pipe.SourceChannel}</tt></td>
+ *     <td>The read end of a pipe</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.ServerSocketChannel}&nbsp;&nbsp;</tt></td>
+ *     <td>A channel to a stream-oriented listening socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.SocketChannel}</tt></td>
+ *     <td>A channel for a stream-oriented connecting socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Selector}</tt></td>
+ *     <td>A multiplexor of selectable channels</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.SelectionKey}</tt></td>
+ *     <td>A token representing the registration <br> of a channel
+ *     with&nbsp;a&nbsp;selector</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Pipe}</tt></td>
+ *     <td>Two channels that form a unidirectional&nbsp;pipe</td></tr>
+ * </table></blockquote>
+ *
+ * <p> Multiplexed, non-blocking I/O, which is much more scalable than
+ * thread-oriented, blocking I/O, is provided by <i>selectors</i>, <i>selectable
+ * channels</i>, and <i>selection keys</i>.
+ *
+ * <p> A <a href="Selector.html"><i>selector</i></a> is a multiplexor of <a
+ * href="SelectableChannel.html"><i>selectable channels</i></a>, which in turn are
+ * a special type of channel that can be put into <a
+ * href="SelectableChannel.html#bm"><i>non-blocking mode</i></a>.  To perform
+ * multiplexed I/O operations, one or more selectable channels are first created,
+ * put into non-blocking mode, and {@link
+ * java.nio.channels.SelectableChannel#register <i>registered</i>}
+ * with a selector.  Registering a channel specifies the set of I/O operations
+ * that will be tested for readiness by the selector, and returns a <a
+ * href="SelectionKey.html"><i>selection key</i></a> that represents the
+ * registration.
+ *
+ * <p> Once some channels have been registered with a selector, a <a
+ * href="Selector.html#selop"><i>selection operation</i></a> can be performed in
+ * order to discover which channels, if any, have become ready to perform one or
+ * more of the operations in which interest was previously declared.  If a channel
+ * is ready then the key returned when it was registered will be added to the
+ * selector's <i>selected-key set</i>.  The key set, and the keys within it, can
+ * be examined in order to determine the operations for which each channel is
+ * ready.  From each key one can retrieve the corresponding channel in order to
+ * perform whatever I/O operations are required.
+ *
+ * <p> That a selection key indicates that its channel is ready for some operation
+ * is a hint, but not a guarantee, that such an operation can be performed by a
+ * thread without causing the thread to block.  It is imperative that code that
+ * performs multiplexed I/O be written so as to ignore these hints when they prove
+ * to be incorrect.
+ *
+ * <p> This package defines selectable-channel classes corresponding to the {@link
+ * java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link
+ * java.net.Socket} classes defined in the <tt>{@link java.net}</tt> package.
+ * Minor changes to these classes have been made in order to support sockets that
+ * are associated with channels.  This package also defines a simple class that
+ * implements unidirectional pipes.  In all cases, a new selectable channel is
+ * created by invoking the static <tt>open</tt> method of the corresponding class.
+ * If a channel needs an associated socket then a socket will be created as a side
+ * effect of this operation.
+ *
+ * <p> The implementation of selectors, selectable channels, and selection keys
+ * can be replaced by "plugging in" an alternative definition or instance of the
+ * {@link java.nio.channels.spi.SelectorProvider} class defined in the <tt>{@link
+ * java.nio.channels.spi}</tt> package.  It is not expected that many developers
+ * will actually make use of this facility; it is provided primarily so that
+ * sophisticated users can take advantage of operating-system-specific
+ * I/O-multiplexing mechanisms when very high performance is required.
+ *
+ * <p> Much of the bookkeeping and synchronization required to implement the
+ * multiplexed-I/O abstractions is performed by the {@link
+ * java.nio.channels.spi.AbstractInterruptibleChannel}, {@link
+ * java.nio.channels.spi.AbstractSelectableChannel}, {@link
+ * java.nio.channels.spi.AbstractSelectionKey}, and {@link
+ * java.nio.channels.spi.AbstractSelector} classes in the <tt>{@link
+ * java.nio.channels.spi}</tt> package.  When defining a custom selector provider,
+ * only the {@link java.nio.channels.spi.AbstractSelector} and {@link
+ * java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed
+ * directly; custom channel classes should extend the appropriate {@link
+ * java.nio.channels.SelectableChannel} subclasses defined in this package.
+ *
+ * <hr width="80%">
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 1.4
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ */
+
+package java.nio.channels;
--- a/src/share/classes/java/nio/channels/package.html	Sun Aug 31 18:32:59 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-<!--
- Copyright 2001-2005 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.
--->
-
-<!doctype html public "-//IETF//DTD HTML//EN">
-<html>
-<body bgcolor="white">
-
-Defines channels, which represent connections to entities that are capable of
-performing I/O operations, such as files and sockets; defines selectors, for
-multiplexed, non-blocking I/O operations.
-
-
-<a name="channels">
-
-<blockquote><table cellspacing=1 cellpadding=0 summary="Lists channels and their descriptions">
-  <tr><th><p align="left">Channels</p></th><th><p align="left">Description</p></th></tr>
-  <tr><td valign=top><tt><i>{@link java.nio.channels.Channel}</i></tt></td>
-      <td>A nexus for I/O operations</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ReadableByteChannel}</i></tt></td>
-      <td>Can read into a buffer</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.ScatteringByteChannel}&nbsp;&nbsp;</i></tt></td>
-      <td>Can read into a sequence of&nbsp;buffers</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.WritableByteChannel}</i></tt></td>
-      <td>Can write from a buffer</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.GatheringByteChannel}</i></tt></td>
-      <td>Can write from a sequence of&nbsp;buffers</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ByteChannel}</i></tt></td>
-      <td>Can read/write to/from a&nbsp;buffer</td></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.Channels}</tt></td>
-      <td>Utility methods for channel/stream interoperation</td></tr>
-</table></blockquote>
-
-<p> A <i>channel</i> represents an open connection to an entity such as a
-hardware device, a file, a network socket, or a program component that is
-capable of performing one or more distinct I/O operations, for example reading
-or writing.  As specified in the {@link java.nio.channels.Channel} interface,
-channels are either open or closed, and they are both <i>asynchronously
-closeable</i> and <i>interruptible</i>.
-
-<p> The {@link java.nio.channels.Channel} interface is extended by several
-other interfaces, each of which specifies a new I/O operation.
-
-<p> The {@link java.nio.channels.ReadableByteChannel} interface specifies a
-{@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes
-from the channel into a buffer; similarly, the {@link
-java.nio.channels.WritableByteChannel} interface specifies a {@link
-java.nio.channels.WritableByteChannel#write write} method that writes bytes
-from a buffer to the channel.  The {@link java.nio.channels.ByteChannel}
-interface unifies these two interfaces for the common case of channels that can
-both read and write bytes.
-
-<p> The {@link java.nio.channels.ScatteringByteChannel} and {@link
-java.nio.channels.GatheringByteChannel} interfaces extend the {@link
-java.nio.channels.ReadableByteChannel} and {@link
-java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link
-java.nio.channels.ScatteringByteChannel#read read} and {@link
-java.nio.channels.GatheringByteChannel#write write} methods that take a
-sequence of buffers rather than a single buffer.
-
-<p> The {@link java.nio.channels.Channels} utility class defines static methods
-that support the interoperation of the stream classes of the <tt>{@link
-java.io}</tt> package with the channel classes of this package.  An appropriate
-channel can be constructed from an {@link java.io.InputStream} or an {@link
-java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an
-{@link java.io.OutputStream} can be constructed from a channel.  A {@link
-java.io.Reader} can be constructed that uses a given charset to decode bytes
-from a given readable byte channel, and conversely a {@link java.io.Writer} can
-be constructed that uses a given charset to encode characters into bytes and
-write them to a given writable byte channel.
-
-
-<blockquote><table cellspacing=1 cellpadding=0 summary="Lists file channels and their descriptions">
-<tr><th><p align="left">File channels</p></th><th><p align="left">Description</p></th></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.FileChannel}</tt></td>
-      <td>Reads, writes, maps, and manipulates files</td></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.FileLock}</tt></td>
-      <td>A lock on a (region of a) file</td></tr>
-  <tr><td valign=top><tt>{@link java.nio.MappedByteBuffer}&nbsp;&nbsp;</tt></td>
-      <td>A direct byte buffer mapped to a region of a&nbsp;file</td></tr>
-</table></blockquote>
-
-<p> The {@link java.nio.channels.FileChannel} class supports the usual
-operations of reading bytes from, and writing bytes to, a channel connected to
-a file, as well as those of querying and modifying the current file position
-and truncating the file to a specific size.  It defines methods for acquiring
-locks on the whole file or on a specific region of a file; these methods return
-instances of the {@link java.nio.channels.FileLock} class.  Finally, it defines
-methods for forcing updates to the file to be written to the storage device that
-contains it, for efficiently transferring bytes between the file and other
-channels, and for mapping a region of the file directly into memory.  This last
-operation creates an instance of the {@link java.nio.MappedByteBuffer}
-class, which extends the {@link java.nio.ByteBuffer} class with several
-file-related operations.
-
-<p> A <tt>getChannel</tt> method has been added to each of the {@link
-java.io.FileInputStream#getChannel FileInputStream}, {@link
-java.io.FileOutputStream#getChannel FileOutputStream}, and {@link
-java.io.RandomAccessFile#getChannel RandomAccessFile} classes of the <tt>{@link
-java.io java.io}</tt> package.  Invoking this method upon an instance of one of
-these classes will return a file channel connected to the underlying file.
-
-
-<a name="multiplex">
-
-<blockquote><table cellspacing=1 cellpadding=0 summary="Lists multiplexed, non-blocking channels and their descriptions">
-  <tr><th><p align="left">Multiplexed, non-blocking I/O</p></th><th><p align="left">Description</p></th></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.SelectableChannel}</tt></td>
-      <td>A channel that can be multiplexed</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.DatagramChannel}</tt></td>
-      <td>A channel for a {@link java.net.DatagramSocket java.net.DatagramSocket}</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.Pipe.SinkChannel}</tt></td>
-      <td>The write end of a pipe</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.Pipe.SourceChannel}</tt></td>
-      <td>The read end of a pipe</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.ServerSocketChannel}&nbsp;&nbsp;</tt></td>
-      <td>A channel for a {@link java.net.ServerSocket java.net.ServerSocket}</td></tr>
-  <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.SocketChannel}</tt></td>
-      <td>A channel for a {@link java.net.Socket java.net.Socket}</td></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.Selector}</tt></td>
-      <td>A multiplexor of selectable channels</td></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.SelectionKey}</tt></td>
-      <td>A token representing the registration <br> of a channel
-          with&nbsp;a&nbsp;selector</td></tr>
-  <tr><td valign=top><tt>{@link java.nio.channels.Pipe}</tt></td>
-      <td>Two channels that form a unidirectional&nbsp;pipe</td></tr>
-</table></blockquote>
-
-<p> Multiplexed, non-blocking I/O, which is much more scalable than
-thread-oriented, blocking I/O, is provided by <i>selectors</i>, <i>selectable
-channels</i>, and <i>selection keys</i>.
-
-<p> A <a href="Selector.html"><i>selector</i></a> is a multiplexor of <a
-href="SelectableChannel.html"><i>selectable channels</i></a>, which in turn are
-a special type of channel that can be put into <a
-href="SelectableChannel.html#bm"><i>non-blocking mode</i></a>.  To perform
-multiplexed I/O operations, one or more selectable channels are first created,
-put into non-blocking mode, and {@link
-java.nio.channels.SelectableChannel#register </code><i>registered</i><code>}
-with a selector.  Registering a channel specifies the set of I/O operations
-that will be tested for readiness by the selector, and returns a <a
-href="SelectionKey.html"><i>selection key</i></a> that represents the
-registration.
-
-<p> Once some channels have been registered with a selector, a <a
-href="Selector.html#selop"><i>selection operation</i></a> can be performed in
-order to discover which channels, if any, have become ready to perform one or
-more of the operations in which interest was previously declared.  If a channel
-is ready then the key returned when it was registered will be added to the
-selector's <i>selected-key set</i>.  The key set, and the keys within it, can
-be examined in order to determine the operations for which each channel is
-ready.  From each key one can retrieve the corresponding channel in order to
-perform whatever I/O operations are required.
-
-<p> That a selection key indicates that its channel is ready for some operation
-is a hint, but not a guarantee, that such an operation can be performed by a
-thread without causing the thread to block.  It is imperative that code that
-performs multiplexed I/O be written so as to ignore these hints when they prove
-to be incorrect.
-
-<p> This package defines selectable-channel classes corresponding to the {@link
-java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link
-java.net.Socket} classes defined in the <tt>{@link java.net}</tt> package.
-Minor changes to these classes have been made in order to support sockets that
-are associated with channels.  This package also defines a simple class that
-implements unidirectional pipes.  In all cases, a new selectable channel is
-created by invoking the static <tt>open</tt> method of the corresponding class.
-If a channel needs an associated socket then a socket will be created as a side
-effect of this operation.
-
-<p> The implementation of selectors, selectable channels, and selection keys
-can be replaced by "plugging in" an alternative definition or instance of the
-{@link java.nio.channels.spi.SelectorProvider} class defined in the <tt>{@link
-java.nio.channels.spi}</tt> package.  It is not expected that many developers
-will actually make use of this facility; it is provided primarily so that
-sophisticated users can take advantage of operating-system-specific
-I/O-multiplexing mechanisms when very high performance is required.
-
-<p> Much of the bookkeeping and synchronization required to implement the
-multiplexed-I/O abstractions is performed by the {@link
-java.nio.channels.spi.AbstractInterruptibleChannel}, {@link
-java.nio.channels.spi.AbstractSelectableChannel}, {@link
-java.nio.channels.spi.AbstractSelectionKey}, and {@link
-java.nio.channels.spi.AbstractSelector} classes in the <tt>{@link
-java.nio.channels.spi}</tt> package.  When defining a custom selector provider,
-only the {@link java.nio.channels.spi.AbstractSelector} and {@link
-java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed
-directly; custom channel classes should extend the appropriate {@link
-java.nio.channels.SelectableChannel} subclasses defined in this package.
-
-<p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
-or method in any class or interface in this package will cause a {@link
-java.lang.NullPointerException NullPointerException} to be thrown.
-
-
-@since 1.4
-@author Mark Reinhold
-@author JSR-51 Expert Group
-
-</body>
-</html>
--- a/src/share/classes/java/nio/channels/spi/SelectorProvider.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/spi/SelectorProvider.java	Sun Aug 31 18:39:01 2008 +0100
@@ -25,10 +25,8 @@
 
 package java.nio.channels.spi;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
+import java.net.ProtocolFamily;
 import java.nio.channels.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -190,7 +188,25 @@
         throws IOException;
 
     /**
-     * Opens a pipe.  </p>
+     * Opens a datagram channel.
+     *
+     * @param   family
+     *          The protocol family
+     *
+     * @return  A new datagram channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the specified protocol family is not supported
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract DatagramChannel openDatagramChannel(ProtocolFamily family)
+        throws IOException;
+
+    /**
+     * Opens a pipe. </p>
      *
      * @return  The new pipe
      */
--- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Sun Aug 31 18:39:01 2008 +0100
@@ -31,7 +31,7 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.*;
 import java.nio.channels.spi.*;
-import java.lang.ref.SoftReference;
+import java.util.*;
 
 
 /**
@@ -47,11 +47,14 @@
     private static NativeDispatcher nd = new DatagramDispatcher();
 
     // Our file descriptor
-    FileDescriptor fd = null;
+    private final FileDescriptor fd;
 
     // fd value needed for dev/poll. This value will remain valid
     // even after the value in the file descriptor object has been set to -1
-    int fdVal;
+    private final int fdVal;
+
+    // The protocol family of the socket
+    private final ProtocolFamily family;
 
     // IDs of native threads doing reads and writes, for signalling
     private volatile long readerThread = 0;
@@ -59,8 +62,8 @@
 
     // Cached InetAddress and port for unconnected DatagramChannels
     // used by receive0
-    private InetAddress cachedSenderInetAddress = null;
-    private int cachedSenderPort = 0;
+    private InetAddress cachedSenderInetAddress;
+    private int cachedSenderPort;
 
     // Lock held by current reading or connecting thread
     private final Object readLock = new Object();
@@ -76,20 +79,20 @@
 
     // State (does not necessarily increase monotonically)
     private static final int ST_UNINITIALIZED = -1;
-    private static int ST_UNCONNECTED = 0;
-    private static int ST_CONNECTED = 1;
+    private static final int ST_UNCONNECTED = 0;
+    private static final int ST_CONNECTED = 1;
     private static final int ST_KILLED = 2;
     private int state = ST_UNINITIALIZED;
 
     // Binding
-    private SocketAddress localAddress = null;
-    SocketAddress remoteAddress = null;
-
-    // Options
-    private SocketOpts.IP options = null;
+    private SocketAddress localAddress;
+    private SocketAddress remoteAddress;
 
     // Our socket adaptor, if any
-    private DatagramSocket socket = null;
+    private DatagramSocket socket;
+
+    // Multicast support
+    private MembershipRegistry registry;
 
     // -- End of fields protected by stateLock
 
@@ -98,7 +101,26 @@
         throws IOException
     {
         super(sp);
-        this.fd = Net.socket(false);
+        this.family = Net.isIPv6Available() ?
+            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+        this.fd = Net.socket(family, false);
+        this.fdVal = IOUtil.fdVal(fd);
+        this.state = ST_UNCONNECTED;
+    }
+
+    public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) {
+        super(sp);
+        if ((family != StandardProtocolFamily.INET) &&
+            (family != StandardProtocolFamily.INET6)) {
+            throw new UnsupportedOperationException("Protocol family not supported");
+        }
+        if (family == StandardProtocolFamily.INET6) {
+            if (!Net.isIPv6Available()) {
+                throw new UnsupportedOperationException("IPv6 not available");
+            }
+        }
+        this.family = family;
+        this.fd = Net.socket(family, false);
         this.fdVal = IOUtil.fdVal(fd);
         this.state = ST_UNCONNECTED;
     }
@@ -107,9 +129,12 @@
         throws IOException
     {
         super(sp);
+        this.family = Net.isIPv6Available() ?
+            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
         this.fd = fd;
         this.fdVal = IOUtil.fdVal(fd);
         this.state = ST_UNCONNECTED;
+        this.localAddress = Net.localAddress(fd);
     }
 
     public DatagramSocket socket() {
@@ -120,6 +145,156 @@
         }
     }
 
+    @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 DatagramChannel 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) {
+            ensureOpen();
+
+            if (name == StandardSocketOption.IP_TOS) {
+                // IPv4 only; no-op for IPv6
+                if (family == StandardProtocolFamily.INET) {
+                    Net.setSocketOption(fd, family, name, value);
+                }
+                return this;
+            }
+
+            if (name == StandardSocketOption.IP_MULTICAST_TTL ||
+                name == StandardSocketOption.IP_MULTICAST_LOOP)
+            {
+                // options are protocol dependent
+                Net.setSocketOption(fd, family, name, value);
+                return this;
+            }
+
+            if (name == StandardSocketOption.IP_MULTICAST_IF) {
+                if (value == null)
+                    throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'");
+                NetworkInterface interf = (NetworkInterface)value;
+                if (family == StandardProtocolFamily.INET6) {
+                    int index = interf.getIndex();
+                    if (index == -1)
+                        throw new IOException("Network interface cannot be identified");
+                    Net.setInterface6(fd, index);
+                } else {
+                    // need IPv4 address to identify interface
+                    Inet4Address target = Net.anyInet4Address(interf);
+                    if (target == null)
+                        throw new IOException("Network interface not configured for IPv4");
+                    int targetAddress = Net.inet4AsInt(target);
+                    Net.setInterface4(fd, targetAddress);
+                }
+                return this;
+            }
+
+            // remaining options don't need any 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) {
+            ensureOpen();
+
+            if (name == StandardSocketOption.IP_TOS) {
+                // IPv4 only; always return 0 on IPv6
+                if (family == StandardProtocolFamily.INET) {
+                    return (T) Net.getSocketOption(fd, family, name);
+                } else {
+                    return (T) Integer.valueOf(0);
+                }
+            }
+
+            if (name == StandardSocketOption.IP_MULTICAST_TTL ||
+                name == StandardSocketOption.IP_MULTICAST_LOOP)
+            {
+                return (T) Net.getSocketOption(fd, family, name);
+            }
+
+            if (name == StandardSocketOption.IP_MULTICAST_IF) {
+                if (family == StandardProtocolFamily.INET) {
+                    int address = Net.getInterface4(fd);
+                    if (address == 0)
+                        return null;    // default interface
+
+                    InetAddress ia = Net.inet4FromInt(address);
+                    NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
+                    if (ni == null)
+                        throw new IOException("Unable to map address to interface");
+                    return (T) ni;
+                } else {
+                    int index = Net.getInterface6(fd);
+                    if (index == 0)
+                        return null;    // default interface
+
+                    NetworkInterface ni = NetworkInterface.getByIndex(index);
+                    if (ni == null)
+                        throw new IOException("Unable to map index to interface");
+                    return (T) ni;
+                }
+            }
+
+            // no 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_REUSEADDR);
+            set.add(StandardSocketOption.SO_BROADCAST);
+            set.add(StandardSocketOption.IP_TOS);
+            set.add(StandardSocketOption.IP_MULTICAST_IF);
+            set.add(StandardSocketOption.IP_MULTICAST_TTL);
+            set.add(StandardSocketOption.IP_MULTICAST_LOOP);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> options() {
+        return LazyInitialization.defaultOptions;
+    }
+
     private void ensureOpen() throws ClosedChannelException {
         if (!isOpen())
             throw new ClosedChannelException();
@@ -135,8 +310,10 @@
         synchronized (readLock) {
             ensureOpen();
             // If socket is not bound then behave as if nothing received
-            if (!isBound())             // ## NotYetBoundException ??
+            // Will be fixed by 6621699
+            if (localAddress() == null) {
                 return null;
+            }
             int n = 0;
             ByteBuffer bb = null;
             try {
@@ -267,6 +444,12 @@
                 do {
                     n = send(fd, src, target);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
+
+                synchronized (stateLock) {
+                    if (isOpen() && (localAddress == null)) {
+                        localAddress = Net.localAddress(fd);
+                    }
+                }
                 return IOStatus.normalize(n);
             } finally {
                 writerThread = 0;
@@ -316,7 +499,8 @@
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
 
-        int written = send0(fd, ((DirectBuffer)bb).address() + pos,
+        boolean preferIPv6 = (family != StandardProtocolFamily.INET);
+        int written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
                             rem, target);
         if (written > 0)
             bb.position(pos + written);
@@ -453,42 +637,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(d);
-            }
-            return options;
-        }
-    }
-
-    public boolean isBound() {
-        return Net.localPortNumber(fd) != 0;
-    }
-
     public SocketAddress localAddress() {
         synchronized (stateLock) {
-            if (isConnected() && (localAddress == null)) {
-                // Socket was not bound before connecting,
-                // so ask what the address turned out to be
-                localAddress = Net.localAddress(fd);
-            }
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                InetSocketAddress isa = (InetSocketAddress)localAddress;
-                sm.checkConnect(isa.getAddress().getHostAddress(), -1);
-            }
             return localAddress;
         }
     }
@@ -499,22 +649,37 @@
         }
     }
 
-    public void bind(SocketAddress local) throws IOException {
+    @Override
+    public DatagramChannel bind(SocketAddress local) throws IOException {
         synchronized (readLock) {
             synchronized (writeLock) {
                 synchronized (stateLock) {
                     ensureOpen();
-                    if (isBound())
+                    if (localAddress != null)
                         throw new AlreadyBoundException();
-                    InetSocketAddress isa = Net.checkAddress(local);
+                    InetSocketAddress isa;
+                    if (local == null) {
+                        isa = new InetSocketAddress(0);
+                    } else {
+                        isa = Net.checkAddress(local);
+
+                        // only Inet4Address allowed with IPv4 socket
+                        if (family == StandardProtocolFamily.INET) {
+                            InetAddress addr = isa.getAddress();
+                            if (!(addr instanceof Inet4Address))
+                                throw new UnsupportedAddressTypeException();
+                        }
+                    }
                     SecurityManager sm = System.getSecurityManager();
-                    if (sm != null)
+                    if (sm != null) {
                         sm.checkListen(isa.getPort());
-                    Net.bind(fd, isa.getAddress(), isa.getPort());
+                    }
+                    Net.bind(family, fd, isa.getAddress(), isa.getPort());
                     localAddress = Net.localAddress(fd);
                 }
             }
         }
+        return this;
     }
 
     public boolean isConnected() {
@@ -533,7 +698,6 @@
     }
 
     public DatagramChannel connect(SocketAddress sa) throws IOException {
-        int trafficClass = 0;
         int localPort = 0;
 
         synchronized(readLock) {
@@ -545,10 +709,10 @@
                     if (sm != null)
                         sm.checkConnect(isa.getAddress().getHostAddress(),
                                         isa.getPort());
-                    int n = Net.connect(fd,
+                    int n = Net.connect(family,
+                                        fd,
                                         isa.getAddress(),
-                                        isa.getPort(),
-                                        trafficClass);
+                                        isa.getPort());
                     if (n <= 0)
                         throw new Error();      // Can't happen
 
@@ -558,6 +722,11 @@
                     sender = isa;
                     cachedSenderInetAddress = isa.getAddress();
                     cachedSenderPort = isa.getPort();
+
+                    // Socket was not bound before connecting,
+                    if (localAddress == null) {
+                        localAddress = Net.localAddress(fd);
+                    }
                 }
             }
         }
@@ -584,9 +753,215 @@
         return this;
     }
 
+    /**
+     * Joins channel's socket to the given group/interface and
+     * optional source address.
+     */
+    private MembershipKey innerJoin(InetAddress group,
+                                    NetworkInterface interf,
+                                    InetAddress source)
+        throws IOException
+    {
+        if (!group.isMulticastAddress())
+            throw new IllegalArgumentException("Group not a multicast address");
+
+        // check multicast address is compatible with this socket
+        if (!(group instanceof Inet4Address)) {
+            if (family == StandardProtocolFamily.INET)
+                throw new IllegalArgumentException("Group is not IPv4 address");
+            if (!(group instanceof Inet6Address))
+                throw new IllegalArgumentException("Address type not supported");
+        }
+
+        // check source address
+        if (source != null) {
+            if (source.isAnyLocalAddress())
+                throw new IllegalArgumentException("Source address is a wildcard address");
+            if (source.isMulticastAddress())
+                throw new IllegalArgumentException("Source address is multicast address");
+            if (source.getClass() != group.getClass())
+                throw new IllegalArgumentException("Source address is different type to group");
+        }
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkMulticast(group);
+
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            // check the registry to see if we are already a member of the group
+            if (registry == null) {
+                registry = new MembershipRegistry();
+            } else {
+                // return existing membership key
+                MembershipKey key = registry.checkMembership(group, interf, source);
+                if (key != null)
+                    return key;
+            }
+
+            MembershipKeyImpl key;
+            if (family == StandardProtocolFamily.INET6) {
+                int index = interf.getIndex();
+                if (index == -1)
+                    throw new IOException("Network interface cannot be identified");
+
+                // need multicast and source address as byte arrays
+                byte[] groupAddress = Net.inet6AsByteArray(group);
+                byte[] sourceAddress = (source == null) ? null :
+                    Net.inet6AsByteArray(source);
+
+                // join the group
+                int n = Net.join6(fd, groupAddress, index, sourceAddress);
+                if (n == IOStatus.UNAVAILABLE)
+                    throw new UnsupportedOperationException();
+
+                key = new MembershipKeyImpl.Type6(this, group, interf, source,
+                                                  groupAddress, index, sourceAddress);
+
+            } else {
+                // need IPv4 address to identify interface
+                Inet4Address target = Net.anyInet4Address(interf);
+                if (target == null)
+                    throw new IOException("Network interface not configured for IPv4");
+
+                int groupAddress = Net.inet4AsInt(group);
+                int targetAddress = Net.inet4AsInt(target);
+                int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
+
+                // join the group
+                int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
+                if (n == IOStatus.UNAVAILABLE)
+                    throw new UnsupportedOperationException();
+
+                key = new MembershipKeyImpl.Type4(this, group, interf, source,
+                                                  groupAddress, targetAddress, sourceAddress);
+            }
+
+            registry.add(key);
+            return key;
+        }
+    }
+
+    @Override
+    public MembershipKey join(InetAddress group,
+                              NetworkInterface interf)
+        throws IOException
+    {
+        return innerJoin(group, interf, null);
+    }
+
+    @Override
+    public MembershipKey join(InetAddress group,
+                              NetworkInterface interf,
+                              InetAddress source)
+        throws IOException
+    {
+        if (source == null)
+            throw new NullPointerException("source address is null");
+        return innerJoin(group, interf, source);
+    }
+
+    // package-private
+    void drop(MembershipKeyImpl key)
+        throws IOException
+    {
+        assert key.getChannel() == this;
+
+        synchronized (stateLock) {
+            if (!key.isValid())
+                return;
+
+            if (family == StandardProtocolFamily.INET6) {
+                MembershipKeyImpl.Type6 key6 =
+                    (MembershipKeyImpl.Type6)key;
+                Net.drop6(fd, key6.group(), key6.index(), key6.source());
+            } else {
+                MembershipKeyImpl.Type4 key4 =
+                    (MembershipKeyImpl.Type4)key;
+                Net.drop4(fd, key4.group(), key4.interfaceAddress(), key4.source());
+            }
+
+            key.invalidate();
+            registry.remove(key);
+        }
+    }
+
+    /**
+     * Block datagrams from given source if a memory to receive all
+     * datagrams.
+     */
+    void block(MembershipKeyImpl key, InetAddress source)
+        throws IOException
+    {
+        assert key.getChannel() == this;
+        assert key.getSourceAddress() == null;
+
+        synchronized (stateLock) {
+            if (!key.isValid())
+                throw new IllegalStateException("key is no longer valid");
+            if (source.isAnyLocalAddress())
+                throw new IllegalArgumentException("Source address is a wildcard address");
+            if (source.isMulticastAddress())
+                throw new IllegalArgumentException("Source address is multicast address");
+            if (source.getClass() != key.getGroup().getClass())
+                throw new IllegalArgumentException("Source address is different type to group");
+
+            int n;
+            if (family == StandardProtocolFamily.INET6) {
+                 MembershipKeyImpl.Type6 key6 =
+                    (MembershipKeyImpl.Type6)key;
+                n = Net.block6(fd, key6.group(), key6.index(),
+                               Net.inet6AsByteArray(source));
+            } else {
+                MembershipKeyImpl.Type4 key4 =
+                    (MembershipKeyImpl.Type4)key;
+                n = Net.block4(fd, key4.group(), key4.interfaceAddress(),
+                               Net.inet4AsInt(source));
+            }
+            if (n == IOStatus.UNAVAILABLE) {
+                // ancient kernel
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+
+    /**
+     * Unblock given source.
+     */
+    void unblock(MembershipKeyImpl key, InetAddress source)
+        throws IOException
+    {
+        assert key.getChannel() == this;
+        assert key.getSourceAddress() == null;
+
+        synchronized (stateLock) {
+            if (!key.isValid())
+                throw new IllegalStateException("key is no longer valid");
+
+            if (family == StandardProtocolFamily.INET6) {
+                MembershipKeyImpl.Type6 key6 =
+                    (MembershipKeyImpl.Type6)key;
+                Net.unblock6(fd, key6.group(), key6.index(),
+                             Net.inet6AsByteArray(source));
+            } else {
+                MembershipKeyImpl.Type4 key4 =
+                    (MembershipKeyImpl.Type4)key;
+                Net.unblock4(fd, key4.group(), key4.interfaceAddress(),
+                             Net.inet4AsInt(source));
+            }
+        }
+    }
+
     protected void implCloseSelectableChannel() throws IOException {
         synchronized (stateLock) {
             nd.preClose(fd);
+
+            // if member of mulitcast group then invalidate all keys
+            if (registry != null)
+                registry.invalidateAll();
+
             long th;
             if ((th = readerThread) != 0)
                 NativeThread.signal(th);
@@ -695,8 +1070,8 @@
                                 boolean connected)
         throws IOException;
 
-    private native int send0(FileDescriptor fd, long address, int len,
-                     SocketAddress sa)
+    private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len,
+                             SocketAddress sa)
         throws IOException;
 
     static {
--- a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java	Sun Aug 31 18:39:01 2008 +0100
@@ -45,16 +45,9 @@
     // The channel being adapted
     private final DatagramChannelImpl dc;
 
-    // Option adaptor object, created on demand
-    private volatile OptionAdaptor opts = null;
-
     // Timeout "option" value for receives
     private volatile int timeout = 0;
 
-    // Traffic-class/Type-of-service
-    private volatile int trafficClass = 0;
-
-
     // ## super will create a useless impl
     private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
         // Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
@@ -82,7 +75,7 @@
             throw new IllegalArgumentException("connect: " + port);
         if (remote == null)
             throw new IllegalArgumentException("connect: null address");
-        if (!isClosed())
+        if (isClosed())
             return;
         try {
             dc.connect(remote);
@@ -124,11 +117,11 @@
     }
 
     public boolean isBound() {
-        return dc.isBound();
+        return dc.localAddress() != null;
     }
 
     public boolean isConnected() {
-        return dc.isConnected();
+        return dc.remoteAddress() != null;
     }
 
     public InetAddress getInetAddress() {
@@ -157,7 +150,7 @@
                             // Legacy DatagramSocket will send in this case
                             // and set address and port of the packet
                             InetSocketAddress isa = (InetSocketAddress)
-                                                    dc.remoteAddress;
+                                                    dc.remoteAddress();
                             p.setPort(isa.getPort());
                             p.setAddress(isa.getAddress());
                             dc.write(bb);
@@ -241,21 +234,32 @@
     public InetAddress getLocalAddress() {
         if (isClosed())
             return null;
-        try {
-            return Net.asInetSocketAddress(dc.localAddress()).getAddress();
-        } catch (Exception x) {
-            return new InetSocketAddress(0).getAddress();
+        SocketAddress local = dc.localAddress();
+        if (local == null)
+            local = new InetSocketAddress(0);
+        InetAddress result = ((InetSocketAddress)local).getAddress();
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                sm.checkConnect(result.getHostAddress(), -1);
+            } catch (SecurityException x) {
+                return new InetSocketAddress(0).getAddress();
+            }
         }
+        return result;
     }
 
     public int getLocalPort() {
         if (isClosed())
             return -1;
         try {
-            return Net.asInetSocketAddress(dc.localAddress()).getPort();
+            SocketAddress local = dc.getLocalAddress();
+            if (local != null) {
+                return ((InetSocketAddress)local).getPort();
+            }
         } catch (Exception x) {
-            return 0;
         }
+        return 0;
     }
 
     public void setSoTimeout(int timeout) throws SocketException {
@@ -266,55 +270,87 @@
         return timeout;
     }
 
-    private OptionAdaptor opts() {
-        if (opts == null)
-            opts = new OptionAdaptor(dc);
-        return opts;
+    private void setBooleanOption(SocketOption<Boolean> name, boolean value)
+        throws SocketException
+    {
+        try {
+            dc.setOption(name, value);
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+        }
+    }
+
+    private void setIntOption(SocketOption<Integer> name, int value)
+        throws SocketException
+    {
+        try {
+            dc.setOption(name, value);
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+        }
+    }
+
+    private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
+        try {
+            return dc.getOption(name).booleanValue();
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+            return false;       // keep compiler happy
+        }
+    }
+
+    private int getIntOption(SocketOption<Integer> name) throws SocketException {
+        try {
+            return dc.getOption(name).intValue();
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+            return -1;          // keep compiler happy
+        }
     }
 
     public void setSendBufferSize(int size) throws SocketException {
-        opts().setSendBufferSize(size);
+        if (size <= 0)
+            throw new IllegalArgumentException("Invalid send size");
+        setIntOption(StandardSocketOption.SO_SNDBUF, size);
     }
 
     public int getSendBufferSize() throws SocketException {
-        return opts().getSendBufferSize();
+        return getIntOption(StandardSocketOption.SO_SNDBUF);
     }
 
     public void setReceiveBufferSize(int size) throws SocketException {
-        opts().setReceiveBufferSize(size);
+        if (size <= 0)
+            throw new IllegalArgumentException("Invalid receive size");
+        setIntOption(StandardSocketOption.SO_RCVBUF, size);
     }
 
     public int getReceiveBufferSize() throws SocketException {
-        return opts().getReceiveBufferSize();
+        return getIntOption(StandardSocketOption.SO_RCVBUF);
     }
 
     public void setReuseAddress(boolean on) throws SocketException {
-        opts().setReuseAddress(on);
+        setBooleanOption(StandardSocketOption.SO_REUSEADDR, on);
     }
 
     public boolean getReuseAddress() throws SocketException {
-        return opts().getReuseAddress();
+        return getBooleanOption(StandardSocketOption.SO_REUSEADDR);
+
     }
 
     public void setBroadcast(boolean on) throws SocketException {
-        opts().setBroadcast(on);
+        setBooleanOption(StandardSocketOption.SO_BROADCAST, on);
     }
 
     public boolean getBroadcast() throws SocketException {
-        return opts().getBroadcast();
+        return getBooleanOption(StandardSocketOption.SO_BROADCAST);
     }
 
     public void setTrafficClass(int tc) throws SocketException {
-        opts().setTrafficClass(tc);
-        trafficClass = tc;
+        setIntOption(StandardSocketOption.IP_TOS, tc);
     }
 
     public int getTrafficClass() throws SocketException {
-        int tc = opts().getTrafficClass();
-        if (tc < 0) {
-            tc = trafficClass;
-        }
-        return tc;
+        return getIntOption(StandardSocketOption.IP_TOS);
     }
 
     public void close() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007-2008 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.nio.ch;
+
+import java.net.SocketOption;
+
+/**
+ * Defines socket options that are supported by the implementation
+ * but not defined in StandardSocketOption.
+ */
+
+class ExtendedSocketOption {
+    private ExtendedSocketOption() { }
+
+    static final SocketOption<Boolean> SO_OOBINLINE =
+        new SocketOption<Boolean>() {
+            public String name() { return "SO_OOBINLINE"; }
+            public Class<Boolean> type() { return Boolean.class; }
+            public String toString() { return name(); }
+        };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2007-2008 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.nio.ch;
+
+import java.nio.channels.*;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.util.HashSet;
+
+/**
+ * MembershipKey implementation.
+ */
+
+class MembershipKeyImpl
+    extends MembershipKey
+{
+    private final MulticastChannel ch;
+    private final InetAddress group;
+    private final NetworkInterface interf;
+    private final InetAddress source;
+
+    // true when key is valid
+    private volatile boolean valid = true;
+
+    // lock used when creating or accessing blockedSet
+    private Object stateLock = new Object();
+
+    // set of source addresses that are blocked
+    private HashSet<InetAddress> blockedSet;
+
+    private MembershipKeyImpl(MulticastChannel ch,
+                              InetAddress group,
+                              NetworkInterface interf,
+                              InetAddress source)
+    {
+        this.ch = ch;
+        this.group = group;
+        this.interf = interf;
+        this.source = source;
+    }
+
+    /**
+     * MembershipKey will additional context for IPv4 membership
+     */
+    static class Type4 extends MembershipKeyImpl {
+        private final int groupAddress;
+        private final int interfAddress;
+        private final int sourceAddress;
+
+        Type4(MulticastChannel ch,
+              InetAddress group,
+              NetworkInterface interf,
+              InetAddress source,
+              int groupAddress,
+              int interfAddress,
+              int sourceAddress)
+        {
+            super(ch, group, interf, source);
+            this.groupAddress = groupAddress;
+            this.interfAddress = interfAddress;
+            this.sourceAddress = sourceAddress;
+        }
+
+        int group() {
+            return groupAddress;
+        }
+
+        int interfaceAddress() {
+            return interfAddress;
+        }
+
+        int source() {
+            return sourceAddress;
+        }
+    }
+
+    /**
+     * MembershipKey will additional context for IPv6 membership
+     */
+    static class Type6 extends MembershipKeyImpl {
+        private final byte[] groupAddress;
+        private final int index;
+        private final byte[] sourceAddress;
+
+        Type6(MulticastChannel ch,
+              InetAddress group,
+              NetworkInterface interf,
+              InetAddress source,
+              byte[] groupAddress,
+              int index,
+              byte[] sourceAddress)
+        {
+            super(ch, group, interf, source);
+            this.groupAddress = groupAddress;
+            this.index = index;
+            this.sourceAddress = sourceAddress;
+        }
+
+        byte[] group() {
+            return groupAddress;
+        }
+
+        int index() {
+            return index;
+        }
+
+        byte[] source() {
+            return sourceAddress;
+        }
+    }
+
+    public boolean isValid() {
+        return valid;
+    }
+
+    // package-private
+    void invalidate() {
+        valid = false;
+    }
+
+    public void drop() throws IOException {
+        // delegate to channel
+        ((DatagramChannelImpl)ch).drop(this);
+    }
+
+    @Override
+    public MulticastChannel getChannel() {
+        return ch;
+    }
+
+    @Override
+    public InetAddress getGroup() {
+        return group;
+    }
+
+    @Override
+    public NetworkInterface getNetworkInterface() {
+        return interf;
+    }
+
+    @Override
+    public InetAddress getSourceAddress() {
+        return source;
+    }
+
+    @Override
+    public MembershipKey block(InetAddress toBlock)
+        throws IOException
+    {
+        if (source != null)
+            throw new IllegalStateException("key is source-specific");
+
+        synchronized (stateLock) {
+            if ((blockedSet != null) && blockedSet.contains(toBlock)) {
+                // already blocked, nothing to do
+                return this;
+            }
+
+            ((DatagramChannelImpl)ch).block(this, toBlock);
+
+            // created blocked set if required and add source address
+            if (blockedSet == null)
+                blockedSet = new HashSet<InetAddress>();
+            blockedSet.add(toBlock);
+        }
+        return this;
+    }
+
+    @Override
+    public MembershipKey unblock(InetAddress toUnblock)
+        throws IOException
+    {
+        synchronized (stateLock) {
+            if ((blockedSet == null) || !blockedSet.contains(toUnblock))
+                throw new IllegalStateException("not blocked");
+
+            ((DatagramChannelImpl)ch).unblock(this, toUnblock);
+
+            blockedSet.remove(toUnblock);
+        }
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(64);
+        sb.append('<');
+        sb.append(group.getHostAddress());
+        sb.append(',');
+        sb.append(interf.getName());
+        if (source != null) {
+            sb.append(',');
+            sb.append(source.getHostAddress());
+        }
+        sb.append('>');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/MembershipRegistry.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007-2008 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.nio.ch;
+
+import java.nio.channels.*;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.*;
+
+/**
+ * Simple registry of membership keys for a MulticastChannel.
+ *
+ * Instances of this object are not safe by multiple concurrent threads.
+ */
+
+class MembershipRegistry {
+
+    // map multicast group to keys
+    private Map<InetAddress,List<MembershipKeyImpl>> groups = null;
+
+    MembershipRegistry() {
+    }
+
+    /**
+     * Checks registry for membership of the group on the given
+     * network interface.
+     */
+    MembershipKey checkMembership(InetAddress group, NetworkInterface interf,
+                                  InetAddress source)
+    {
+        if (groups != null) {
+            List<MembershipKeyImpl> keys = groups.get(group);
+            if (keys != null) {
+                for (MembershipKeyImpl key: keys) {
+                    if (key.getNetworkInterface().equals(interf)) {
+                        // already a member to receive all packets so return
+                        // existing key or detect conflict
+                        if (source == null) {
+                            if (key.getSourceAddress() == null)
+                                return key;
+                            throw new IllegalStateException("Already a member to receive all packets");
+                        }
+
+                        // already have source-specific membership so return key
+                        // or detect conflict
+                        if (key.getSourceAddress() == null)
+                            throw new IllegalStateException("Already have source-specific membership");
+                        if (source.equals(key.getSourceAddress()))
+                            return key;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Add membership to the registry, returning a new membership key.
+     */
+    void add(MembershipKeyImpl key) {
+        InetAddress group = key.getGroup();
+        List<MembershipKeyImpl> keys;
+        if (groups == null) {
+            groups = new HashMap<InetAddress,List<MembershipKeyImpl>>();
+            keys = null;
+        } else {
+            keys = groups.get(group);
+        }
+        if (keys == null) {
+            keys = new LinkedList<MembershipKeyImpl>();
+            groups.put(group, keys);
+        }
+        keys.add(key);
+    }
+
+    /**
+     * Remove a key from the registry
+     */
+    void remove(MembershipKeyImpl key) {
+        InetAddress group = key.getGroup();
+        List<MembershipKeyImpl> keys = groups.get(group);
+        if (keys != null) {
+            Iterator<MembershipKeyImpl> i = keys.iterator();
+            while (i.hasNext()) {
+                if (i.next() == key) {
+                    i.remove();
+                    break;
+                }
+            }
+            if (keys.isEmpty()) {
+                groups.remove(group);
+            }
+        }
+    }
+
+    /**
+     * Invalidate all keys in the registry
+     */
+    void invalidateAll() {
+        for (InetAddress group: groups.keySet()) {
+            for (MembershipKeyImpl key: groups.get(group)) {
+                key.invalidate();
+            }
+        }
+    }
+}
--- a/src/share/classes/sun/nio/ch/Net.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/Net.java	Sun Aug 31 18:39:01 2008 +0100
@@ -26,21 +26,43 @@
 package sun.nio.ch;
 
 import java.io.*;
-import java.lang.reflect.*;
 import java.net.*;
 import java.nio.channels.*;
+import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 
 class Net {                                             // package-private
 
     private Net() { }
 
+    // unspecified protocol family
+    static final ProtocolFamily UNSPEC = new ProtocolFamily() {
+        public String name() {
+            return "UNSPEC";
+        }
+    };
 
     // -- Miscellaneous utilities --
 
+    private static volatile boolean checkedIPv6 = false;
+    private static volatile boolean isIPv6Available;
+
+    /**
+     * Tells whether dual-IPv4/IPv6 sockets should be used.
+     */
+    static boolean isIPv6Available() {
+        if (!checkedIPv6) {
+            isIPv6Available = isIPv6Available0();
+            checkedIPv6 = true;
+        }
+        return isIPv6Available;
+    }
+
     static InetSocketAddress checkAddress(SocketAddress sa) {
         if (sa == null)
-            throw new IllegalArgumentException();
+            throw new NullPointerException();
         if (!(sa instanceof InetSocketAddress))
             throw new UnsupportedAddressTypeException(); // ## needs arg
         InetSocketAddress isa = (InetSocketAddress)sa;
@@ -63,6 +85,8 @@
         Exception nx = x;
         if (x instanceof ClosedChannelException)
             nx = new SocketException("Socket is closed");
+        else if (x instanceof NotYetConnectedException)
+            nx = new SocketException("Socket is not connected");
         else if (x instanceof AlreadyBoundException)
             nx = new SocketException("Already bound");
         else if (x instanceof NotYetBoundException)
@@ -105,73 +129,359 @@
         translateException(x, false);
     }
 
+    /**
+     * Returns any IPv4 address of the given network interface, or
+     * null if the interface does not have any IPv4 addresses.
+     */
+    static Inet4Address anyInet4Address(final NetworkInterface interf) {
+        return AccessController.doPrivileged(new PrivilegedAction<Inet4Address>() {
+            public Inet4Address run() {
+                Enumeration<InetAddress> addrs = interf.getInetAddresses();
+                while (addrs.hasMoreElements()) {
+                    InetAddress addr = addrs.nextElement();
+                    if (addr instanceof Inet4Address) {
+                        return (Inet4Address)addr;
+                    }
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Returns an IPv4 address as an int.
+     */
+    static int inet4AsInt(InetAddress ia) {
+        if (ia instanceof Inet4Address) {
+            byte[] addr = ia.getAddress();
+            int address  = addr[3] & 0xFF;
+            address |= ((addr[2] << 8) & 0xFF00);
+            address |= ((addr[1] << 16) & 0xFF0000);
+            address |= ((addr[0] << 24) & 0xFF000000);
+            return address;
+        }
+        throw new AssertionError("Should not reach here");
+    }
+
+    /**
+     * Returns an InetAddress from the given IPv4 address
+     * represented as an int.
+     */
+    static InetAddress inet4FromInt(int address) {
+        byte[] addr = new byte[4];
+        addr[0] = (byte) ((address >>> 24) & 0xFF);
+        addr[1] = (byte) ((address >>> 16) & 0xFF);
+        addr[2] = (byte) ((address >>> 8) & 0xFF);
+        addr[3] = (byte) (address & 0xFF);
+        try {
+            return InetAddress.getByAddress(addr);
+        } catch (UnknownHostException uhe) {
+            throw new AssertionError("Should not reach here");
+        }
+    }
+
+    /**
+     * Returns an IPv6 address as a byte array
+     */
+    static byte[] inet6AsByteArray(InetAddress ia) {
+        if (ia instanceof Inet6Address) {
+            return ia.getAddress();
+        }
+
+        // need to construct IPv4-mapped address
+        if (ia instanceof Inet4Address) {
+            byte[] ip4address = ia.getAddress();
+            byte[] address = new byte[16];
+            address[10] = (byte)0xff;
+            address[11] = (byte)0xff;
+            address[12] = ip4address[0];
+            address[13] = ip4address[1];
+            address[14] = ip4address[2];
+            address[15] = ip4address[3];
+            return address;
+        }
+
+        throw new AssertionError("Should not reach here");
+    }
+
+    // -- Socket options
+
+    static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
+                                SocketOption name, Object value)
+        throws IOException
+    {
+        if (value == null)
+            throw new IllegalArgumentException("Invalid option value");
+
+        // only simple values supported by this method
+        Class<?> type = name.type();
+        if (type != Integer.class && type != Boolean.class)
+            throw new AssertionError("Should not reach here");
+
+        // special handling
+        if (name == StandardSocketOption.SO_RCVBUF ||
+            name == StandardSocketOption.SO_SNDBUF)
+        {
+            int i = ((Integer)value).intValue();
+            if (i < 0)
+                throw new IllegalArgumentException("Invalid send/receive buffer size");
+        }
+        if (name == StandardSocketOption.SO_LINGER) {
+            int i = ((Integer)value).intValue();
+            if (i < 0)
+                value = Integer.valueOf(-1);
+            if (i > 65535)
+                value = Integer.valueOf(65535);
+        }
+        if (name == StandardSocketOption.IP_TOS) {
+            int i = ((Integer)value).intValue();
+            if (i < 0 || i > 255)
+                throw new IllegalArgumentException("Invalid IP_TOS value");
+        }
+        if (name == StandardSocketOption.IP_MULTICAST_TTL) {
+            int i = ((Integer)value).intValue();
+            if (i < 0 || i > 255)
+                throw new IllegalArgumentException("Invalid TTL/hop value");
+        }
+
+        // map option name to platform level/name
+        OptionKey key = SocketOptionRegistry.findOption(name, family);
+        if (key == null)
+            throw new AssertionError("Option not found");
+
+        int arg;
+        if (type == Integer.class) {
+            arg = ((Integer)value).intValue();
+        } else {
+            boolean b = ((Boolean)value).booleanValue();
+            arg = (b) ? 1 : 0;
+        }
+
+        boolean mayNeedConversion = (family == UNSPEC);
+        setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg);
+    }
+
+    static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
+                                  SocketOption name)
+        throws IOException
+    {
+        Class<?> type = name.type();
+
+        // only simple values supported by this method
+        if (type != Integer.class && type != Boolean.class)
+            throw new AssertionError("Should not reach here");
+
+        // map option name to platform level/name
+        OptionKey key = SocketOptionRegistry.findOption(name, family);
+        if (key == null)
+            throw new AssertionError("Option not found");
+
+        boolean mayNeedConversion = (family == UNSPEC);
+        int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name());
+
+        if (type == Integer.class) {
+            return Integer.valueOf(value);
+        } else {
+            return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
+        }
+    }
 
     // -- Socket operations --
 
+    static native boolean isIPv6Available0();
+
     static FileDescriptor socket(boolean stream) {
-        return IOUtil.newFD(socket0(stream, false));
+        return socket(UNSPEC, stream);
+    }
+
+    static FileDescriptor socket(ProtocolFamily family, boolean stream) {
+        boolean preferIPv6 = isIPv6Available() &&
+            (family != StandardProtocolFamily.INET);
+        return IOUtil.newFD(socket0(preferIPv6, stream, false));
     }
 
     static FileDescriptor serverSocket(boolean stream) {
-        return IOUtil.newFD(socket0(stream, true));
+        return IOUtil.newFD(socket0(isIPv6Available(), stream, true));
     }
 
     // Due to oddities SO_REUSEADDR on windows reuse is ignored
-    private static native int socket0(boolean stream, boolean reuse);
+    private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse);
 
-    static native void bind(FileDescriptor fd, InetAddress addr, int port)
+    static void bind(FileDescriptor fd, InetAddress addr, int port)
+        throws IOException
+    {
+        bind(UNSPEC, fd, addr, port);
+    }
+
+    static void bind(ProtocolFamily family, FileDescriptor fd,
+                     InetAddress addr, int port) throws IOException
+    {
+        boolean preferIPv6 = isIPv6Available() &&
+            (family != StandardProtocolFamily.INET);
+        bind0(preferIPv6, fd, addr, port);
+    }
+
+    private static native void bind0(boolean preferIPv6, FileDescriptor fd,
+                                     InetAddress addr, int port)
         throws IOException;
 
-    static native int connect(FileDescriptor fd,
-                              InetAddress remote,
-                              int remotePort,
-                              int trafficClass)
+    static native void listen(FileDescriptor fd, int backlog) throws IOException;
+
+    static int connect(FileDescriptor fd, InetAddress remote, int remotePort)
+        throws IOException
+    {
+        return connect(UNSPEC, fd, remote, remotePort);
+    }
+
+    static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort)
+        throws IOException
+    {
+        boolean preferIPv6 = isIPv6Available() &&
+            (family != StandardProtocolFamily.INET);
+        return connect0(preferIPv6, fd, remote, remotePort);
+    }
+
+    private static native int connect0(boolean preferIPv6,
+                                       FileDescriptor fd,
+                                       InetAddress remote,
+                                       int remotePort)
         throws IOException;
 
 
+    public final static int SHUT_RD = 0;
+    public final static int SHUT_WR = 1;
+    public final static int SHUT_RDWR = 2;
+
+    static native void shutdown(FileDescriptor fd, int how) throws IOException;
+
     private static native int localPort(FileDescriptor fd)
         throws IOException;
 
     private static native InetAddress localInetAddress(FileDescriptor fd)
         throws IOException;
 
-    static InetSocketAddress localAddress(FileDescriptor fd) {
-        try {
-            return new InetSocketAddress(localInetAddress(fd),
-                                         localPort(fd));
-        } catch (IOException x) {
-            throw new Error(x);         // Can't happen
-        }
+    static InetSocketAddress localAddress(FileDescriptor fd)
+        throws IOException
+    {
+        return new InetSocketAddress(localInetAddress(fd), localPort(fd));
     }
 
-    static int localPortNumber(FileDescriptor fd) {
-        try {
-            return localPort(fd);
-        } catch (IOException x) {
-            throw new Error(x);         // Can't happen
-        }
+    private static native int remotePort(FileDescriptor fd)
+        throws IOException;
+
+    private static native InetAddress remoteInetAddress(FileDescriptor fd)
+        throws IOException;
+
+    static InetSocketAddress remoteAddress(FileDescriptor fd)
+        throws IOException
+    {
+        return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd));
     }
 
-    private static native int getIntOption0(FileDescriptor fd, int opt)
+    private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion,
+                                            int level, int opt)
         throws IOException;
 
-    static int getIntOption(FileDescriptor fd, int opt)
+    private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion,
+                                             int level, int opt, int arg)
+        throws IOException;
+
+    // -- Multicast support --
+
+
+    /**
+     * Join IPv4 multicast group
+     */
+    static int join4(FileDescriptor fd, int group, int interf, int source)
         throws IOException
     {
-        return getIntOption0(fd, opt);
+        return joinOrDrop4(true, fd, group, interf, source);
     }
 
+    /**
+     * Drop membership of IPv4 multicast group
+     */
+    static void drop4(FileDescriptor fd, int group, int interf, int source)
+        throws IOException
+    {
+        joinOrDrop4(false, fd, group, interf, source);
+    }
 
-    private static native void setIntOption0(FileDescriptor fd,
-                                             int opt, int arg)
+    private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source)
         throws IOException;
 
-    static void setIntOption(FileDescriptor fd, int opt, int arg)
+    /**
+     * Block IPv4 source
+     */
+    static int block4(FileDescriptor fd, int group, int interf, int source)
         throws IOException
     {
-        setIntOption0(fd, opt, arg);
+        return blockOrUnblock4(true, fd, group, interf, source);
     }
 
+    /**
+     * Unblock IPv6 source
+     */
+    static void unblock4(FileDescriptor fd, int group, int interf, int source)
+        throws IOException
+    {
+        blockOrUnblock4(false, fd, group, interf, source);
+    }
+
+    private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group,
+                                              int interf, int source)
+        throws IOException;
+
+    /**
+     * Join IPv6 multicast group
+     */
+    static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
+        throws IOException
+    {
+        return joinOrDrop6(true, fd, group, index, source);
+    }
+
+    /**
+     * Drop membership of IPv6 multicast group
+     */
+    static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source)
+        throws IOException
+    {
+        joinOrDrop6(false, fd, group, index, source);
+    }
+
+    private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
+        throws IOException;
+
+    /**
+     * Block IPv6 source
+     */
+    static int block6(FileDescriptor fd, byte[] group, int index, byte[] source)
+        throws IOException
+    {
+        return blockOrUnblock6(true, fd, group, index, source);
+    }
+
+    /**
+     * Unblock IPv6 source
+     */
+    static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source)
+        throws IOException
+    {
+        blockOrUnblock6(false, fd, group, index, source);
+    }
+
+    static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source)
+        throws IOException;
+
+    static native void setInterface4(FileDescriptor fd, int interf) throws IOException;
+
+    static native int getInterface4(FileDescriptor fd) throws IOException;
+
+    static native void setInterface6(FileDescriptor fd, int index) throws IOException;
+
+    static native int getInterface6(FileDescriptor fd) throws IOException;
+
     private static native void initIDs();
 
     static {
--- a/src/share/classes/sun/nio/ch/OptionAdaptor.java	Sun Aug 31 18:32:59 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
- * Copyright 2001 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.nio.ch;
-
-import java.io.*;
-import java.net.*;
-import java.nio.*;
-import java.nio.channels.*;
-
-
-// Adaptor class for java.net-style options
-//
-// The option get/set methods in the socket, server-socket, and datagram-socket
-// adaptors delegate to an instance of this class.
-//
-
-class OptionAdaptor {                                   // package-private
-
-    private final SocketOpts.IP opts;
-
-    OptionAdaptor(SocketChannelImpl sc) {
-        opts = (SocketOpts.IP)sc.options();
-    }
-
-    OptionAdaptor(ServerSocketChannelImpl ssc) {
-        opts = (SocketOpts.IP)ssc.options();
-    }
-
-    OptionAdaptor(DatagramChannelImpl dc) {
-        opts = (SocketOpts.IP)dc.options();
-    }
-
-    private SocketOpts.IP opts() {
-        return opts;
-    }
-
-    private SocketOpts.IP.TCP tcpOpts() {
-        return (SocketOpts.IP.TCP)opts;
-    }
-
-    public void setTcpNoDelay(boolean on) throws SocketException {
-        try {
-            tcpOpts().noDelay(on);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public boolean getTcpNoDelay() throws SocketException {
-        try {
-            return tcpOpts().noDelay();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return false;               // Never happens
-        }
-    }
-
-    public void setSoLinger(boolean on, int linger) throws SocketException {
-        try {
-            if (linger > 65535)
-                linger = 65535;
-            opts().linger(on ? linger : -1);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public int getSoLinger() throws SocketException {
-        try {
-            return opts().linger();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return 0;                   // Never happens
-        }
-    }
-
-    public void setOOBInline(boolean on) throws SocketException {
-        try {
-            opts().outOfBandInline(on);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public boolean getOOBInline() throws SocketException {
-        try {
-            return opts().outOfBandInline();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return false;               // Never happens
-        }
-    }
-
-    public void setSendBufferSize(int size)
-        throws SocketException
-    {
-        try {
-            opts().sendBufferSize(size);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public int getSendBufferSize() throws SocketException {
-        try {
-            return opts().sendBufferSize();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return 0;                   // Never happens
-        }
-    }
-
-    public void setReceiveBufferSize(int size)
-        throws SocketException
-    {
-        try {
-            opts().receiveBufferSize(size);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public int getReceiveBufferSize() throws SocketException {
-        try {
-            return opts().receiveBufferSize();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return 0;                   // Never happens
-        }
-    }
-
-    public void setKeepAlive(boolean on) throws SocketException {
-        try {
-            opts().keepAlive(on);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public boolean getKeepAlive() throws SocketException {
-        try {
-            return opts().keepAlive();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return false;               // Never happens
-        }
-    }
-
-    public void setTrafficClass(int tc) throws SocketException {
-        if (tc < 0 || tc > 255)
-            throw new IllegalArgumentException("tc is not in range 0 -- 255");
-        try {
-            opts().typeOfService(tc);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public int getTrafficClass() throws SocketException {
-        try {
-            return opts().typeOfService();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return 0;                   // Never happens
-        }
-    }
-
-    public void setReuseAddress(boolean on)
-        throws SocketException
-    {
-        try {
-            opts().reuseAddress(on);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public boolean getReuseAddress() throws SocketException {
-        try {
-            return opts().reuseAddress();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return false;               // Never happens
-        }
-    }
-
-    public void setBroadcast(boolean on)
-        throws SocketException
-    {
-        try {
-            opts().broadcast(on);
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-        }
-    }
-
-    public boolean getBroadcast() throws SocketException {
-        try {
-            return opts().broadcast();
-        } catch (Exception x) {
-            Net.translateToSocketException(x);
-            return false;               // Never happens
-        }
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/OptionKey.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007-2008 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.nio.ch;
+
+/**
+ * Represents the level/name of a socket option
+ */
+
+class OptionKey {
+    private int level;
+    private int name;
+
+    OptionKey(int level, int name) {
+        this.level = level;
+        this.name = name;
+    }
+
+    int level() {
+        return level;
+    }
+
+    int name() {
+        return name;
+    }
+}
--- a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java	Sun Aug 31 18:39:01 2008 +0100
@@ -29,6 +29,7 @@
 import java.io.IOException;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.net.ProtocolFamily;
 import java.nio.channels.*;
 import java.nio.channels.spi.*;
 
@@ -41,6 +42,10 @@
         return new DatagramChannelImpl(this);
     }
 
+    public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException {
+        return new DatagramChannelImpl(this, family);
+    }
+
     public Pipe openPipe() throws IOException {
         return new PipeImpl(this);
     }
@@ -54,5 +59,4 @@
     public SocketChannel openSocketChannel() throws IOException {
         return new SocketChannelImpl(this);
     }
-
 }
--- a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java	Sun Aug 31 18:39:01 2008 +0100
@@ -44,9 +44,6 @@
     // The channel being adapted
     private final ServerSocketChannelImpl ssc;
 
-    // Option adaptor object, created on demand
-    private volatile OptionAdaptor opts = null;
-
     // Timeout "option" value for accepts
     private volatile int timeout = 0;
 
@@ -174,18 +171,21 @@
         return timeout;
     }
 
-    private OptionAdaptor opts() {
-        if (opts == null)
-            opts = new OptionAdaptor(ssc);
-        return opts;
-    }
-
     public void setReuseAddress(boolean on) throws SocketException {
-        opts().setReuseAddress(on);
+        try {
+            ssc.setOption(StandardSocketOption.SO_REUSEADDR, on);
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+        }
     }
 
     public boolean getReuseAddress() throws SocketException {
-        return opts().getReuseAddress();
+        try {
+            return ssc.getOption(StandardSocketOption.SO_REUSEADDR).booleanValue();
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+            return false;       // Never happens
+        }
     }
 
     public String toString() {
@@ -197,11 +197,23 @@
     }
 
     public void setReceiveBufferSize(int size) throws SocketException {
-        opts().setReceiveBufferSize(size);
+        // size 0 valid for ServerSocketChannel, invalid for ServerSocket
+        if (size <= 0)
+            throw new IllegalArgumentException("size cannot be 0 or negative");
+        try {
+            ssc.setOption(StandardSocketOption.SO_RCVBUF, size);
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+        }
     }
 
     public int getReceiveBufferSize() throws SocketException {
-        return opts().getReceiveBufferSize();
+        try {
+            return ssc.getOption(StandardSocketOption.SO_RCVBUF).intValue();
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+            return -1;          // Never happens
+        }
     }
 
 }
--- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Sun Aug 31 18:39:01 2008 +0100
@@ -33,8 +33,7 @@
 import java.nio.channels.spi.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.HashSet;
-import java.util.Iterator;
+import java.util.*;
 
 
 /**
@@ -75,10 +74,7 @@
     private int state = ST_UNINITIALIZED;
 
     // Binding
-    private SocketAddress localAddress = null; // null => unbound
-
-    // Options, created on demand
-    private SocketOpts.IP.TCP options = null;
+    private SocketAddress localAddress; // null => unbound
 
     // Our socket adaptor, if any
     ServerSocket socket;
@@ -103,7 +99,6 @@
         localAddress = Net.localAddress(fd);
     }
 
-
     public ServerSocket socket() {
         synchronized (stateLock) {
             if (socket == null)
@@ -112,6 +107,69 @@
         }
     }
 
+    @Override
+    public SocketAddress getLocalAddress() throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                return null;
+            return localAddress;
+        }
+    }
+
+    @Override
+    public ServerSocketChannel 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();
+
+            // 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();
+
+            // 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<?>>(2);
+            set.add(StandardSocketOption.SO_RCVBUF);
+            set.add(StandardSocketOption.SO_REUSEADDR);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> options() {
+        return LazyInitialization.defaultOptions;
+    }
+
     public boolean isBound() {
         synchronized (stateLock) {
             return localAddress != null;
@@ -124,22 +182,25 @@
         }
     }
 
-    public void bind(SocketAddress local, int backlog) throws IOException {
+    @Override
+    public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
         synchronized (lock) {
             if (!isOpen())
                 throw new ClosedChannelException();
             if (isBound())
                 throw new AlreadyBoundException();
-            InetSocketAddress isa = Net.checkAddress(local);
+            InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
+                Net.checkAddress(local);
             SecurityManager sm = System.getSecurityManager();
             if (sm != null)
                 sm.checkListen(isa.getPort());
             Net.bind(fd, isa.getAddress(), isa.getPort());
-            listen(fd, backlog < 1 ? 50 : backlog);
+            Net.listen(fd, backlog < 1 ? 50 : backlog);
             synchronized (stateLock) {
                 localAddress = Net.localAddress(fd);
             }
         }
+        return this;
     }
 
     public SocketChannel accept() throws IOException {
@@ -196,24 +257,6 @@
         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;
-        }
-    }
-
     protected void implCloseSelectableChannel() throws IOException {
         synchronized (stateLock) {
             nd.preClose(fd);
@@ -320,9 +363,6 @@
 
     // -- Native methods --
 
-    private static native void listen(FileDescriptor fd, int backlog)
-        throws IOException;
-
     // Accepts a new connection, setting the given file descriptor to refer to
     // the new socket and setting isaa[0] to the socket's remote address.
     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
--- a/src/share/classes/sun/nio/ch/SocketAdaptor.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/SocketAdaptor.java	Sun Aug 31 18:39:01 2008 +0100
@@ -54,16 +54,9 @@
     // The channel being adapted
     private final SocketChannelImpl sc;
 
-    // Option adaptor object, created on demand
-    private volatile OptionAdaptor opts = null;
-
     // Timeout "option" value for reads
     private volatile int timeout = 0;
 
-    // Traffic-class/Type-of-service
-    private volatile int trafficClass = 0;
-
-
     // ## super will create a useless impl
     private SocketAdaptor(SocketChannelImpl sc) {
         this.sc = sc;
@@ -145,8 +138,6 @@
 
     public void bind(SocketAddress local) throws IOException {
         try {
-            if (local == null)
-                local = new InetSocketAddress(0);
             sc.bind(local);
         } catch (Exception x) {
             Net.translateException(x);
@@ -154,27 +145,39 @@
     }
 
     public InetAddress getInetAddress() {
-        if (!sc.isConnected())
+        SocketAddress remote = sc.remoteAddress();
+        if (remote == null) {
             return null;
-        return Net.asInetSocketAddress(sc.remoteAddress()).getAddress();
+        } else {
+            return ((InetSocketAddress)remote).getAddress();
+        }
     }
 
     public InetAddress getLocalAddress() {
-        if (!sc.isBound())
-            return new InetSocketAddress(0).getAddress();
-        return Net.asInetSocketAddress(sc.localAddress()).getAddress();
+        if (sc.isOpen()) {
+            SocketAddress local = sc.localAddress();
+            if (local != null)
+                return ((InetSocketAddress)local).getAddress();
+        }
+        return new InetSocketAddress(0).getAddress();
     }
 
     public int getPort() {
-        if (!sc.isConnected())
+        SocketAddress remote = sc.remoteAddress();
+        if (remote == null) {
             return 0;
-        return Net.asInetSocketAddress(sc.remoteAddress()).getPort();
+        } else {
+            return ((InetSocketAddress)remote).getPort();
+        }
     }
 
     public int getLocalPort() {
-        if (!sc.isBound())
+        SocketAddress local = sc.localAddress();
+        if (local == null) {
             return -1;
-        return Net.asInetSocketAddress(sc.localAddress()).getPort();
+        } else {
+            return ((InetSocketAddress)local).getPort();
+        }
     }
 
     private class SocketInputStream
@@ -276,26 +279,60 @@
         return os;
     }
 
-    private OptionAdaptor opts() {
-        if (opts == null)
-            opts = new OptionAdaptor(sc);
-        return opts;
+    private void setBooleanOption(SocketOption<Boolean> name, boolean value)
+        throws SocketException
+    {
+        try {
+            sc.setOption(name, value);
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+        }
+    }
+
+    private void setIntOption(SocketOption<Integer> name, int value)
+        throws SocketException
+    {
+        try {
+            sc.setOption(name, value);
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+        }
+    }
+
+    private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
+        try {
+            return sc.getOption(name).booleanValue();
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+            return false;       // keep compiler happy
+        }
+    }
+
+    private int getIntOption(SocketOption<Integer> name) throws SocketException {
+        try {
+            return sc.getOption(name).intValue();
+        } catch (IOException x) {
+            Net.translateToSocketException(x);
+            return -1;          // keep compiler happy
+        }
     }
 
     public void setTcpNoDelay(boolean on) throws SocketException {
-        opts().setTcpNoDelay(on);
+        setBooleanOption(StandardSocketOption.TCP_NODELAY, on);
     }
 
     public boolean getTcpNoDelay() throws SocketException {
-        return opts().getTcpNoDelay();
+        return getBooleanOption(StandardSocketOption.TCP_NODELAY);
     }
 
     public void setSoLinger(boolean on, int linger) throws SocketException {
-        opts().setSoLinger(on, linger);
+        if (!on)
+            linger = -1;
+        setIntOption(StandardSocketOption.SO_LINGER, linger);
     }
 
     public int getSoLinger() throws SocketException {
-        return opts().getSoLinger();
+        return getIntOption(StandardSocketOption.SO_LINGER);
     }
 
     public void sendUrgentData(int data) throws IOException {
@@ -303,11 +340,11 @@
     }
 
     public void setOOBInline(boolean on) throws SocketException {
-        opts().setOOBInline(on);
+        setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
     }
 
     public boolean getOOBInline() throws SocketException {
-        return opts().getOOBInline();
+        return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
     }
 
     public void setSoTimeout(int timeout) throws SocketException {
@@ -321,48 +358,49 @@
     }
 
     public void setSendBufferSize(int size) throws SocketException {
-        opts().setSendBufferSize(size);
+        // size 0 valid for SocketChannel, invalid for Socket
+        if (size <= 0)
+            throw new IllegalArgumentException("Invalid send size");
+        setIntOption(StandardSocketOption.SO_SNDBUF, size);
     }
 
     public int getSendBufferSize() throws SocketException {
-        return opts().getSendBufferSize();
+        return getIntOption(StandardSocketOption.SO_SNDBUF);
     }
 
     public void setReceiveBufferSize(int size) throws SocketException {
-        opts().setReceiveBufferSize(size);
+        // size 0 valid for SocketChannel, invalid for Socket
+        if (size <= 0)
+            throw new IllegalArgumentException("Invalid receive size");
+        setIntOption(StandardSocketOption.SO_RCVBUF, size);
     }
 
     public int getReceiveBufferSize() throws SocketException {
-        return opts().getReceiveBufferSize();
+        return getIntOption(StandardSocketOption.SO_RCVBUF);
     }
 
     public void setKeepAlive(boolean on) throws SocketException {
-        opts().setKeepAlive(on);
+        setBooleanOption(StandardSocketOption.SO_KEEPALIVE, on);
     }
 
     public boolean getKeepAlive() throws SocketException {
-        return opts().getKeepAlive();
+        return getBooleanOption(StandardSocketOption.SO_KEEPALIVE);
     }
 
     public void setTrafficClass(int tc) throws SocketException {
-        opts().setTrafficClass(tc);
-        trafficClass = tc;
+        setIntOption(StandardSocketOption.IP_TOS, tc);
     }
 
     public int getTrafficClass() throws SocketException {
-        int tc = opts().getTrafficClass();
-        if (tc < 0) {
-            tc = trafficClass;
-        }
-        return tc;
+        return getIntOption(StandardSocketOption.IP_TOS);
     }
 
     public void setReuseAddress(boolean on) throws SocketException {
-        opts().setReuseAddress(on);
+        setBooleanOption(StandardSocketOption.SO_REUSEADDR, on);
     }
 
     public boolean getReuseAddress() throws SocketException {
-        return opts().getReuseAddress();
+        return getBooleanOption(StandardSocketOption.SO_REUSEADDR);
     }
 
     public void close() throws IOException {
@@ -402,7 +440,7 @@
     }
 
     public boolean isBound() {
-        return sc.isBound();
+        return sc.localAddress() != null;
     }
 
     public boolean isClosed() {
--- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/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();
--- a/src/share/classes/sun/nio/ch/SocketOpts.java	Sun Aug 31 18:32:59 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * Copyright 2001 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.nio.ch;
-
-import java.io.IOException;
-import java.nio.*;
-import java.net.NetworkInterface;
-
-
-// Typical use:
-//
-//     sc.options()
-//         .noDelay(true)
-//         .typeOfService(SocketOpts.IP.TOS_RELIABILITY)
-//         .sendBufferSize(1024)
-//         .receiveBufferSize(1024)
-//         .keepAlive(true);
-//
-
-
-public interface SocketOpts {   // SocketOptions already used in java.net
-
-    // Options that apply to all kinds of sockets
-
-    // SO_BROADCAST
-    public abstract boolean broadcast() throws IOException;
-    public abstract SocketOpts broadcast(boolean b) throws IOException;
-
-    // SO_KEEPALIVE
-    public abstract boolean keepAlive() throws IOException;
-    public abstract SocketOpts keepAlive(boolean b) throws IOException;
-
-    // SO_LINGER
-    public abstract int linger() throws IOException;
-    public abstract SocketOpts linger(int n) throws IOException;
-
-    // SO_OOBINLINE
-    public abstract boolean outOfBandInline() throws IOException;
-    public abstract SocketOpts outOfBandInline(boolean b) throws IOException;
-
-    // SO_RCVBUF
-    public abstract int receiveBufferSize() throws IOException;
-    public abstract SocketOpts receiveBufferSize(int n) throws IOException;
-
-    // SO_SNDBUF
-    public abstract int sendBufferSize() throws IOException;
-    public abstract SocketOpts sendBufferSize(int n) throws IOException;
-
-    // SO_REUSEADDR
-    public abstract boolean reuseAddress() throws IOException;
-    public abstract SocketOpts reuseAddress(boolean b) throws IOException;
-
-
-    // IP-specific options
-
-    public static interface IP
-        extends SocketOpts
-    {
-
-        // IP_MULTICAST_IF2
-        public abstract NetworkInterface multicastInterface()
-            throws IOException;
-        public abstract IP multicastInterface(NetworkInterface ni)
-            throws IOException;
-
-        // IP_MULTICAST_LOOP
-        public abstract boolean multicastLoop() throws IOException;
-        public abstract IP multicastLoop(boolean b) throws IOException;
-
-        // IP_TOS
-        public static final int TOS_LOWDELAY = 0x10;
-        public static final int TOS_THROUGHPUT = 0x08;
-        public static final int TOS_RELIABILITY = 0x04;
-        public static final int TOS_MINCOST = 0x02;
-        public abstract int typeOfService() throws IOException;
-        public abstract IP typeOfService(int tos) throws IOException;
-
-
-        // TCP-specific options
-
-        public static interface TCP
-            extends IP
-        {
-            // TCP_NODELAY
-            public abstract boolean noDelay() throws IOException;
-            public abstract TCP noDelay(boolean b) throws IOException;
-
-        }
-
-    }
-
-}
--- a/src/share/classes/sun/nio/ch/SocketOptsImpl.java	Sun Aug 31 18:32:59 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,318 +0,0 @@
-/*
- * Copyright 2001 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.nio.ch;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.NetworkInterface;
-import java.net.SocketOptions;
-import java.nio.channels.*;
-
-
-class SocketOptsImpl
-    implements SocketOpts
-{
-
-    static abstract class Dispatcher {
-        abstract int getInt(int opt) throws IOException;
-        abstract void setInt(int opt, int arg) throws IOException;
-        // Others that pass addresses, etc., will come later
-    }
-
-    private final Dispatcher d;
-
-    SocketOptsImpl(Dispatcher d) {
-        this.d = d;
-    }
-
-    protected boolean getBoolean(int opt) throws IOException {
-        return d.getInt(opt) > 0;
-    }
-
-    protected void setBoolean(int opt, boolean b) throws IOException {
-        d.setInt(opt, b ? 1 : 0);
-    }
-
-    protected int getInt(int opt) throws IOException {
-        return d.getInt(opt);
-    }
-
-    protected void setInt(int opt, int n) throws IOException {
-        d.setInt(opt, n);
-    }
-
-    protected NetworkInterface getNetworkInterface(int opt)
-        throws IOException
-    {
-        throw new UnsupportedOperationException("NYI");
-    }
-
-    protected void setNetworkInterface(int opt, NetworkInterface ni)
-        throws IOException
-    {
-        throw new UnsupportedOperationException("NYI");
-    }
-
-    protected void addToString(StringBuffer sb, String s) {
-        char c = sb.charAt(sb.length() - 1);
-        if ((c != '[') && (c != '='))
-            sb.append(' ');
-        sb.append(s);
-    }
-
-    protected void addToString(StringBuffer sb, int n) {
-        addToString(sb, Integer.toString(n));
-    }
-
-
-    // SO_BROADCAST
-
-    public boolean broadcast() throws IOException {
-        return getBoolean(SocketOptions.SO_BROADCAST);
-    }
-
-    public SocketOpts broadcast(boolean b) throws IOException {
-        setBoolean(SocketOptions.SO_BROADCAST, b);
-        return this;
-    }
-
-
-    // SO_KEEPALIVE
-
-    public boolean keepAlive() throws IOException {
-        return getBoolean(SocketOptions.SO_KEEPALIVE);
-    }
-
-    public SocketOpts keepAlive(boolean b) throws IOException {
-        setBoolean(SocketOptions.SO_KEEPALIVE, b);
-        return this;
-    }
-
-
-    // SO_LINGER
-
-    public int linger() throws IOException {
-        return getInt(SocketOptions.SO_LINGER);
-    }
-
-    public SocketOpts linger(int n) throws IOException {
-        setInt(SocketOptions.SO_LINGER, n);
-        return this;
-    }
-
-
-    // SO_OOBINLINE
-
-    public boolean outOfBandInline() throws IOException {
-        return getBoolean(SocketOptions.SO_OOBINLINE);
-    }
-
-    public SocketOpts outOfBandInline(boolean b) throws IOException {
-        setBoolean(SocketOptions.SO_OOBINLINE, b);
-        return this;
-    }
-
-
-    // SO_RCVBUF
-
-    public int receiveBufferSize() throws IOException {
-        return getInt(SocketOptions.SO_RCVBUF);
-    }
-
-    public SocketOpts receiveBufferSize(int n) throws IOException {
-        if (n <= 0)
-            throw new IllegalArgumentException("Invalid receive size");
-        setInt(SocketOptions.SO_RCVBUF, n);
-        return this;
-    }
-
-
-    // SO_SNDBUF
-
-    public int sendBufferSize() throws IOException {
-        return getInt(SocketOptions.SO_SNDBUF);
-    }
-
-    public SocketOpts sendBufferSize(int n) throws IOException {
-        if (n <= 0)
-            throw new IllegalArgumentException("Invalid send size");
-        setInt(SocketOptions.SO_SNDBUF, n);
-        return this;
-    }
-
-
-    // SO_REUSEADDR
-
-    public boolean reuseAddress() throws IOException {
-        return getBoolean(SocketOptions.SO_REUSEADDR);
-    }
-
-    public SocketOpts reuseAddress(boolean b) throws IOException {
-        setBoolean(SocketOptions.SO_REUSEADDR, b);
-        return this;
-    }
-
-
-    // toString
-
-    protected void toString(StringBuffer sb) throws IOException {
-        int n;
-        if (broadcast())
-            addToString(sb, "broadcast");
-        if (keepAlive())
-            addToString(sb, "keepalive");
-        if ((n = linger()) > 0) {
-            addToString(sb, "linger=");
-            addToString(sb, n);
-        }
-        if (outOfBandInline())
-            addToString(sb, "oobinline");
-        if ((n = receiveBufferSize()) > 0) {
-            addToString(sb, "rcvbuf=");
-            addToString(sb, n);
-        }
-        if ((n = sendBufferSize()) > 0) {
-            addToString(sb, "sndbuf=");
-            addToString(sb, n);
-        }
-        if (reuseAddress())
-            addToString(sb, "reuseaddr");
-    }
-
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append(this.getClass().getInterfaces()[0].getName());
-        sb.append('[');
-        int i = sb.length();
-        try {
-            toString(sb);
-        } catch (IOException x) {
-            sb.setLength(i);
-            sb.append("closed");
-        }
-        sb.append(']');
-        return sb.toString();
-    }
-
-
-    // IP-specific socket options
-
-    static class IP
-        extends SocketOptsImpl
-        implements SocketOpts.IP
-    {
-
-        IP(Dispatcher d) {
-            super(d);
-        }
-
-
-        // IP_MULTICAST_IF2
-        // ## Do we need IP_MULTICAST_IF also?
-
-        public NetworkInterface multicastInterface() throws IOException {
-            return getNetworkInterface(SocketOptions.IP_MULTICAST_IF2);
-        }
-
-        public SocketOpts.IP multicastInterface(NetworkInterface ni)
-            throws IOException
-        {
-            setNetworkInterface(SocketOptions.IP_MULTICAST_IF2, ni);
-            return this;
-        }
-
-
-        // IP_MULTICAST_LOOP
-
-        public boolean multicastLoop() throws IOException {
-            return getBoolean(SocketOptions.IP_MULTICAST_LOOP);
-        }
-
-        public SocketOpts.IP multicastLoop(boolean b) throws IOException {
-            setBoolean(SocketOptions.IP_MULTICAST_LOOP, b);
-            return this;
-        }
-
-
-        // IP_TOS
-
-        public int typeOfService() throws IOException {
-            return getInt(SocketOptions.IP_TOS);
-        }
-
-        public SocketOpts.IP typeOfService(int tos) throws IOException {
-            setInt(SocketOptions.IP_TOS, tos);
-            return this;
-        }
-
-
-        // toString
-
-        protected void toString(StringBuffer sb) throws IOException {
-            super.toString(sb);
-            int n;
-            if ((n = typeOfService()) > 0) {
-                addToString(sb, "tos=");
-                addToString(sb, n);
-            }
-        }
-
-
-        // TCP-specific IP options
-
-        public static class TCP
-            extends SocketOptsImpl.IP
-            implements SocketOpts.IP.TCP
-        {
-
-            TCP(Dispatcher d) {
-                super(d);
-            }
-
-            // TCP_NODELAY
-
-            public boolean noDelay() throws IOException {
-                return getBoolean(SocketOptions.TCP_NODELAY);
-            }
-
-            public SocketOpts.IP.TCP noDelay(boolean b) throws IOException {
-                setBoolean(SocketOptions.TCP_NODELAY, b);
-                return this;
-            }
-
-
-            // toString
-
-            protected void toString(StringBuffer sb) throws IOException {
-                super.toString(sb);
-                if (noDelay())
-                    addToString(sb, "nodelay");
-            }
-
-        }
-    }
-
-}
--- a/src/share/classes/sun/nio/ch/exceptions	Sun Aug 31 18:32:59 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#
-# Copyright 2000-2007 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.
-#
-
-# Generated exception classes for sun.nio.ch
-
-SINCE=1.4
-PACKAGE=sun.nio.ch
-# This year should only change if the generated source is modified.
-COPYRIGHT_YEARS=2000-2007
-
-
-SUPER=IllegalStateException
-
-gen AlreadyBoundException "
- * Unchecked exception thrown when an attempt is made to bind a {@link
- * SocketChannel} that is already bound." \
- 9002280723481772026L
--- a/src/share/native/java/net/net_util.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/native/java/net/net_util.c	Sun Aug 31 18:39:01 2008 +0100
@@ -82,7 +82,7 @@
     }
 }
 
-jobject
+JNIEXPORT jobject JNICALL
 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
     jobject iaObj;
     init(env);
@@ -159,7 +159,7 @@
     return iaObj;
 }
 
-jint
+JNIEXPORT jint JNICALL
 NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
 {
     jint family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
--- a/src/share/native/java/net/net_util.h	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/native/java/net/net_util.h	Sun Aug 31 18:39:01 2008 +0100
@@ -116,7 +116,7 @@
 JNIEXPORT int JNICALL
 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him, int *len, jboolean v4MappedAddress);
 
-jobject
+JNIEXPORT jobject JNICALL
 NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port);
 
 void initLocalAddrTable ();
@@ -124,10 +124,10 @@
 void
 NET_SetTrafficClass(struct sockaddr *him, int trafficClass);
 
-jint
+JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him);
 
-jint
+JNIEXPORT jint JNICALL
 NET_SockaddrEqualsInetAddress(JNIEnv *env,struct sockaddr *him, jobject iaObj);
 
 int
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007 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 <stdio.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#endif
+
+/**
+ * Generates sun.nio.ch.SocketOptionRegistry, a class that maps Java-level
+ * socket options to the platform specific level and option.
+ */
+
+static void out(char* s) {
+    printf("%s\n", s);
+}
+
+static void emit(const char *name, char * family, int level, int optname) {
+    printf("            map.put(new RegistryKey(%s, %s),", name, family);
+    printf(" new OptionKey(%d, %d));\n", level, optname);
+}
+
+static void emit_unspec(const char *name, int level, int optname) {
+    emit(name, "Net.UNSPEC", level, optname);
+}
+
+static  void emit_inet(const char *name, int level, int optname) {
+    emit(name, "StandardProtocolFamily.INET", level, optname);
+}
+
+static void emit_inet6(const char *name, int level, int optname) {
+    emit(name, "StandardProtocolFamily.INET6", level, optname);
+}
+
+int main(int argc, const char* argv[]) {
+    out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT                                  ");
+    out("package sun.nio.ch;                                                            ");
+    out("import java.net.SocketOption;                                                  ");
+    out("import java.net.StandardSocketOption;                                          ");
+    out("import java.net.ProtocolFamily;                                                ");
+    out("import java.net.StandardProtocolFamily;                                        ");
+    out("import java.util.Map;                                                          ");
+    out("import java.util.HashMap;                                                      ");
+    out("class SocketOptionRegistry {                                                   ");
+    out("    private SocketOptionRegistry() { }                                         ");
+    out("    private static class RegistryKey {                                         ");
+    out("        private final SocketOption name;                                       ");
+    out("        private final ProtocolFamily family;                                   ");
+    out("        RegistryKey(SocketOption name, ProtocolFamily family) {                ");
+    out("            this.name = name;                                                  ");
+    out("            this.family = family;                                              ");
+    out("        }                                                                      ");
+    out("        public int hashCode() {                                                ");
+    out("            return name.hashCode() + family.hashCode();                        ");
+    out("        }                                                                      ");
+    out("        public boolean equals(Object ob) {                                     ");
+    out("            if (ob == null) return false;                                      ");
+    out("            if (!(ob instanceof RegistryKey)) return false;                    ");
+    out("            RegistryKey other = (RegistryKey)ob;                               ");
+    out("            if (this.name != other.name) return false;                         ");
+    out("            if (this.family != other.family) return false;                     ");
+    out("            return true;                                                       ");
+    out("        }                                                                      ");
+    out("    }                                                                          ");
+    out("    private static class LazyInitialization {                                  ");
+    out("        static final Map<RegistryKey,OptionKey> options = options();           ");
+    out("        private static Map<RegistryKey,OptionKey> options() {                  ");
+    out("            Map<RegistryKey,OptionKey> map =                                   ");
+    out("                new HashMap<RegistryKey,OptionKey>();                          ");
+
+    emit_unspec("StandardSocketOption.SO_BROADCAST", SOL_SOCKET, SO_BROADCAST);
+    emit_unspec("StandardSocketOption.SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE);
+    emit_unspec("StandardSocketOption.SO_LINGER",    SOL_SOCKET, SO_LINGER);
+    emit_unspec("StandardSocketOption.SO_SNDBUF",    SOL_SOCKET, SO_SNDBUF);
+    emit_unspec("StandardSocketOption.SO_RCVBUF",    SOL_SOCKET, SO_RCVBUF);
+    emit_unspec("StandardSocketOption.SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR);
+    emit_unspec("StandardSocketOption.TCP_NODELAY",  IPPROTO_TCP, TCP_NODELAY);
+
+    emit_inet("StandardSocketOption.IP_TOS",            IPPROTO_IP,     IP_TOS);
+    emit_inet("StandardSocketOption.IP_MULTICAST_IF",   IPPROTO_IP,     IP_MULTICAST_IF);
+    emit_inet("StandardSocketOption.IP_MULTICAST_TTL",  IPPROTO_IP,     IP_MULTICAST_TTL);
+    emit_inet("StandardSocketOption.IP_MULTICAST_LOOP", IPPROTO_IP,     IP_MULTICAST_LOOP);
+
+#ifdef AF_INET6
+    emit_inet6("StandardSocketOption.IP_MULTICAST_IF",   IPPROTO_IPV6,  IPV6_MULTICAST_IF);
+    emit_inet6("StandardSocketOption.IP_MULTICAST_TTL",  IPPROTO_IPV6,  IPV6_MULTICAST_HOPS);
+    emit_inet6("StandardSocketOption.IP_MULTICAST_LOOP", IPPROTO_IPV6,  IPV6_MULTICAST_LOOP);
+#endif
+
+    emit_unspec("ExtendedSocketOption.SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE);
+
+    out("            return map;                                                        ");
+    out("        }                                                                      ");
+    out("    }                                                                          ");
+    out("    public static OptionKey findOption(SocketOption name, ProtocolFamily family) { ");
+    out("        RegistryKey key = new RegistryKey(name, family);                       ");
+    out("        return LazyInitialization.options.get(key);                            ");
+    out("    }                                                                          ");
+    out("}                                                                              ");
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/nio/multicast/MulticastAddress.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.net.SocketException;
+
+/**
+ * Parses and represents a multicast address.
+ */
+
+class MulticastAddress {
+    private final InetAddress group;
+    private final int port;
+    private final NetworkInterface interf;
+
+    private MulticastAddress(InetAddress group, int port, NetworkInterface interf) {
+        this.group = group;
+        this.port = port;
+        this.interf = interf;
+    }
+
+    InetAddress group() {
+        return group;
+    }
+
+    int port() {
+        return port;
+    }
+
+    /**
+     * @return  The network interface, may be {@code null}
+     */
+    NetworkInterface interf() {
+        return interf;
+    }
+
+    /**
+     * Parses a string of the form "group:port[@interface]", returning
+     * a MulticastAddress representing the address
+     */
+    static MulticastAddress parse(String s) {
+        String[] components = s.split("@");
+        if (components.length > 2)
+            throw new IllegalArgumentException("At most one '@' expected");
+
+        // get group and port
+        String target = components[0];
+        int len = components[0].length();
+        int colon = components[0].lastIndexOf(':');
+        if ((colon < 1) || (colon > (len-2)))
+            throw new IllegalArgumentException("group:port expected");
+        String groupString = target.substring(0, colon);
+        int port = -1;
+        try {
+            port = Integer.parseInt(target.substring(colon+1, len));
+        } catch (NumberFormatException x) {
+             throw new IllegalArgumentException(x);
+        }
+
+        // handle IPv6 literal address
+        if (groupString.charAt(0) == '[') {
+            len = groupString.length();
+            if (groupString.charAt(len-1) != ']')
+                throw new IllegalArgumentException("missing ']'");
+            groupString = groupString.substring(1,len-1);
+            if (groupString.length() == 0)
+                throw new IllegalArgumentException("missing IPv6 address");
+        }
+
+        // get group address
+        InetAddress group = null;
+        try {
+            group = InetAddress.getByName(groupString);
+        } catch (UnknownHostException x) {
+            throw new IllegalArgumentException(x);
+        }
+        if (!group.isMulticastAddress()) {
+            throw new IllegalArgumentException("'" + group.getHostAddress() +
+                "' is not multicast address");
+        }
+
+        // optional interface
+        NetworkInterface interf = null;
+        if (components.length == 2) {
+            try {
+                interf = NetworkInterface.getByName(components[1]);
+            } catch (SocketException x) {
+                throw new IllegalArgumentException(x);
+            }
+            if (interf == null) {
+                throw new IllegalArgumentException("'" + components[1] +
+                   "' is not valid interface");
+            }
+        }
+        return new MulticastAddress(group, port, interf);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/nio/multicast/Reader.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.channels.*;
+import java.nio.charset.*;
+import java.nio.ByteBuffer;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+
+public class Reader {
+
+    static void usage() {
+        System.err.println("usage: java Reader group:port@interf [-only source...] [-block source...]");
+        System.exit(-1);
+    }
+
+    static void printDatagram(SocketAddress sa, ByteBuffer buf) {
+        System.out.format("-- datagram from %s --\n",
+            ((InetSocketAddress)sa).getAddress().getHostAddress());
+        System.out.println(Charset.defaultCharset().decode(buf));
+    }
+
+    static void parseAddessList(String s, List<InetAddress> list)
+        throws UnknownHostException
+    {
+        String[] sources = s.split(",");
+        for (int i=0; i<sources.length; i++) {
+            list.add(InetAddress.getByName(sources[i]));
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        if (args.length == 0)
+            usage();
+
+        // first parameter is the multicast address (interface required)
+        MulticastAddress target = MulticastAddress.parse(args[0]);
+        if (target.interf() == null)
+            usage();
+
+        // addition arguments are source addresses to include or exclude
+        List<InetAddress> includeList = new ArrayList<InetAddress>();
+        List<InetAddress> excludeList = new ArrayList<InetAddress>();
+        int argc = 1;
+        while (argc < args.length) {
+            String option = args[argc++];
+            if (argc >= args.length)
+                usage();
+            String value = args[argc++];
+            if (option.equals("-only")) {
+                 parseAddessList(value, includeList);
+                continue;
+            }
+            if (option.equals("-block")) {
+                parseAddessList(value, excludeList);
+                continue;
+            }
+            usage();
+        }
+        if (!includeList.isEmpty() && !excludeList.isEmpty()) {
+            usage();
+        }
+
+        // create and bind socket
+        ProtocolFamily family = StandardProtocolFamily.INET;
+        if (target.group() instanceof Inet6Address) {
+            family = StandardProtocolFamily.INET6;
+        }
+        DatagramChannel dc = DatagramChannel.open(family)
+            .setOption(StandardSocketOption.SO_REUSEADDR, true)
+            .bind(new InetSocketAddress(target.port()));
+
+        if (includeList.isEmpty()) {
+            // join group and block addresses on the exclude list
+            MembershipKey key = dc.join(target.group(), target.interf());
+            for (InetAddress source: excludeList) {
+                key.block(source);
+            }
+        } else {
+            // join with source-specific membership for each source
+            for (InetAddress source: includeList) {
+                dc.join(target.group(), target.interf(), source);
+            }
+        }
+
+        // register socket with Selector
+        Selector sel = Selector.open();
+        dc.configureBlocking(false);
+        dc.register(sel, SelectionKey.OP_READ);
+
+        // print out each datagram that we receive
+        ByteBuffer buf = ByteBuffer.allocateDirect(4096);
+        for (;;) {
+            int updated = sel.select();
+            if (updated > 0) {
+                Iterator<SelectionKey> iter = sel.selectedKeys().iterator();
+                while (iter.hasNext()) {
+                    SelectionKey sk = iter.next();
+                    iter.remove();
+
+                    DatagramChannel ch = (DatagramChannel)sk.channel();
+                    SocketAddress sa = ch.receive(buf);
+                    if (sa != null) {
+                        buf.flip();
+                        printDatagram(sa, buf);
+                        buf.rewind();
+                        buf.limit(buf.capacity());
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/nio/multicast/Sender.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.channels.*;
+import java.nio.charset.Charset;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Sample multicast sender to send a message in a multicast datagram
+ * to a given group.
+ */
+
+public class Sender {
+
+    private static void usage() {
+        System.err.println("usage: java Sender group:port[@interface] message");
+        System.exit(-1);
+    }
+
+    public static void main(String[] args) throws IOException {
+        if (args.length < 2)
+            usage();
+
+        MulticastAddress target = MulticastAddress.parse(args[0]);
+
+        // create socket
+        ProtocolFamily family = StandardProtocolFamily.INET;
+        if (target.group() instanceof Inet6Address)
+            family = StandardProtocolFamily.INET6;
+        DatagramChannel dc = DatagramChannel.open(family).bind(new InetSocketAddress(0));
+        if (target.interf() != null) {
+            dc.setOption(StandardSocketOption.IP_MULTICAST_IF, target.interf());
+        }
+
+        // send multicast packet
+        dc.send(Charset.defaultCharset().encode(args[1]),
+                new InetSocketAddress(target.group(), target.port()));
+        dc.close();
+    }
+
+}
--- a/src/solaris/native/java/net/net_util_md.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/java/net/net_util_md.c	Sun Aug 31 18:39:01 2008 +0100
@@ -791,7 +791,7 @@
 #endif /* AF_INET6 */
 }
 
-jint
+JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him) {
 #ifdef AF_INET6
     if (him->sa_family == AF_INET6) {
--- a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c	Sun Aug 31 18:39:01 2008 +0100
@@ -198,7 +198,7 @@
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
-                                            jobject fdo, jlong address,
+                                          jboolean preferIPv6, jobject fdo, jlong address,
                                             jint len, jobject dest)
 {
     jint fd = fdval(env, fdo);
@@ -215,7 +215,7 @@
 
     if (NET_InetAddressToSockaddr(env, destAddress, destPort,
                                   (struct sockaddr *)&sa,
-                                  &sa_len, JNI_TRUE) != 0) {
+                                  &sa_len, preferIPv6) != 0) {
       return IOS_THROWN;
     }
 
--- a/src/solaris/native/sun/nio/ch/FileKey.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/FileKey.c	Sun Aug 31 18:39:01 2008 +0100
@@ -33,12 +33,6 @@
 static jfieldID key_st_dev;    /* id for FileKey.st_dev */
 static jfieldID key_st_ino;    /* id for FileKey.st_ino */
 
-#define RESTARTABLE(_cmd, _result) do { \
-  do { \
-    _result = _cmd; \
-  } while ((_result == -1) && (errno == EINTR)); \
-} while(0)
-
 
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_FileKey_initIDs(JNIEnv *env, jclass clazz)
--- a/src/solaris/native/sun/nio/ch/Net.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/Net.c	Sun Aug 31 18:39:01 2008 +0100
@@ -37,17 +37,109 @@
 #include "net_util.h"
 #include "net_util_md.h"
 #include "nio_util.h"
-#include "java_net_SocketOptions.h"
 #include "nio.h"
 
+/**
+ * Definitions for source-specific multicast to allow for building
+ * with older header files.
+ */
+
+#ifdef __solaris__
+
+#ifndef IP_BLOCK_SOURCE
+
+#define IP_BLOCK_SOURCE                 0x15
+#define IP_UNBLOCK_SOURCE               0x16
+#define IP_ADD_SOURCE_MEMBERSHIP        0x17
+#define IP_DROP_SOURCE_MEMBERSHIP       0x18
+
+#define MCAST_BLOCK_SOURCE              0x2b
+#define MCAST_UNBLOCK_SOURCE            0x2c
+#define MCAST_JOIN_SOURCE_GROUP         0x2d
+#define MCAST_LEAVE_SOURCE_GROUP        0x2e
+
+#endif  /* IP_BLOCK_SOURCE */
+
+struct my_ip_mreq_source {
+        struct in_addr  imr_multiaddr;
+        struct in_addr  imr_sourceaddr;
+        struct in_addr  imr_interface;
+};
+
+/*
+ * Use #pragma pack() construct to force 32-bit alignment on amd64.
+ */
+#if defined(amd64)
+#pragma pack(4)
+#endif
+
+struct my_group_source_req {
+        uint32_t                gsr_interface;  /* interface index */
+        struct sockaddr_storage gsr_group;      /* group address */
+        struct sockaddr_storage gsr_source;     /* source address */
+};
+
+#if defined(amd64)
+#pragma pack()
+#endif
+
+#endif  /* __solaris__ */
+
+
 #ifdef __linux__
-#include <sys/utsname.h>
 
-#define IPV6_MULTICAST_IF 17
-#ifndef SO_BSDCOMPAT
-#define SO_BSDCOMPAT  14
-#endif
-#endif
+#ifndef IP_BLOCK_SOURCE
+
+#define IP_BLOCK_SOURCE                 38
+#define IP_UNBLOCK_SOURCE               37
+#define IP_ADD_SOURCE_MEMBERSHIP        39
+#define IP_DROP_SOURCE_MEMBERSHIP       40
+
+#define MCAST_BLOCK_SOURCE              43
+#define MCAST_UNBLOCK_SOURCE            44
+#define MCAST_JOIN_SOURCE_GROUP         42
+#define MCAST_LEAVE_SOURCE_GROUP        45
+
+#endif  /* IP_BLOCK_SOURCE */
+
+struct my_ip_mreq_source {
+        struct in_addr  imr_multiaddr;
+        struct in_addr  imr_interface;
+        struct in_addr  imr_sourceaddr;
+};
+
+struct my_group_source_req {
+        uint32_t                gsr_interface;  /* interface index */
+        struct sockaddr_storage gsr_group;      /* group address */
+        struct sockaddr_storage gsr_source;     /* source address */
+};
+
+#endif   /* __linux__ */
+
+
+#define COPY_INET6_ADDRESS(env, source, target) \
+    (*env)->GetByteArrayRegion(env, source, 0, 16, target)
+
+/*
+ * Copy IPv6 group, interface index, and IPv6 source address
+ * into group_source_req structure.
+ */
+static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
+                               jbyteArray source, struct my_group_source_req* req)
+{
+    struct sockaddr_in6* sin6;
+
+    req->gsr_interface = (uint32_t)index;
+
+    sin6 = (struct sockaddr_in6*)&(req->gsr_group);
+    sin6->sin6_family = AF_INET6;
+    COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
+
+    sin6 = (struct sockaddr_in6*)&(req->gsr_source);
+    sin6->sin6_family = AF_INET6;
+    COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
+}
+
 
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
@@ -55,43 +147,61 @@
     /* Here because Windows native code does need to init IDs */
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
+{
+    return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
 JNIEXPORT int JNICALL
-Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream,
-                            jboolean reuse)
+Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
+                            jboolean stream, jboolean reuse)
 {
     int fd;
+    int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+    int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
 
-#ifdef AF_INET6
-    if (ipv6_available())
-        fd = socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
-    else
-#endif /* AF_INET6 */
-        fd = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
-
+    fd = socket(domain, type, 0);
     if (fd < 0) {
         return handleSocketError(env, errno);
     }
     if (reuse) {
         int arg = 1;
-        if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
-                           sizeof(arg)) < 0) {
+        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
+                       sizeof(arg)) < 0) {
             JNU_ThrowByNameWithLastError(env,
                                          JNU_JAVANETPKG "SocketException",
                                          "sun.nio.ch.Net.setIntOption");
+            close(fd);
+            return -1;
         }
     }
+#ifdef __linux__
+    /* By default, Linux uses the route default */
+    if (domain == AF_INET6 && type == SOCK_DGRAM) {
+        int arg = 1;
+        if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
+                       sizeof(arg)) < 0) {
+            JNU_ThrowByNameWithLastError(env,
+                                         JNU_JAVANETPKG "SocketException",
+                                         "sun.nio.ch.Net.setIntOption");
+            close(fd);
+            return -1;
+        }
+    }
+#endif
     return fd;
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk */
-                         jobject fdo, jobject ia, int port)
+Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
+                          jobject fdo, jobject iao, int port)
 {
     SOCKADDR sa;
     int sa_len = SOCKADDR_LEN;
     int rv = 0;
 
-    if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr *)&sa, &sa_len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
       return;
     }
 
@@ -101,27 +211,27 @@
     }
 }
 
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
+{
+    if (listen(fdval(env, fdo), backlog) < 0)
+        handleSocketError(env, errno);
+}
+
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz,
-                                jobject fdo, jobject iao, jint port,
-                                jint trafficClass)
+Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
+                             jobject fdo, jobject iao, jint port)
 {
     SOCKADDR sa;
     int sa_len = SOCKADDR_LEN;
     int rv;
 
-    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, &sa_len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa,
+                                  &sa_len, preferIPv6) != 0)
+    {
       return IOS_THROWN;
     }
 
-#ifdef AF_INET6
-#if 0
-    if (trafficClass != 0 && ipv6_available()) { /* ## FIX */
-        NET_SetTrafficClass((struct sockaddr *)&sa, trafficClass);
-    }
-#endif
-#endif
-
     rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
     if (rv != 0) {
         if (errno == EINPROGRESS) {
@@ -159,119 +269,79 @@
     return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
 }
 
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+                                  jboolean mayNeedConversion, jint level, jint opt)
+{
+    int result;
+    struct linger linger;
+    u_char carg;
+    void *arg;
+    int arglen, n;
 
-#ifdef NEEDED
+    /* Option value is an int except for a few specific cases */
 
-/* ## This is gross.  We should generate platform-specific constant
- * ## definitions into a .java file and use those directly.
- */
+    arg = (void *)&result;
+    arglen = sizeof(result);
 
-static int
-mapOption(JNIEnv *env, int opt, int *klevel, int *kopt)
-{
-
-    switch (opt) {
-
-    case java_net_SocketOptions_IP_TOS:
-        *klevel = IPPROTO_IP;
-        *kopt = IP_TOS;
-        break;
-
-    case java_net_SocketOptions_SO_BROADCAST:
-    case java_net_SocketOptions_SO_KEEPALIVE:
-    case java_net_SocketOptions_SO_LINGER:
-    case java_net_SocketOptions_SO_OOBINLINE:
-    case java_net_SocketOptions_SO_RCVBUF:
-    case java_net_SocketOptions_SO_REUSEADDR:
-    case java_net_SocketOptions_SO_SNDBUF:
-        *klevel = SOL_SOCKET;
-        break;
-
-    case java_net_SocketOptions_TCP_NODELAY:
-        *klevel = IPPROTO_IP;
-        *kopt = TCP_NODELAY;
-        return 0;
-
-    default:
-        JNU_ThrowByName(env, "java/lang/IllegalArgumentException", NULL);
-        return -1;
+    if (level == IPPROTO_IP &&
+        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
+        arg = (void*)&carg;
+        arglen = sizeof(carg);
     }
 
-    switch (opt) {
-
-    case java_net_SocketOptions_SO_BROADCAST:   *kopt = SO_BROADCAST;  break;
-    case java_net_SocketOptions_SO_KEEPALIVE:   *kopt = SO_KEEPALIVE;  break;
-    case java_net_SocketOptions_SO_LINGER:      *kopt = SO_LINGER;  break;
-    case java_net_SocketOptions_SO_OOBINLINE:   *kopt = SO_OOBINLINE;  break;
-    case java_net_SocketOptions_SO_RCVBUF:      *kopt = SO_RCVBUF;  break;
-    case java_net_SocketOptions_SO_REUSEADDR:   *kopt = SO_REUSEADDR;  break;
-    case java_net_SocketOptions_SO_SNDBUF:      *kopt = SO_SNDBUF;  break;
-
-    default:
-        return -1;
+    if (level == SOL_SOCKET && opt == SO_LINGER) {
+        arg = (void *)&linger;
+        arglen = sizeof(linger);
     }
 
-    return 0;
-}
-#endif
-
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz,
-                                  jobject fdo, jint opt)
-{
-    int klevel, kopt;
-    int result;
-    struct linger linger;
-    void *arg;
-    int arglen;
-
-    if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
-        JNU_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "SocketException",
-                                     "Unsupported socket option");
-        return -1;
+    if (mayNeedConversion) {
+        n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen);
+    } else {
+        n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
     }
-
-    if (opt == java_net_SocketOptions_SO_LINGER) {
-        arg = (void *)&linger;
-        arglen = sizeof(linger);
-    } else {
-        arg = (void *)&result;
-        arglen = sizeof(result);
-    }
-
-    if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) {
+    if (n < 0) {
         JNU_ThrowByNameWithLastError(env,
                                      JNU_JAVANETPKG "SocketException",
                                      "sun.nio.ch.Net.getIntOption");
         return -1;
     }
 
-    if (opt == java_net_SocketOptions_SO_LINGER)
-        return linger.l_onoff ? linger.l_linger : -1;
-    else
-        return result;
+    if (level == IPPROTO_IP &&
+        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
+    {
+        return (jint)carg;
+    }
+
+    if (level == SOL_SOCKET && opt == SO_LINGER)
+        return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
+
+    return (jint)result;
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz,
-                                  jobject fdo, jint opt, jint arg)
+Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+                                  jboolean mayNeedConversion, jint level, jint opt, jint arg)
 {
-    int klevel, kopt;
     int result;
     struct linger linger;
+    u_char carg;
     void *parg;
-    int arglen;
+    int arglen, n;
 
-    if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
-        JNU_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "SocketException",
-                                     "Unsupported socket option");
-        return;
+    /* Option value is an int except for a few specific cases */
+
+    parg = (void*)&arg;
+    arglen = sizeof(arg);
+
+    if (level == IPPROTO_IP &&
+        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
+        parg = (void*)&carg;
+        arglen = sizeof(carg);
+        carg = (u_char)arg;
     }
 
-    if (opt == java_net_SocketOptions_SO_LINGER) {
+    if (level == SOL_SOCKET && opt == SO_LINGER) {
         parg = (void *)&linger;
         arglen = sizeof(linger);
         if (arg >= 0) {
@@ -281,19 +351,199 @@
             linger.l_onoff = 0;
             linger.l_linger = 0;
         }
-    } else {
-        parg = (void *)&arg;
-        arglen = sizeof(arg);
     }
 
-    if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) {
+    if (mayNeedConversion) {
+        n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
+    } else {
+        n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
+    }
+    if (n < 0) {
         JNU_ThrowByNameWithLastError(env,
                                      JNU_JAVANETPKG "SocketException",
                                      "sun.nio.ch.Net.setIntOption");
     }
 }
 
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+                                jint group, jint interf, jint source)
+{
+    struct ip_mreq mreq;
+    struct my_ip_mreq_source mreq_source;
+    int opt, n, optlen;
+    void* optval;
 
+    if (source == 0) {
+        mreq.imr_multiaddr.s_addr = htonl(group);
+        mreq.imr_interface.s_addr = htonl(interf);
+        opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+        optval = (void*)&mreq;
+        optlen = sizeof(mreq);
+    } else {
+        mreq_source.imr_multiaddr.s_addr = htonl(group);
+        mreq_source.imr_sourceaddr.s_addr = htonl(source);
+        mreq_source.imr_interface.s_addr = htonl(interf);
+        opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
+        optval = (void*)&mreq_source;
+        optlen = sizeof(mreq_source);
+    }
+
+    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
+    if (n < 0) {
+        if (join && (errno == ENOPROTOOPT))
+            return IOS_UNAVAILABLE;
+        handleSocketError(env, errno);
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+                                    jint group, jint interf, jint source)
+{
+    struct my_ip_mreq_source mreq_source;
+    int n;
+    int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
+
+    mreq_source.imr_multiaddr.s_addr = htonl(group);
+    mreq_source.imr_sourceaddr.s_addr = htonl(source);
+    mreq_source.imr_interface.s_addr = htonl(interf);
+
+    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
+                   (void*)&mreq_source, sizeof(mreq_source));
+    if (n < 0) {
+        if (block && (errno == ENOPROTOOPT))
+            return IOS_UNAVAILABLE;
+        handleSocketError(env, errno);
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+                                jbyteArray group, jint index, jbyteArray source)
+{
+    struct ipv6_mreq mreq6;
+    struct my_group_source_req req;
+    int opt, n, optlen;
+    void* optval;
+
+    if (source == NULL) {
+        COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
+        mreq6.ipv6mr_interface = (int)index;
+        opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+        optval = (void*)&mreq6;
+        optlen = sizeof(mreq6);
+    } else {
+#ifdef __linux__
+        /* Include-mode filtering broken on Linux at least to 2.6.24 */
+        return IOS_UNAVAILABLE;
+#else
+        initGroupSourceReq(env, group, index, source, &req);
+        opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
+        optval = (void*)&req;
+        optlen = sizeof(req);
+#endif
+    }
+
+    n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
+    if (n < 0) {
+        if (join && (errno == ENOPROTOOPT))
+            return IOS_UNAVAILABLE;
+        handleSocketError(env, errno);
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+                                    jbyteArray group, jint index, jbyteArray source)
+{
+    struct my_group_source_req req;
+    int n;
+    int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
+
+    initGroupSourceReq(env, group, index, source, &req);
+
+    n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
+        (void*)&req, sizeof(req));
+    if (n < 0) {
+        if (block && (errno == ENOPROTOOPT))
+            return IOS_UNAVAILABLE;
+        handleSocketError(env, errno);
+    }
+    return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
+{
+    struct in_addr in;
+    int arglen = sizeof(struct in_addr);
+    int n;
+
+    in.s_addr = htonl(interf);
+
+    n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
+                   (void*)&(in.s_addr), arglen);
+    if (n < 0) {
+        handleSocketError(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
+{
+    struct in_addr in;
+    int arglen = sizeof(struct in_addr);
+    int n;
+
+    n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
+    if (n < 0) {
+        handleSocketError(env, errno);
+        return -1;
+    }
+    return ntohl(in.s_addr);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
+{
+    int value = (jint)index;
+    int arglen = sizeof(value);
+    int n;
+
+    n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
+                   (void*)&(index), arglen);
+    if (n < 0) {
+        handleSocketError(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
+{
+    int index;
+    int arglen = sizeof(index);
+    int n;
+
+    n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
+    if (n < 0) {
+        handleSocketError(env, errno);
+        return -1;
+    }
+    return (jint)index;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
+{
+    int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
+        (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
+    if (shutdown(fdval(env, fdo), how) < 0)
+        handleSocketError(env, errno);
+}
 
 /* Declared in nio_util.h */
 
--- a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c	Sun Aug 31 18:39:01 2008 +0100
@@ -65,14 +65,6 @@
                                      "(Ljava/net/InetAddress;I)V");
 }
 
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_ServerSocketChannelImpl_listen(JNIEnv *env, jclass cl,
-                                               jobject fdo, jint backlog)
-{
-    if (listen(fdval(env, fdo), backlog) < 0)
-        handleSocketError(env, errno);
-}
-
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this,
                                                 jobject ssfdo, jobject newfdo,
--- a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c	Sun Aug 31 18:39:01 2008 +0100
@@ -35,10 +35,6 @@
 #include <netinet/in.h>
 #endif
 
-#if defined(__solaris__) && !defined(_SOCKLEN_T)
-typedef size_t socklen_t;       /* New in SunOS 5.7, so need this for 5.6 */
-#endif
-
 #include "jni.h"
 #include "jni_util.h"
 #include "net_util.h"
@@ -88,12 +84,3 @@
     }
     return 0;
 }
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl,
-                                           jobject fdo, jint how)
-{
-    if (shutdown(fdval(env, fdo), how) < 0)
-        handleSocketError(env, errno);
-}
--- a/src/solaris/native/sun/nio/ch/nio_util.h	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/nio_util.h	Sun Aug 31 18:39:01 2008 +0100
@@ -27,8 +27,15 @@
 #include "jni_util.h"
 #include "jvm.h"
 #include "jlong.h"
+#include <errno.h>
 #include <sys/types.h>
 
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
 
 /* NIO utility procedures */
 
--- a/src/windows/native/java/net/net_util_md.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/java/net/net_util_md.c	Sun Aug 31 18:39:01 2008 +0100
@@ -889,7 +889,7 @@
     return 0;
 }
 
-jint
+JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him) {
     if (him->sa_family == AF_INET6) {
         return ntohs(((struct sockaddr_in6*)him)->sin6_port);
--- a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c	Sun Aug 31 18:39:01 2008 +0100
@@ -39,46 +39,9 @@
 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 */
-static jfieldID ia_addrID;
-static jfieldID ia_famID;
 static jclass isa_class;        /* java.net.InetSocketAddress */
-static jclass ia_class;
-static jmethodID isa_ctorID;    /*   .InetSocketAddress(InetAddress, int) */
-static jmethodID ia_ctorID;
+static jmethodID isa_ctorID;    /* java.net.InetSocketAddress(InetAddress, int) */
 
-/*
- * Returns JNI_TRUE if DatagramChannelImpl has already cached an
- * InetAddress/port corresponding to the socket address.
- */
-static jboolean isSenderCached(JNIEnv *env, jobject this, struct sockaddr_in *sa) {
-    jobject senderAddr;
-
-    /* shouldn't happen until we have dual IPv4/IPv6 stack (post-XP ?) */
-    if (sa->sin_family != AF_INET) {
-        return JNI_FALSE;
-    }
-
-    /*
-     * Compare source address to cached InetAddress
-     */
-    senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
-    if (senderAddr == NULL) {
-        return JNI_FALSE;
-    }
-    if ((jint)ntohl(sa->sin_addr.s_addr) !=
-        (*env)->GetIntField(env, senderAddr, ia_addrID)) {
-        return JNI_FALSE;
-    }
-
-    /*
-     * Compare source port to cached port
-     */
-    if ((jint)ntohs(sa->sin_port) !=
-        (*env)->GetIntField(env, this, dci_senderPortID)) {
-        return JNI_FALSE;
-    }
-    return JNI_TRUE;
-}
 
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz)
@@ -99,32 +62,6 @@
                                           "Ljava/net/InetAddress;");
     dci_senderPortID = (*env)->GetFieldID(env, clazz,
                                           "cachedSenderPort", "I");
-    clazz = (*env)->FindClass(env, "java/net/Inet4Address");
-    ia_class = (*env)->NewGlobalRef(env, clazz);
-    ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I");
-    ia_famID = (*env)->GetFieldID(env, clazz, "family", "I");
-    ia_ctorID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
-}
-
-/*
- * Return JNI_TRUE if this Windows edition supports ICMP Port Unreachable
- */
-__inline static jboolean supportPortUnreachable() {
-    static jboolean initDone;
-    static jboolean portUnreachableSupported;
-
-    if (!initDone) {
-        OSVERSIONINFO ver;
-        ver.dwOSVersionInfoSize = sizeof(ver);
-        GetVersionEx(&ver);
-        if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 5) {
-            portUnreachableSupported = JNI_TRUE;
-        } else {
-            portUnreachableSupported = JNI_FALSE;
-        }
-        initDone = JNI_TRUE;
-    }
-    return portUnreachableSupported;
 }
 
 /*
@@ -140,15 +77,8 @@
     char buf[1];
     fd_set tbl;
     struct timeval t = { 0, 0 };
-    struct sockaddr_in rmtaddr;
-    int addrlen = sizeof(rmtaddr);
-
-    /*
-     * A no-op if this OS doesn't support it.
-     */
-    if (!supportPortUnreachable()) {
-        return JNI_FALSE;
-    }
+    SOCKETADDRESS sa;
+    int addrlen = sizeof(sa);
 
     /*
      * Peek at the queue to see if there is an ICMP port unreachable. If there
@@ -161,7 +91,7 @@
             break;
         }
         if (recvfrom(fd, buf, 1, MSG_PEEK,
-                     (struct sockaddr *)&rmtaddr, &addrlen) != SOCKET_ERROR) {
+                     (struct sockaddr *)&sa, &addrlen) != SOCKET_ERROR) {
             break;
         }
         if (WSAGetLastError() != WSAECONNRESET) {
@@ -169,7 +99,7 @@
             break;
         }
 
-        recvfrom(fd, buf, 1, 0,  (struct sockaddr *)&rmtaddr, &addrlen);
+        recvfrom(fd, buf, 1, 0,  (struct sockaddr *)&sa, &addrlen);
         got_icmp = JNI_TRUE;
     }
 
@@ -182,12 +112,12 @@
 {
     jint fd = fdval(env, fdo);
     int rv = 0;
-    struct sockaddr_in psa;
-    int sa_len = sizeof(psa);
+    SOCKETADDRESS sa;
+    int sa_len = sizeof(sa);
 
-    memset(&psa, 0, sa_len);
+    memset(&sa, 0, sa_len);
 
-    rv = connect((SOCKET)fd, (struct sockaddr *)&psa, sa_len);
+    rv = connect((SOCKET)fd, (struct sockaddr *)&sa, sa_len);
     if (rv == SOCKET_ERROR) {
         handleSocketError(env, WSAGetLastError());
     }
@@ -200,10 +130,11 @@
 {
     jint fd = fdval(env, fdo);
     void *buf = (void *)jlong_to_ptr(address);
-    struct sockaddr_in psa;
-    int sa_len = sizeof(psa);
+    SOCKETADDRESS sa;
+    int sa_len = sizeof(sa);
     BOOL retry = FALSE;
     jint n;
+    jobject senderAddr;
 
     do {
         retry = FALSE;
@@ -211,7 +142,7 @@
                      (char *)buf,
                      len,
                      0,
-                     (struct sockaddr *)&psa,
+                     (struct sockaddr *)&sa,
                      &sa_len);
 
         if (n == SOCKET_ERROR) {
@@ -233,21 +164,30 @@
         }
     } while (retry);
 
-    if (!isSenderCached(env, this, &psa)) {
-        int port = ntohs(psa.sin_port);
-        jobject ia = (*env)->NewObject(env, ia_class, ia_ctorID);
+    /*
+     * If the source address and port match the cached address
+     * and port in DatagramChannelImpl then we don't need to
+     * create InetAddress and InetSocketAddress objects.
+     */
+    senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
+    if (senderAddr != NULL) {
+        if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
+                                           senderAddr)) {
+            senderAddr = NULL;
+        } else {
+            jint port = (*env)->GetIntField(env, this, dci_senderPortID);
+            if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) {
+                senderAddr = NULL;
+            }
+        }
+    }
+    if (senderAddr == NULL) {
         jobject isa = NULL;
-
-        if (psa.sin_family != AF_INET) {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                            "Protocol family unavailable");
-        }
+        int port;
+        jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa,
+                                               &port);
 
         if (ia != NULL) {
-            // populate InetAddress (assumes AF_INET)
-            (*env)->SetIntField(env, ia, ia_addrID, ntohl(psa.sin_addr.s_addr));
-
-            // create InetSocketAddress
             isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
         }
 
@@ -258,9 +198,8 @@
 
         // update cachedSenderInetAddress/cachedSenderPort
         (*env)->SetObjectField(env, this, dci_senderAddrID, ia);
-        (*env)->SetIntField(env, this, dci_senderPortID, port);
-
-        // update sender
+        (*env)->SetIntField(env, this, dci_senderPortID,
+                            NET_GetPortFromSockaddr((struct sockaddr *)&sa));
         (*env)->SetObjectField(env, this, dci_senderID, isa);
     }
     return n;
@@ -268,21 +207,20 @@
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
-                                            jobject fdo, jlong address,
-                                            jint len, jobject dest)
+                                          jboolean preferIPv6, jobject fdo,
+                                          jlong address, jint len, jobject dest)
 {
     jint fd = fdval(env, fdo);
     void *buf = (void *)jlong_to_ptr(address);
-    SOCKETADDRESS psa;
-    int sa_len = sizeof(psa);
+    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 *)&psa,
-                                   &sa_len, JNI_FALSE) != 0) {
+                                  (struct sockaddr *)&sa,
+                                   &sa_len, preferIPv6) != 0) {
       return IOS_THROWN;
     }
 
@@ -290,7 +228,7 @@
                buf,
                len,
                0,
-               (struct sockaddr *)&psa,
+               (struct sockaddr *)&sa,
                sa_len);
     if (rv == SOCKET_ERROR) {
         int theErr = (jint)WSAGetLastError();
--- a/src/windows/native/sun/nio/ch/Net.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/Net.c	Sun Aug 31 18:39:01 2008 +0100
@@ -36,51 +36,95 @@
 
 #include "sun_nio_ch_Net.h"
 
+/**
+ * Definitions to allow for building with older SDK include files.
+ */
 
-static jfieldID ia_addrID;
-static jclass ia_class;
-static jmethodID ia_ctorID;
-static jfieldID ia_famID;
+#ifndef MCAST_BLOCK_SOURCE
 
-/**************************************************************
- * static method to store field IDs in initializers
+#define MCAST_BLOCK_SOURCE          43
+#define MCAST_UNBLOCK_SOURCE        44
+#define MCAST_JOIN_SOURCE_GROUP     45
+#define MCAST_LEAVE_SOURCE_GROUP    46
+
+#endif  /* MCAST_BLOCK_SOURCE */
+
+typedef struct my_ip_mreq_source {
+    IN_ADDR imr_multiaddr;
+    IN_ADDR imr_sourceaddr;
+    IN_ADDR imr_interface;
+};
+
+typedef struct my_group_source_req {
+    ULONG gsr_interface;
+    SOCKADDR_STORAGE gsr_group;
+    SOCKADDR_STORAGE gsr_source;
+};
+
+/**
+ * Copy IPv6 address as jbytearray to target
  */
+#define COPY_INET6_ADDRESS(env, source, target) \
+    (*env)->GetByteArrayRegion(env, source, 0, 16, target)
+
+
 
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
 {
-    clazz = (*env)->FindClass(env, "java/net/Inet4Address");
-    ia_class = (*env)->NewGlobalRef(env, clazz);
-    ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I");
-    ia_famID = (*env)->GetFieldID(env, clazz, "family", "I");
-    ia_ctorID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
+    /* nothing to do */
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
+{
+    /*
+     * Return true if Windows Vista or newer, and IPv6 is configured
+     */
+    OSVERSIONINFO ver;
+    ver.dwOSVersionInfoSize = sizeof(ver);
+    GetVersionEx(&ver);
+    if ((ver.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
+        (ver.dwMajorVersion >= 6)  && ipv6_available())
+    {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream,
-                            jboolean reuse)
+Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
+                            jboolean stream, jboolean reuse)
 {
     SOCKET s;
+    int domain = (preferIPv6) ? AF_INET6 : AF_INET;
 
-    s = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
+    s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
     if (s != INVALID_SOCKET) {
         SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
+
+        /* IPV6_V6ONLY is true by default */
+        if (domain == AF_INET6) {
+            int opt = 0;
+            setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+                       (const char *)&opt, sizeof(opt));
+        }
     } else {
         NET_ThrowNew(env, WSAGetLastError(), "socket");
     }
+
     return (jint)s;
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz,
-                         jobject fdo, jobject iao, jint port)
+Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
+                          jobject fdo, jobject iao, jint port)
 {
     SOCKETADDRESS sa;
     int rv;
-    int sa_len = sizeof(sa);
+    int sa_len;
 
-   if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
       return;
     }
 
@@ -89,16 +133,25 @@
         NET_ThrowNew(env, WSAGetLastError(), "bind");
 }
 
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
+{
+    if (listen(fdval(env,fdo), backlog) == SOCKET_ERROR) {
+        NET_ThrowNew(env, WSAGetLastError(), "listen");
+    }
+}
+
+
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao,
-                            jint port, jint trafficClass)
+Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo,
+                             jobject iao, jint port)
 {
     SOCKETADDRESS sa;
     int rv;
-    int sa_len = sizeof(sa);
+    int sa_len;
 
-   if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) {
-      return IOS_THROWN;
+    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
+        return IOS_THROWN;
     }
 
     rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
@@ -116,7 +169,7 @@
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
 {
-    struct sockaddr_in sa;
+    SOCKETADDRESS sa;
     int sa_len = sizeof(sa);
 
     if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
@@ -127,50 +180,64 @@
         NET_ThrowNew(env, error, "getsockname");
         return IOS_THROWN;
     }
-    return (jint)ntohs(sa.sin_port);
+    return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
 }
 
 JNIEXPORT jobject JNICALL
 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
 {
-    struct sockaddr_in sa;
+    SOCKETADDRESS sa;
     int sa_len = sizeof(sa);
-    jobject iao;
+    int port;
 
     if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
         NET_ThrowNew(env, WSAGetLastError(), "getsockname");
         return NULL;
     }
-
-    iao = (*env)->NewObject(env, ia_class, ia_ctorID);
-    if (iao == NULL) {
-        JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
-    } else {
-        (*env)->SetIntField(env, iao, ia_addrID, ntohl(sa.sin_addr.s_addr));
-    }
-
-    return iao;
+    return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
 }
 
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    SOCKETADDRESS sa;
+    int sa_len = sizeof(sa);
+
+    if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+        int error = WSAGetLastError();
+        if (error == WSAEINVAL) {
+            return 0;
+        }
+        NET_ThrowNew(env, error, "getsockname");
+        return IOS_THROWN;
+    }
+    return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
+}
+
+JNIEXPORT jobject JNICALL
+Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    SOCKETADDRESS sa;
+    int sa_len = sizeof(sa);
+    int port;
+
+    if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+        NET_ThrowNew(env, WSAGetLastError(), "getsockname");
+        return NULL;
+    }
+    return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+}
 
 JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz,
-                                  jobject fdo, jint opt)
+Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+                                  jboolean mayNeedConversion, jint level, jint opt)
 {
-    int klevel, kopt;
-    int result;
+    int result = 0;
     struct linger linger;
     char *arg;
-    int arglen;
+    int arglen, n;
 
-    if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
-        JNU_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "SocketException",
-                                     "Unsupported socket option");
-        return IOS_THROWN;
-    }
-
-    if (opt == java_net_SocketOptions_SO_LINGER) {
+    if (level == SOL_SOCKET && opt == SO_LINGER) {
         arg = (char *)&linger;
         arglen = sizeof(linger);
     } else {
@@ -178,34 +245,40 @@
         arglen = sizeof(result);
     }
 
-    if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) {
-        NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption");
+    /**
+     * HACK: IP_TOS is deprecated on Windows and querying the option
+     * returns a protocol error. NET_GetSockOpt handles this and uses
+     * a fallback mechanism.
+     */
+    if (level == IPPROTO_IP && opt == IP_TOS) {
+        mayNeedConversion = JNI_TRUE;
+    }
+
+    if (mayNeedConversion) {
+        n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen);
+    } else {
+        n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
+    }
+    if (n < 0) {
+        handleSocketError(env, WSAGetLastError());
         return IOS_THROWN;
     }
 
-    if (opt == java_net_SocketOptions_SO_LINGER)
+    if (level == SOL_SOCKET && opt == SO_LINGER)
         return linger.l_onoff ? linger.l_linger : -1;
     else
         return result;
 }
 
 JNIEXPORT void JNICALL
-Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz,
-                                  jobject fdo, jint opt, jint arg)
+Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+                                  jboolean mayNeedConversion, jint level, jint opt, jint arg)
 {
-    int klevel, kopt;
     struct linger linger;
     char *parg;
-    int arglen;
+    int arglen, n;
 
-    if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
-        JNU_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "SocketException",
-                                     "Unsupported socket option");
-        return;
-    }
-
-    if (opt == java_net_SocketOptions_SO_LINGER) {
+    if (level == SOL_SOCKET && opt == SO_LINGER) {
         parg = (char *)&linger;
         arglen = sizeof(linger);
         if (arg >= 0) {
@@ -220,7 +293,200 @@
         arglen = sizeof(arg);
     }
 
-    if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) {
-        NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption");
+    if (mayNeedConversion) {
+        n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
+    } else {
+        n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
+    }
+    if (n < 0)
+        handleSocketError(env, WSAGetLastError());
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+                                jint group, jint interf, jint source)
+{
+    struct ip_mreq mreq;
+    struct my_ip_mreq_source mreq_source;
+    int opt, n, optlen;
+    void* optval;
+
+    if (source == 0) {
+        mreq.imr_multiaddr.s_addr = htonl(group);
+        mreq.imr_interface.s_addr = htonl(interf);
+        opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+        optval = (void*)&mreq;
+        optlen = sizeof(mreq);
+    } else {
+        mreq_source.imr_multiaddr.s_addr = htonl(group);
+        mreq_source.imr_sourceaddr.s_addr = htonl(source);
+        mreq_source.imr_interface.s_addr = htonl(interf);
+        opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
+        optval = (void*)&mreq_source;
+        optlen = sizeof(mreq_source);
+    }
+
+    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
+    if (n < 0) {
+        if (join && (WSAGetLastError() == WSAENOPROTOOPT))
+            return IOS_UNAVAILABLE;
+        handleSocketError(env, WSAGetLastError());
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+                                   jint group, jint interf, jint source)
+{
+    struct my_ip_mreq_source mreq_source;
+    int n;
+    int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
+
+    mreq_source.imr_multiaddr.s_addr = htonl(group);
+    mreq_source.imr_sourceaddr.s_addr = htonl(source);
+    mreq_source.imr_interface.s_addr = htonl(interf);
+
+    n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
+                   (void*)&mreq_source, sizeof(mreq_source));
+    if (n < 0) {
+        if (block && (WSAGetLastError() == WSAENOPROTOOPT))
+            return IOS_UNAVAILABLE;
+        handleSocketError(env, WSAGetLastError());
+    }
+    return 0;
+}
+
+/**
+ * Call setsockopt with a IPPROTO_IPV6 level socket option
+ * and a group_source_req structure as the option value. The
+ * given IPv6 group, interface index, and IPv6 source address
+ * are copied into the structure.
+ */
+static int setGroupSourceReqOption(JNIEnv* env,
+                                   jobject fdo,
+                                   int opt,
+                                   jbyteArray group,
+                                   jint index,
+                                   jbyteArray source)
+{
+    struct my_group_source_req req;
+    struct sockaddr_in6* sin6;
+
+    req.gsr_interface = (ULONG)index;
+
+    sin6 = (struct sockaddr_in6*)&(req.gsr_group);
+    sin6->sin6_family = AF_INET6;
+    COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
+
+    sin6 = (struct sockaddr_in6*)&(req.gsr_source);
+    sin6->sin6_family = AF_INET6;
+    COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
+
+    return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req));
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+                                jbyteArray group, jint index, jbyteArray source)
+{
+    struct ipv6_mreq mreq6;
+    int n;
+
+    if (source == NULL) {
+        int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+        COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
+        mreq6.ipv6mr_interface = (int)index;
+        n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
+                       (void*)&mreq6, sizeof(mreq6));
+    } else {
+        int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
+        n = setGroupSourceReqOption(env, fdo, opt, group, index, source);
+    }
+
+    if (n < 0) {
+        handleSocketError(env, errno);
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+                                    jbyteArray group, jint index, jbyteArray source)
+{
+    int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
+    int n = setGroupSourceReqOption(env, fdo, opt, group, index, source);
+    if (n < 0) {
+        handleSocketError(env, errno);
+    }
+    return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
+{
+    struct in_addr in;
+    int arglen = sizeof(struct in_addr);
+    int n;
+
+    in.s_addr = htonl(interf);
+
+    n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
+                   (void*)&(in.s_addr), arglen);
+    if (n < 0) {
+        handleSocketError(env, WSAGetLastError());
     }
 }
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
+{
+    struct in_addr in;
+    int arglen = sizeof(struct in_addr);
+    int n;
+
+    n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
+    if (n < 0) {
+        handleSocketError(env, WSAGetLastError());
+        return IOS_THROWN;
+    }
+    return ntohl(in.s_addr);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
+{
+    int value = (jint)index;
+    int arglen = sizeof(value);
+    int n;
+
+    n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
+                   (void*)&(index), arglen);
+    if (n < 0) {
+        handleSocketError(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
+{
+    int index;
+    int arglen = sizeof(index);
+    int n;
+
+    n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
+    if (n < 0) {
+        handleSocketError(env, errno);
+        return -1;
+    }
+    return (jint)index;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) {
+    int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE :
+        (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH;
+    if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) {
+        NET_ThrowNew(env, WSAGetLastError(), "shutdown");
+    }
+}
--- a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c	Sun Aug 31 18:39:01 2008 +0100
@@ -46,10 +46,6 @@
 static jfieldID fd_fdID;        /* java.io.FileDescriptor.fd */
 static jclass isa_class;        /* java.net.InetSocketAddress */
 static jmethodID isa_ctorID;    /* InetSocketAddress(InetAddress, int) */
-static jclass ia_class;         /* java.net.InetAddress */
-static jmethodID ia_ctorID;     /* InetAddress() */
-static jfieldID ia_addrID;      /* java.net.InetAddress.address */
-static jfieldID ia_famID;       /* java.net.InetAddress.family */
 
 
 /**************************************************************
@@ -66,12 +62,6 @@
     isa_class = (*env)->NewGlobalRef(env, cls);
     isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
                                      "(Ljava/net/InetAddress;I)V");
-
-    cls = (*env)->FindClass(env, "java/net/Inet4Address");
-    ia_class = (*env)->NewGlobalRef(env, cls);
-    ia_ctorID = (*env)->GetMethodID(env, cls, "<init>","()V");
-    ia_addrID = (*env)->GetFieldID(env, cls, "address", "I");
-    ia_famID = (*env)->GetFieldID(env, cls, "family", "I");
 }
 
 JNIEXPORT void JNICALL
@@ -90,8 +80,9 @@
 {
     jint ssfd = (*env)->GetIntField(env, ssfdo, fd_fdID);
     jint newfd;
-    struct sockaddr_in sa;
-    jobject remote_ia = 0;
+    SOCKETADDRESS sa;
+    jobject remote_ia;
+    int remote_port;
     jobject isa;
     jobject ia;
     int addrlen = sizeof(sa);
@@ -106,14 +97,13 @@
         JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
         return IOS_THROWN;
     }
+
     (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
+    remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port);
 
-    ia = (*env)->NewObject(env, ia_class, ia_ctorID);
-    (*env)->SetIntField(env, ia, ia_addrID, ntohl(sa.sin_addr.s_addr));
-    (*env)->SetIntField(env, ia, ia_famID, sa.sin_family);
+    isa = (*env)->NewObject(env, isa_class, isa_ctorID,
+                            remote_ia, remote_port);
+    (*env)->SetObjectArrayElement(env, isaa, 0, isa);
 
-    isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia,
-                            ntohs(sa.sin_port));
-    (*env)->SetObjectArrayElement(env, isaa, 0, isa);
     return 1;
 }
--- a/src/windows/native/sun/nio/ch/SocketChannelImpl.c	Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/SocketChannelImpl.c	Sun Aug 31 18:39:01 2008 +0100
@@ -139,12 +139,3 @@
 
     return 0;
 }
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl,
-                                           jobject fdo, jint how)
-{
-    if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) {
-        NET_ThrowNew(env, WSAGetLastError(), "shutdown");
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2007-2008 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 4527345
+ * @summary Unit test for DatagramChannel's multicast support
+ * @build BasicMulticastTests NetworkConfiguration
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+import java.io.IOException;
+
+public class BasicMulticastTests {
+
+    /**
+     * Tests that existing membership key is returned by join methods and that
+     * membership key methods return the expected results
+     */
+    static void membershipKeyTests(NetworkInterface nif,
+                                   InetAddress group,
+                                   InetAddress source)
+        throws IOException
+    {
+        System.out.format("MembershipKey test using %s @ %s\n",
+            group.getHostAddress(), nif.getName());
+
+        ProtocolFamily family = (group instanceof Inet4Address) ?
+            StandardProtocolFamily.INET : StandardProtocolFamily.INET6;
+
+        DatagramChannel dc = DatagramChannel.open(family)
+            .setOption(StandardSocketOption.SO_REUSEADDR, true)
+            .bind(new InetSocketAddress(source, 0));
+
+        // check existing key is returned
+        MembershipKey key = dc.join(group, nif);
+        MembershipKey other = dc.join(group, nif);
+        if (other != key) {
+            throw new RuntimeException("existing key not returned");
+        }
+
+        // check key
+        if (!key.isValid())
+            throw new RuntimeException("key is not valid");
+        if (!key.getGroup().equals(group))
+            throw new RuntimeException("group is incorrect");
+        if (!key.getNetworkInterface().equals(nif))
+            throw new RuntimeException("network interface is incorrect");
+        if (key.getSourceAddress() != null)
+            throw new RuntimeException("key is source specific");
+
+        // drop membership
+        key.drop();
+        if (key.isValid()) {
+            throw new RuntimeException("key is still valid");
+        }
+
+        // source-specific
+        try {
+            key = dc.join(group, nif, source);
+            other = dc.join(group, nif, source);
+            if (other != key) {
+                throw new RuntimeException("existing key not returned");
+            }
+            if (!key.isValid())
+                throw new RuntimeException("key is not valid");
+            if (!key.getGroup().equals(group))
+                throw new RuntimeException("group is incorrect");
+            if (!key.getNetworkInterface().equals(nif))
+                throw new RuntimeException("network interface is incorrect");
+            if (!key.getSourceAddress().equals(source))
+                throw new RuntimeException("key's source address incorrect");
+
+            // drop membership
+            key.drop();
+            if (key.isValid()) {
+                throw new RuntimeException("key is still valid");
+            }
+        } catch (UnsupportedOperationException x) {
+        }
+
+        // done
+        dc.close();
+    }
+
+    /**
+     * Tests exceptions for invalid arguments or scenarios
+     */
+    static void exceptionTests(NetworkInterface nif)
+        throws IOException
+    {
+        System.out.println("Exception Tests");
+
+        DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+            .setOption(StandardSocketOption.SO_REUSEADDR, true)
+            .bind(new InetSocketAddress(0));
+
+        InetAddress group = InetAddress.getByName("225.4.5.6");
+        InetAddress notGroup = InetAddress.getByName("1.2.3.4");
+        InetAddress thisHost = InetAddress.getLocalHost();
+
+        // IllegalStateException
+        MembershipKey key;
+        key = dc.join(group, nif);
+        try {
+            dc.join(group, nif, thisHost);
+            throw new RuntimeException("IllegalStateException not thrown");
+        } catch (IllegalStateException x) {
+        } catch (UnsupportedOperationException x) {
+        }
+        key.drop();
+        try {
+            key = dc.join(group, nif, thisHost);
+            try {
+                dc.join(group, nif);
+                throw new RuntimeException("IllegalStateException not thrown");
+            } catch (IllegalStateException x) {
+            }
+            key.drop();
+        } catch (UnsupportedOperationException x) {
+        }
+
+        // IllegalArgumentException
+        try {
+            dc.join(notGroup, nif);
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException x) {
+        }
+        try {
+            dc.join(notGroup, nif, thisHost);
+            throw new RuntimeException("IllegalArgumentException not thrown");
+        } catch (IllegalArgumentException x) {
+        } catch (UnsupportedOperationException x) {
+        }
+
+        // NullPointerException
+        try {
+            dc.join(null, nif);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            dc.join(group, null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            dc.join(group, nif, null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        } catch (UnsupportedOperationException x) {
+        }
+
+        dc.close();
+
+        // ClosedChannelException
+        try {
+            dc.join(group, nif);
+            throw new RuntimeException("ClosedChannelException not thrown");
+        } catch (ClosedChannelException x) {
+        }
+        try {
+            dc.join(group, nif, thisHost);
+            throw new RuntimeException("ClosedChannelException not thrown");
+        } catch (ClosedChannelException x) {
+        } catch (UnsupportedOperationException x) {
+        }
+    }
+
+
+    /**
+     * Probe interfaces to get interfaces that support IPv4 or IPv6 multicasting
+     * and invoke tests.
+     */
+    public static void main(String[] args) throws IOException {
+
+        // multicast groups used for the test
+        InetAddress ip4Group = InetAddress.getByName("225.4.5.6");
+        InetAddress ip6Group = InetAddress.getByName("ff02::a");
+
+
+        NetworkConfiguration config = NetworkConfiguration.probe();
+
+        NetworkInterface nif = config.ip4Interfaces().iterator().next();
+        InetAddress anySource = config.ip4Addresses(nif).iterator().next();
+        membershipKeyTests(nif, ip4Group, anySource);
+        exceptionTests(nif);
+
+        // re-run the membership key tests with IPv6 if available
+
+        Iterator<NetworkInterface> iter = config.ip6Interfaces().iterator();
+        if (iter.hasNext()) {
+            nif = iter.next();
+            anySource = config.ip6Addresses(nif).iterator().next();
+            membershipKeyTests(nif, ip6Group, anySource);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2007-2008 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 4527345
+ * @summary Unit test for DatagramChannel's multicast support
+ * @build MulticastSendReceiveTests NetworkConfiguration
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+import java.io.IOException;
+
+public class MulticastSendReceiveTests {
+
+    static Random rand = new Random();
+
+    /**
+     * Send datagram from given local address to given multicast
+     * group.
+     */
+    static int sendDatagram(InetAddress local,
+                            NetworkInterface nif,
+                            InetAddress group,
+                            int port)
+        throws IOException
+    {
+        ProtocolFamily family = (group instanceof Inet6Address) ?
+            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+        DatagramChannel dc = DatagramChannel.open(family)
+            .bind(new InetSocketAddress(local, 0))
+            .setOption(StandardSocketOption.IP_MULTICAST_IF, nif);
+        int id = rand.nextInt();
+        byte[] msg = Integer.toString(id).getBytes("UTF-8");
+        ByteBuffer buf = ByteBuffer.wrap(msg);
+        System.out.format("Send message from %s -> group %s (id=0x%x)\n",
+            local.getHostAddress(), group.getHostAddress(), id);
+        dc.send(buf, new InetSocketAddress(group, port));
+        dc.close();
+        return id;
+    }
+
+    /**
+     * Wait (with timeout) for datagram.
+     *
+     * @param   expectedSender - expected sender address, or
+     *                           null if no datagram expected
+     * @param   id - expected id of datagram
+     */
+    static void receiveDatagram(DatagramChannel dc,
+                                InetAddress expectedSender,
+                                int id)
+        throws IOException
+    {
+        Selector sel = Selector.open();
+        dc.configureBlocking(false);
+        dc.register(sel, SelectionKey.OP_READ);
+        ByteBuffer buf = ByteBuffer.allocateDirect(100);
+
+        try {
+            for (;;) {
+                System.out.println("Waiting to receive message");
+                sel.select(5*1000);
+                SocketAddress sa = dc.receive(buf);
+
+                // no datagram received
+                if (sa == null) {
+                    if (expectedSender != null) {
+                        throw new RuntimeException("Expected message not recieved");
+                    }
+                    System.out.println("No message received (correct)");
+                    return;
+                }
+
+                // datagram received
+
+                InetAddress sender = ((InetSocketAddress)sa).getAddress();
+                buf.flip();
+                byte[] bytes = new byte[buf.remaining()];
+                buf.get(bytes);
+                int receivedId = Integer.parseInt(new String(bytes));
+
+                System.out.format("Received message from %s (id=0x%x)\n",
+                    sender, receivedId);
+
+                if (expectedSender == null) {
+                    if (receivedId == id)
+                        throw new RuntimeException("Message not expected");
+                    System.out.println("Message ignored (has wrong id)");
+                } else {
+                    if (sender.equals(expectedSender)) {
+                        System.out.println("Message expected");
+                        return;
+                    }
+                    System.out.println("Message ignored (wrong sender)");
+                }
+
+                sel.selectedKeys().clear();
+                buf.rewind();
+            }
+        } finally {
+            sel.close();
+        }
+    }
+
+
+    /**
+     * Exercise multicast send/receive on given group/interface
+     */
+    static void test(NetworkInterface nif, InetAddress group, InetAddress source)
+        throws IOException
+    {
+        ProtocolFamily family = (group instanceof Inet6Address) ?
+            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+        System.out.format("create channel to %s socket\n", family.name());
+        DatagramChannel dc = DatagramChannel.open(family)
+            .setOption(StandardSocketOption.SO_REUSEADDR, true)
+            .bind(new InetSocketAddress(0));
+
+        // join group
+        System.out.format("join %s @ %s\n", group.getHostAddress(),
+            nif.getName());
+        MembershipKey key = dc.join(group, nif);
+
+        // send message to group
+        int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
+        int id = sendDatagram(source, nif, group, port);
+
+        // receive message and check id matches
+        receiveDatagram(dc, source, id);
+
+        // exclude-mode filtering
+
+        try {
+            System.out.format("block %s\n", source.getHostAddress());
+
+            // may throw UOE
+            key.block(source);
+            id = sendDatagram(source, nif, group, port);
+            receiveDatagram(dc, null, id);
+
+            // unblock source, send message, message should be received
+            System.out.format("unblock %s\n", source.getHostAddress());
+            key.unblock(source);
+            id = sendDatagram(source, nif, group, port);
+            receiveDatagram(dc, source, id);
+        } catch (UnsupportedOperationException x) {
+            System.out.println("Exclude-mode filtering not supported!");
+        }
+
+        key.drop();
+
+        // include-mode filtering
+
+        InetAddress bogus = (group instanceof Inet6Address) ?
+            InetAddress.getByName("fe80::1234") :
+            InetAddress.getByName("1.2.3.4");
+        System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
+            nif.getName(), bogus.getHostAddress());
+        try {
+            // may throw UOE
+            key = dc.join(group, nif, bogus);
+
+            id = sendDatagram(source, nif, group, port);
+            receiveDatagram(dc, null, id);
+
+            System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
+                nif.getName(), source.getHostAddress());
+            key = dc.join(group, nif, source);
+
+            id = sendDatagram(source, nif, group, port);
+            receiveDatagram(dc, source, id);
+        } catch (UnsupportedOperationException x) {
+            System.out.println("Include-mode filtering not supported!");
+        }
+
+        // done
+        dc.close();
+    }
+
+    public static void main(String[] args) throws IOException {
+        NetworkConfiguration config = NetworkConfiguration.probe();
+
+        // multicast groups used for the test
+        InetAddress ip4Group = InetAddress.getByName("225.4.5.6");
+        InetAddress ip6Group = InetAddress.getByName("ff02::a");
+
+        for (NetworkInterface nif: config.ip4Interfaces()) {
+            InetAddress source = config.ip4Addresses(nif).iterator().next();
+            test(nif, ip4Group, source);
+        }
+
+        for (NetworkInterface nif: config.ip6Interfaces()) {
+            InetAddress source = config.ip6Addresses(nif).iterator().next();
+            test(nif, ip6Group, source);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2007-2008 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.util.*;
+import java.io.IOException;
+
+/**
+ * Helper class for multicasting tests.
+ */
+
+class NetworkConfiguration {
+
+    private Map<NetworkInterface,List<InetAddress>> ip4Interfaces;
+    private Map<NetworkInterface,List<InetAddress>> ip6Interfaces;
+
+    private NetworkConfiguration(Map<NetworkInterface,List<InetAddress>> ip4Interfaces,
+                                 Map<NetworkInterface,List<InetAddress>> ip6Interfaces)
+    {
+        this.ip4Interfaces = ip4Interfaces;
+        this.ip6Interfaces = ip6Interfaces;
+    }
+
+    Iterable<NetworkInterface> ip4Interfaces() {
+        return ip4Interfaces.keySet();
+    }
+
+    Iterable<NetworkInterface> ip6Interfaces() {
+        return ip6Interfaces.keySet();
+    }
+
+    Iterable<InetAddress> ip4Addresses(NetworkInterface nif) {
+        return ip4Interfaces.get(nif);
+    }
+
+    Iterable<InetAddress> ip6Addresses(NetworkInterface nif) {
+        return ip6Interfaces.get(nif);
+    }
+
+    static NetworkConfiguration probe() throws IOException {
+        Map<NetworkInterface,List<InetAddress>> ip4Interfaces =
+            new HashMap<NetworkInterface,List<InetAddress>>();
+        Map<NetworkInterface,List<InetAddress>> ip6Interfaces =
+            new HashMap<NetworkInterface,List<InetAddress>>();
+
+        // find the interfaces that support IPv4 and IPv6
+        List<NetworkInterface> nifs = Collections
+            .list(NetworkInterface.getNetworkInterfaces());
+        for (NetworkInterface nif: nifs) {
+            // ignore intertaces that are down or don't support multicast
+            if (!nif.isUp() || !nif.supportsMulticast() || nif.isLoopback())
+                continue;
+
+            List<InetAddress> addrs = Collections.list(nif.getInetAddresses());
+            for (InetAddress addr: addrs) {
+                if (addr instanceof Inet4Address) {
+                    List<InetAddress> list = ip4Interfaces.get(nif);
+                    if (list == null) {
+                        list = new LinkedList<InetAddress>();
+                    }
+                    list.add(addr);
+                    ip4Interfaces.put(nif, list);
+                }
+                if (addr instanceof Inet6Address) {
+                    List<InetAddress> list = ip6Interfaces.get(nif);
+                    if (list == null) {
+                        list = new LinkedList<InetAddress>();
+                    }
+                    list.add(addr);
+                    ip6Interfaces.put(nif, list);
+
+                }
+            }
+        }
+        return new NetworkConfiguration(ip4Interfaces, ip6Interfaces);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2007-2008 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 4640544
+ * @summary Unit test for setOption/getOption/options methods
+ */
+
+import java.nio.*;
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+import static java.net.StandardSocketOption.*;
+
+public class SocketOptionTests {
+
+    static <T> void checkOption(DatagramChannel dc,
+                                SocketOption<T> name,
+                                T expectedValue)
+        throws IOException
+    {
+        T value = dc.getOption(name);
+        if (!value.equals(expectedValue))
+            throw new RuntimeException("value not as expected");
+    }
+
+    public static void main(String[] args) throws IOException {
+        DatagramChannel dc = DatagramChannel.open();
+
+        // check supported options
+        Set<SocketOption<?>> options = dc.options();
+        List<? extends SocketOption<?>> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
+            SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL,
+            IP_MULTICAST_LOOP);
+        for (SocketOption opt: expected) {
+            if (!options.contains(opt))
+                throw new RuntimeException(opt.name() + " should be supported");
+        }
+
+        // check specified defaults
+        checkOption(dc, SO_BROADCAST, false);
+        checkOption(dc, IP_MULTICAST_TTL, 1);           // true on supported platforms
+        checkOption(dc, IP_MULTICAST_LOOP, true);       // true on supported platforms
+
+        // allowed to change when not bound
+        dc.setOption(SO_BROADCAST, true);
+        checkOption(dc, SO_BROADCAST, true);
+        dc.setOption(SO_BROADCAST, false);
+        checkOption(dc, SO_BROADCAST, false);
+        dc.setOption(SO_SNDBUF, 16*1024);       // can't check
+        dc.setOption(SO_RCVBUF, 16*1024);       // can't check
+        dc.setOption(SO_REUSEADDR, true);
+        checkOption(dc, SO_REUSEADDR, true);
+        dc.setOption(SO_REUSEADDR, false);
+        checkOption(dc, SO_REUSEADDR, false);
+
+        // bind socket
+        dc.bind(new InetSocketAddress(0));
+
+        // allow to change when bound
+        dc.setOption(SO_BROADCAST, true);
+        checkOption(dc, SO_BROADCAST, true);
+        dc.setOption(SO_BROADCAST, false);
+        checkOption(dc, SO_BROADCAST, false);
+        dc.setOption(IP_TOS, 0x08);     // can't check
+        dc.setOption(IP_MULTICAST_TTL, 2);
+        checkOption(dc, IP_MULTICAST_TTL, 2);
+        dc.setOption(IP_MULTICAST_LOOP, false);
+        checkOption(dc, IP_MULTICAST_LOOP, false);
+        dc.setOption(IP_MULTICAST_LOOP, true);
+        checkOption(dc, IP_MULTICAST_LOOP, true);
+
+
+        // NullPointerException
+        try {
+            dc.setOption(null, "value");
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            dc.getOption(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+
+        // ClosedChannelException
+        dc.close();
+        try {
+            dc.setOption(IP_MULTICAST_LOOP, true);
+            throw new RuntimeException("ClosedChannelException not thrown");
+        } catch (ClosedChannelException x) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2007-2008 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 4640544
+ * @summary Unit test for ServerSocketChannel setOption/getOption/options
+ *          methods.
+ */
+
+import java.nio.*;
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+import static java.net.StandardSocketOption.*;
+
+public class SocketOptionTests {
+
+    static void checkOption(ServerSocketChannel ssc, SocketOption name, Object expectedValue)
+        throws IOException
+    {
+        Object value = ssc.getOption(name);
+        if (!value.equals(expectedValue))
+            throw new RuntimeException("value not as expected");
+    }
+
+    public static void main(String[] args) throws IOException {
+        ServerSocketChannel ssc = ServerSocketChannel.open();
+
+        // check supported options
+        Set<SocketOption<?>> options = ssc.options();
+        if (!options.contains(SO_REUSEADDR))
+            throw new RuntimeException("SO_REUSEADDR should be supported");
+        if (!options.contains(SO_RCVBUF))
+            throw new RuntimeException("SO_RCVBUF should be supported");
+
+        // allowed to change when not bound
+        ssc.setOption(SO_RCVBUF, 256*1024);     // can't check
+        ssc.setOption(SO_REUSEADDR, true);
+        checkOption(ssc, SO_REUSEADDR, true);
+        ssc.setOption(SO_REUSEADDR, false);
+        checkOption(ssc, SO_REUSEADDR, false);
+
+        // NullPointerException
+        try {
+            ssc.setOption(null, "value");
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            ssc.getOption(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+
+        // ClosedChannelException
+        ssc.close();
+        try {
+            ssc.setOption(SO_REUSEADDR, true);
+            throw new RuntimeException("ClosedChannelException not thrown");
+        } catch (ClosedChannelException x) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/SocketChannel/SocketOptionTests.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007-2008 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 4640544
+ * @summary Unit test to check SocketChannel setOption/getOption/options
+ *          methods.
+ */
+
+import java.nio.*;
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+import static java.net.StandardSocketOption.*;
+
+public class SocketOptionTests {
+
+    static void checkOption(SocketChannel sc, SocketOption name, Object expectedValue)
+        throws IOException
+    {
+        Object value = sc.getOption(name);
+        if (!value.equals(expectedValue))
+            throw new RuntimeException("value not as expected");
+    }
+
+    public static void main(String[] args) throws IOException {
+        SocketChannel sc = SocketChannel.open();
+
+        // check supported options
+        Set<SocketOption<?>> options = sc.options();
+        List<? extends SocketOption> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
+            SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, TCP_NODELAY);
+        for (SocketOption opt: expected) {
+            if (!options.contains(opt))
+                throw new RuntimeException(opt.name() + " should be supported");
+        }
+
+        // check specified defaults
+        int linger = sc.<Integer>getOption(SO_LINGER);
+        if (linger >= 0)
+            throw new RuntimeException("initial value of SO_LINGER should be < 0");
+        checkOption(sc, SO_KEEPALIVE, false);
+        checkOption(sc, TCP_NODELAY, false);
+
+        // allowed to change when not bound
+        sc.setOption(SO_KEEPALIVE, true);
+        checkOption(sc, SO_KEEPALIVE, true);
+        sc.setOption(SO_KEEPALIVE, false);
+        checkOption(sc, SO_KEEPALIVE, false);
+        sc.setOption(SO_SNDBUF, 128*1024);      // can't check
+        sc.setOption(SO_RCVBUF, 256*1024);      // can't check
+        sc.setOption(SO_REUSEADDR, true);
+        checkOption(sc, SO_REUSEADDR, true);
+        sc.setOption(SO_REUSEADDR, false);
+        checkOption(sc, SO_REUSEADDR, false);
+        sc.setOption(SO_LINGER, 10);
+        linger = sc.<Integer>getOption(SO_LINGER);
+        if (linger < 1)
+            throw new RuntimeException("expected linger to be enabled");
+        sc.setOption(SO_LINGER, -1);
+        linger = sc.<Integer>getOption(SO_LINGER);
+        if (linger >= 0)
+            throw new RuntimeException("expected linger to be disabled");
+        sc.setOption(TCP_NODELAY, true);
+        checkOption(sc, TCP_NODELAY, true);
+        sc.setOption(TCP_NODELAY, false);       // can't check
+
+        // bind socket
+        sc.bind(new InetSocketAddress(0));
+
+        // allow to change when bound
+        sc.setOption(SO_KEEPALIVE, true);
+        checkOption(sc, SO_KEEPALIVE, true);
+        sc.setOption(SO_KEEPALIVE, false);
+        checkOption(sc, SO_KEEPALIVE, false);
+
+        sc.setOption(SO_LINGER, 10);
+        linger = sc.<Integer>getOption(SO_LINGER);
+        if (linger < 1)
+            throw new RuntimeException("expected linger to be enabled");
+        sc.setOption(SO_LINGER, -1);
+        linger = sc.<Integer>getOption(SO_LINGER);
+        if (linger >= 0)
+            throw new RuntimeException("expected linger to be disabled");
+        sc.setOption(TCP_NODELAY, true);        // can't check
+        sc.setOption(TCP_NODELAY, false);       // can't check
+
+        // NullPointerException
+        try {
+            sc.setOption(null, "value");
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            sc.getOption(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+
+        // ClosedChannelException
+        sc.close();
+        try {
+            sc.setOption(TCP_NODELAY, true);
+            throw new RuntimeException("ClosedChannelException not thrown");
+        } catch (ClosedChannelException x) {
+        }
+    }
+}
--- a/test/java/nio/channels/TestUtil.java	Sun Aug 31 18:32:59 2008 +0100
+++ b/test/java/nio/channels/TestUtil.java	Sun Aug 31 18:39:01 2008 +0100
@@ -38,7 +38,7 @@
     // executing in a different network.
     public static final String HOST = "javaweb.sfbay.sun.com";
     public static final String REFUSING_HOST = "jano1.sfbay.sun.com";
-    public static final String FAR_HOST = "theclub.ireland.sun.com";
+    public static final String FAR_HOST = "irejano.ireland.sun.com";
     public static final String UNRESOLVABLE_HOST = "blah-blah.blah-blah.blah";
 
     private TestUtil() { }
@@ -102,5 +102,4 @@
     static boolean onWindows() {
         return osName.startsWith("Windows");
     }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/etc/NetworkChannelTests.java	Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2007-2008 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 4640544
+ * @summary Unit test for channels that implement NetworkChannel
+ */
+
+import java.nio.*;
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+
+public class NetworkChannelTests {
+
+    static interface ChannelFactory {
+        NetworkChannel open() throws IOException;
+    }
+
+    static class BogusSocketAddress extends SocketAddress {
+    }
+
+    /**
+     * Exercise bind method.
+     */
+    static void bindTests(ChannelFactory factory) throws IOException {
+        NetworkChannel ch;
+
+        // AlreadyBoundException
+        ch = factory.open().bind(new InetSocketAddress(0));
+        try {
+            ch.bind(new InetSocketAddress(0));
+            throw new RuntimeException("AlreadyBoundException not thrown");
+        } catch (AlreadyBoundException x) {
+        }
+        ch.close();
+
+        // bind(null)
+        ch = factory.open().bind(null);
+        if (ch.getLocalAddress() == null)
+            throw new RuntimeException("socket not found");
+        ch.close();
+
+        // UnsupportedAddressTypeException
+        ch = factory.open();
+        try {
+            ch.bind(new BogusSocketAddress());
+            throw new RuntimeException("UnsupportedAddressTypeException not thrown");
+        } catch (UnsupportedAddressTypeException x) {
+        }
+        ch.close();
+
+        // ClosedChannelException
+        try {
+            ch.bind(new InetSocketAddress(0));
+            throw new RuntimeException("ClosedChannelException not thrown");
+        } catch (ClosedChannelException x) {
+        }
+    }
+
+    /**
+     * Exercise getLocalAddress method.
+     */
+    static void localAddressTests(ChannelFactory factory) throws IOException {
+        NetworkChannel ch;
+
+        // not bound
+        ch = factory.open();
+        if (ch.getLocalAddress() != null) {
+            throw new RuntimeException("Local address returned when not bound");
+        }
+
+        // bound
+        InetSocketAddress local =
+            (InetSocketAddress)(ch.bind(new InetSocketAddress(0)).getLocalAddress());
+        if (!local.getAddress().isAnyLocalAddress()) {
+            if (NetworkInterface.getByInetAddress(local.getAddress()) == null)
+                throw new RuntimeException("not bound to local address");
+        }
+        if (local.getPort() <= 0)
+            throw new RuntimeException("not bound to local port");
+
+        // closed
+        ch.close();
+        if (ch.getLocalAddress() != null) {
+            throw new RuntimeException("Local address return when closed");
+        }
+    }
+
+    /**
+     * Exercise getConnectedAddress method (SocketChannel only)
+     */
+    static void connectedAddressTests() throws IOException {
+        ServerSocketChannel ssc = ServerSocketChannel.open()
+            .bind(new InetSocketAddress(0));
+        InetSocketAddress local = (InetSocketAddress)(ssc.getLocalAddress());
+        int port = local.getPort();
+        InetSocketAddress server = new InetSocketAddress(InetAddress.getLocalHost(), port);
+
+        SocketChannel sc = SocketChannel.open();
+
+        // not connected
+        if (sc.getConnectedAddress() != null)
+            throw new RuntimeException("getConnectedAddress returned address when not connected");
+
+        // connected
+        sc.connect(server);
+        SocketAddress remote = sc.getConnectedAddress();
+        if (!remote.equals(server))
+            throw new RuntimeException("getConnectedAddress returned incorrect address");
+
+        // closed
+        sc.close();
+        if (sc.getConnectedAddress() != null)
+            throw new RuntimeException("getConnectedAddress returned address when closed");
+
+        ssc.close();
+    }
+
+    public static void main(String[] args) throws IOException {
+        ChannelFactory factory;
+
+        // -- SocketChannel --
+
+        factory = new ChannelFactory() {
+            public NetworkChannel open() throws IOException {
+                return SocketChannel.open();
+            }
+        };
+
+        bindTests(factory);
+        localAddressTests(factory);
+        connectedAddressTests();
+
+        // -- ServerSocketChannel --
+
+        factory = new ChannelFactory() {
+            public NetworkChannel open() throws IOException {
+                return ServerSocketChannel.open();
+            }
+        };
+
+        bindTests(factory);
+        localAddressTests(factory);
+
+        // backlog values
+        ServerSocketChannel.open()
+            .bind(new InetSocketAddress(0), 100).close();
+        ServerSocketChannel.open()
+            .bind(new InetSocketAddress(0), 0).close();
+        ServerSocketChannel.open()
+            .bind(new InetSocketAddress(0), -1).close();
+
+        // -- DatagramChannel --
+
+        factory = new ChannelFactory() {
+            public NetworkChannel open() throws IOException {
+                return DatagramChannel.open();
+            }
+        };
+
+        bindTests(factory);
+        localAddressTests(factory);
+    }
+
+}