aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralanb <none@none>2008-08-31 18:39:01 +0100
committeralanb <none@none>2008-08-31 18:39:01 +0100
commitccd6a54fa454a291cb19aae3036b5b1a0558e5dd (patch)
tree6e18890085a32beb660266b79a81a1ef9c402c48
parenta2d1761569bdf7d0e8fe2e3e1245d2975ec8a2ce (diff)
4640544: New I/O: Complete socket-channel functionality
Reviewed-by: iris, sherman, chegar --HG-- rename : src/share/classes/java/nio/channels/package.html => src/share/classes/java/nio/channels/package-info.java
-rw-r--r--make/java/nio/FILES_java.gmk19
-rw-r--r--make/java/nio/Makefile45
-rw-r--r--make/java/nio/mapfile-linux41
-rw-r--r--make/java/nio/mapfile-solaris41
-rw-r--r--make/mksample/nio/Makefile2
-rw-r--r--make/mksample/nio/multicast/Makefile (renamed from src/share/classes/sun/nio/ch/exceptions)35
-rw-r--r--src/share/classes/java/net/NetworkInterface.java1
-rw-r--r--src/share/classes/java/net/ProtocolFamily.java39
-rw-r--r--src/share/classes/java/net/SocketOption.java55
-rw-r--r--src/share/classes/java/net/StandardProtocolFamily.java45
-rw-r--r--src/share/classes/java/net/StandardSocketOption.java352
-rw-r--r--src/share/classes/java/nio/channels/DatagramChannel.java157
-rw-r--r--src/share/classes/java/nio/channels/MembershipKey.java183
-rw-r--r--src/share/classes/java/nio/channels/MulticastChannel.java211
-rw-r--r--src/share/classes/java/nio/channels/NetworkChannel.java158
-rw-r--r--src/share/classes/java/nio/channels/ServerSocketChannel.java127
-rw-r--r--src/share/classes/java/nio/channels/SocketChannel.java150
-rw-r--r--src/share/classes/java/nio/channels/exceptions11
-rw-r--r--src/share/classes/java/nio/channels/package-info.java231
-rw-r--r--src/share/classes/java/nio/channels/package.html222
-rw-r--r--src/share/classes/java/nio/channels/spi/SelectorProvider.java24
-rw-r--r--src/share/classes/sun/nio/ch/DatagramChannelImpl.java497
-rw-r--r--src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java108
-rw-r--r--src/share/classes/sun/nio/ch/ExtendedSocketOption.java44
-rw-r--r--src/share/classes/sun/nio/ch/MembershipKeyImpl.java222
-rw-r--r--src/share/classes/sun/nio/ch/MembershipRegistry.java129
-rw-r--r--src/share/classes/sun/nio/ch/Net.java370
-rw-r--r--src/share/classes/sun/nio/ch/OptionAdaptor.java229
-rw-r--r--src/share/classes/sun/nio/ch/OptionKey.java48
-rw-r--r--src/share/classes/sun/nio/ch/SelectorProviderImpl.java6
-rw-r--r--src/share/classes/sun/nio/ch/ServerSocketAdaptor.java38
-rw-r--r--src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java102
-rw-r--r--src/share/classes/sun/nio/ch/SocketAdaptor.java126
-rw-r--r--src/share/classes/sun/nio/ch/SocketChannelImpl.java205
-rw-r--r--src/share/classes/sun/nio/ch/SocketOpts.java115
-rw-r--r--src/share/classes/sun/nio/ch/SocketOptsImpl.java318
-rw-r--r--src/share/native/java/net/net_util.c4
-rw-r--r--src/share/native/java/net/net_util.h6
-rw-r--r--src/share/native/sun/nio/ch/genSocketOptionRegistry.c129
-rw-r--r--src/share/sample/nio/multicast/MulticastAddress.java127
-rw-r--r--src/share/sample/nio/multicast/Reader.java142
-rw-r--r--src/share/sample/nio/multicast/Sender.java71
-rw-r--r--src/solaris/native/java/net/net_util_md.c2
-rw-r--r--src/solaris/native/sun/nio/ch/DatagramChannelImpl.c4
-rw-r--r--src/solaris/native/sun/nio/ch/FileKey.c6
-rw-r--r--src/solaris/native/sun/nio/ch/Net.c492
-rw-r--r--src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c8
-rw-r--r--src/solaris/native/sun/nio/ch/SocketChannelImpl.c13
-rw-r--r--src/solaris/native/sun/nio/ch/nio_util.h7
-rw-r--r--src/windows/native/java/net/net_util_md.c2
-rw-r--r--src/windows/native/sun/nio/ch/DatagramChannelImpl.c148
-rw-r--r--src/windows/native/sun/nio/ch/Net.c394
-rw-r--r--src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c26
-rw-r--r--src/windows/native/sun/nio/ch/SocketChannelImpl.c9
-rw-r--r--test/java/nio/channels/DatagramChannel/BasicMulticastTests.java220
-rw-r--r--test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java220
-rw-r--r--test/java/nio/channels/DatagramChannel/NetworkConfiguration.java97
-rw-r--r--test/java/nio/channels/DatagramChannel/SocketOptionTests.java115
-rw-r--r--test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java84
-rw-r--r--test/java/nio/channels/SocketChannel/SocketOptionTests.java129
-rw-r--r--test/java/nio/channels/TestUtil.java3
-rw-r--r--test/java/nio/channels/etc/NetworkChannelTests.java187
62 files changed, 5728 insertions, 1623 deletions
diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk
index c99f55204..8a6177b0a 100644
--- a/make/java/nio/FILES_java.gmk
+++ b/make/java/nio/FILES_java.gmk
@@ -39,6 +39,9 @@ FILES_src = \
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 @@ FILES_src = \
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 @@ FILES_src = \
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 @@ FILES_src = \
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 @@ FILES_gen_ex = \
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 @@ FILES_gen_ex = \
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)
diff --git a/make/java/nio/Makefile b/make/java/nio/Makefile
index cff9ce5ce..26c2f2fc6 100644
--- a/make/java/nio/Makefile
+++ b/make/java/nio/Makefile
@@ -56,18 +56,18 @@ FILES_java += \
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_java += \
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 @@ $(BUF_GEN)/%Exception.java: genExceptions.sh $(BUF_SRC)/exceptions
@$(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 @@ $(SCS_GEN)/StandardCharsets.java: genCharsetProvider.sh \
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
diff --git a/make/java/nio/mapfile-linux b/make/java/nio/mapfile-linux
index 2eba69d17..3fb47b0eb 100644
--- a/make/java/nio/mapfile-linux
+++ b/make/java/nio/mapfile-linux
@@ -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 @@ SUNWprivate_1.1 {
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:
*;
diff --git a/make/java/nio/mapfile-solaris b/make/java/nio/mapfile-solaris
index 77ef8ea2a..6e109e2fa 100644
--- a/make/java/nio/mapfile-solaris
+++ b/make/java/nio/mapfile-solaris
@@ -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 @@ SUNWprivate_1.1 {
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:
*;
diff --git a/make/mksample/nio/Makefile b/make/mksample/nio/Makefile
index a6e8fc46d..1f17a4cce 100644
--- a/make/mksample/nio/Makefile
+++ b/make/mksample/nio/Makefile
@@ -31,7 +31,7 @@ BUILDDIR = ../..
PRODUCT = java
include $(BUILDDIR)/common/Defs.gmk
-SUBDIRS = server
+SUBDIRS = multicast server
all build clean clobber::
$(SUBDIRS-loop)
diff --git a/src/share/classes/sun/nio/ch/exceptions b/make/mksample/nio/multicast/Makefile
index 55d295f87..05a153a13 100644
--- a/src/share/classes/sun/nio/ch/exceptions
+++ b/make/mksample/nio/multicast/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
+# 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
@@ -23,17 +23,30 @@
# have any questions.
#
-# Generated exception classes for sun.nio.ch
+#
+# 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
-SINCE=1.4
-PACKAGE=sun.nio.ch
-# This year should only change if the generated source is modified.
-COPYRIGHT_YEARS=2000-2007
+all build: $(SAMPLE_FILES)
+$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/%
+ $(install-file)
-SUPER=IllegalStateException
+clean clobber:
+ $(RM) -r $(SAMPLE_DST_DIR)
-gen AlreadyBoundException "
- * Unchecked exception thrown when an attempt is made to bind a {@link
- * SocketChannel} that is already bound." \
- 9002280723481772026L
+.PHONY: all build clean clobber
diff --git a/src/share/classes/java/net/NetworkInterface.java b/src/share/classes/java/net/NetworkInterface.java
index a4f4bc9c6..da9503d57 100644
--- a/src/share/classes/java/net/NetworkInterface.java
+++ b/src/share/classes/java/net/NetworkInterface.java
@@ -25,7 +25,6 @@
package java.net;
-import java.net.SocketException;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import sun.security.action.*;
diff --git a/src/share/classes/java/net/ProtocolFamily.java b/src/share/classes/java/net/ProtocolFamily.java
new file mode 100644
index 000000000..b997c7bb0
--- /dev/null
+++ b/src/share/classes/java/net/ProtocolFamily.java
@@ -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();
+}
diff --git a/src/share/classes/java/net/SocketOption.java b/src/share/classes/java/net/SocketOption.java
new file mode 100644
index 000000000..afc9714b5
--- /dev/null
+++ b/src/share/classes/java/net/SocketOption.java
@@ -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();
+}
diff --git a/src/share/classes/java/net/StandardProtocolFamily.java b/src/share/classes/java/net/StandardProtocolFamily.java
new file mode 100644
index 000000000..7c11b32f5
--- /dev/null
+++ b/src/share/classes/java/net/StandardProtocolFamily.java
@@ -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
+}
diff --git a/src/share/classes/java/net/StandardSocketOption.java b/src/share/classes/java/net/StandardSocketOption.java
new file mode 100644
index 000000000..405038cc1
--- /dev/null
+++ b/src/share/classes/java/net/StandardSocketOption.java
@@ -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; }
+ }
+}
diff --git a/src/share/classes/java/nio/channels/DatagramChannel.java b/src/share/classes/java/nio/channels/DatagramChannel.java
index 744495c55..f04b1b000 100644
--- a/src/share/classes/java/nio/channels/DatagramChannel.java
+++ b/src/share/classes/java/nio/channels/DatagramChannel.java
@@ -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 @@ import java.nio.channels.spi.*;
* 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 @@ import java.nio.channels.spi.*;
public abstract class DatagramChannel
extends AbstractSelectableChannel
- implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
+ implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
{
/**
@@ -88,7 +127,13 @@ public abstract class DatagramChannel
* 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 @@ public abstract class DatagramChannel
}
/**
+ * 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 @@ public abstract class DatagramChannel
// -- 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 class DatagramChannel
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 class DatagramChannel
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
diff --git a/src/share/classes/java/nio/channels/MembershipKey.java b/src/share/classes/java/nio/channels/MembershipKey.java
new file mode 100644
index 000000000..0d2fc52bc
--- /dev/null
+++ b/src/share/classes/java/nio/channels/MembershipKey.java
@@ -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();
+}
diff --git a/src/share/classes/java/nio/channels/MulticastChannel.java b/src/share/classes/java/nio/channels/MulticastChannel.java
new file mode 100644
index 000000000..440dd2a8b
--- /dev/null
+++ b/src/share/classes/java/nio/channels/MulticastChannel.java
@@ -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;
+}
diff --git a/src/share/classes/java/nio/channels/NetworkChannel.java b/src/share/classes/java/nio/channels/NetworkChannel.java
new file mode 100644
index 000000000..fae642fcb
--- /dev/null
+++ b/src/share/classes/java/nio/channels/NetworkChannel.java
@@ -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();
+}
diff --git a/src/share/classes/java/nio/channels/ServerSocketChannel.java b/src/share/classes/java/nio/channels/ServerSocketChannel.java
index 0ffed003a..578646f30 100644
--- a/src/share/classes/java/nio/channels/ServerSocketChannel.java
+++ b/src/share/classes/java/nio/channels/ServerSocketChannel.java
@@ -27,33 +27,44 @@ package java.nio.channels;
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. 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.
+ * 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> 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 @@ import java.nio.channels.spi.*;
public abstract class ServerSocketChannel
extends AbstractSelectableChannel
+ implements NetworkChannel
{
/**
@@ -110,6 +122,89 @@ public abstract class ServerSocketChannel
// -- 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
diff --git a/src/share/classes/java/nio/channels/SocketChannel.java b/src/share/classes/java/nio/channels/SocketChannel.java
index 826699422..ccc6342a7 100644
--- a/src/share/classes/java/nio/channels/SocketChannel.java
+++ b/src/share/classes/java/nio/channels/SocketChannel.java
@@ -27,24 +27,17 @@ package java.nio.channels;
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 @@ import java.nio.channels.spi.*;
* 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 @@ import java.nio.channels.spi.*;
* 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 @@ import java.nio.channels.spi.*;
* 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 @@ import java.nio.channels.spi.*;
public abstract class SocketChannel
extends AbstractSelectableChannel
- implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
+ implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
{
/**
@@ -192,6 +211,73 @@ public abstract class SocketChannel
// -- 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 class SocketChannel
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 class SocketChannel
*/
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 --
diff --git a/src/share/classes/java/nio/channels/exceptions b/src/share/classes/java/nio/channels/exceptions
index ae4d4c0d9..dd6e4357f 100644
--- a/src/share/classes/java/nio/channels/exceptions
+++ b/src/share/classes/java/nio/channels/exceptions
@@ -146,3 +146,14 @@ gen OverlappingFileLockException "
* 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
+
diff --git a/src/share/classes/java/nio/channels/package-info.java b/src/share/classes/java/nio/channels/package-info.java
new file mode 100644
index 000000000..fd4d50369
--- /dev/null
+++ b/src/share/classes/java/nio/channels/package-info.java
@@ -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;
diff --git a/src/share/classes/java/nio/channels/package.html b/src/share/classes/java/nio/channels/package.html
deleted file mode 100644
index 151378f78..000000000
--- a/src/share/classes/java/nio/channels/package.html
+++ /dev/null
@@ -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>
diff --git a/src/share/classes/java/nio/channels/spi/SelectorProvider.java b/src/share/classes/java/nio/channels/spi/SelectorProvider.java
index 9a8a3cc70..dc61c9c27 100644
--- a/src/share/classes/java/nio/channels/spi/SelectorProvider.java
+++ b/src/share/classes/java/nio/channels/spi/SelectorProvider.java
@@ -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 @@ public abstract class SelectorProvider {
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
*/
diff --git a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
index 029ab3e11..a7939c0ce 100644
--- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
@@ -31,7 +31,7 @@ import java.net.*;
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
// 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 @@ class DatagramChannelImpl
// 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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
}
}
+ @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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
}
}
- 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 @@ class DatagramChannelImpl
}
public DatagramChannel connect(SocketAddress sa) throws IOException {
- int trafficClass = 0;
int localPort = 0;
synchronized(readLock) {
@@ -545,10 +709,10 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 @@ class DatagramChannelImpl
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 {
diff --git a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java
index 79a0d41b4..34b24225a 100644
--- a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java
+++ b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java
@@ -45,16 +45,9 @@ public class DatagramSocketAdaptor
// 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 @@ public class DatagramSocketAdaptor
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 class DatagramSocketAdaptor
}
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 @@ public class DatagramSocketAdaptor
// 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 class DatagramSocketAdaptor
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 @@ public class DatagramSocketAdaptor
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() {
diff --git a/src/share/classes/sun/nio/ch/ExtendedSocketOption.java b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java
new file mode 100644
index 000000000..86e787ef8
--- /dev/null
+++ b/src/share/classes/sun/nio/ch/ExtendedSocketOption.java
@@ -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(); }
+ };
+}
diff --git a/src/share/classes/sun/nio/ch/MembershipKeyImpl.java b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java
new file mode 100644
index 000000000..687f79c00
--- /dev/null
+++ b/src/share/classes/sun/nio/ch/MembershipKeyImpl.java
@@ -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();
+ }
+}
diff --git a/src/share/classes/sun/nio/ch/MembershipRegistry.java b/src/share/classes/sun/nio/ch/MembershipRegistry.java
new file mode 100644
index 000000000..5a2a8ef74
--- /dev/null
+++ b/src/share/classes/sun/nio/ch/MembershipRegistry.java
@@ -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();
+ }
+ }
+ }
+}
diff --git a/src/share/classes/sun/nio/ch/Net.java b/src/share/classes/sun/nio/ch/Net.java
index 295e4f5c4..98b4615ab 100644
--- a/src/share/classes/sun/nio/ch/Net.java
+++ b/src/share/classes/sun/nio/ch/Net.java
@@ -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 @@ class Net { // package-private
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 @@ class Net { // package-private
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 void bind(FileDescriptor fd, InetAddress addr, int port)
+ throws IOException
+ {
+ bind(UNSPEC, fd, addr, port);
+ }
- static native void bind(FileDescriptor fd, InetAddress addr, int 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, boolean mayNeedConversion,
+ int level, int opt)
+ throws IOException;
+
+ 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 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 int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source)
+ throws IOException;
+
+ /**
+ * Block IPv4 source
+ */
+ static int block4(FileDescriptor fd, int group, int interf, int source)
+ throws IOException
+ {
+ 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 getIntOption0(FileDescriptor fd, int opt)
+ private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group,
+ int interf, int source)
throws IOException;
- static int getIntOption(FileDescriptor fd, int opt)
+ /**
+ * Join IPv6 multicast group
+ */
+ static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException
{
- return getIntOption0(fd, opt);
+ 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 void setIntOption0(FileDescriptor fd,
- int opt, int arg)
+ private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
throws IOException;
- static void setIntOption(FileDescriptor fd, int opt, int arg)
+ /**
+ * 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
{
- setIntOption0(fd, opt, arg);
+ 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 {
diff --git a/src/share/classes/sun/nio/ch/OptionAdaptor.java b/src/share/classes/sun/nio/ch/OptionAdaptor.java
deleted file mode 100644
index 95a271176..000000000
--- a/src/share/classes/sun/nio/ch/OptionAdaptor.java
+++ /dev/null
@@ -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
- }
- }
-
-}
diff --git a/src/share/classes/sun/nio/ch/OptionKey.java b/src/share/classes/sun/nio/ch/OptionKey.java
new file mode 100644
index 000000000..70ba8a6fa
--- /dev/null
+++ b/src/share/classes/sun/nio/ch/OptionKey.java
@@ -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;
+ }
+}
diff --git a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java
index 367785564..7a8771361 100644
--- a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java
+++ b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java
@@ -29,6 +29,7 @@ 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.nio.channels.spi.*;
@@ -41,6 +42,10 @@ public abstract class SelectorProviderImpl
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 abstract class SelectorProviderImpl
public SocketChannel openSocketChannel() throws IOException {
return new SocketChannelImpl(this);
}
-
}
diff --git a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java
index 1077ae4bd..ccf8e03d5 100644
--- a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java
+++ b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java
@@ -44,9 +44,6 @@ public class ServerSocketAdaptor // package-private
// 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 @@ public class ServerSocketAdaptor // package-private
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 class ServerSocketAdaptor // package-private
}
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
+ }
}
}
diff --git a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
index 7f91cf3b8..cf4e11dde 100644
--- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
@@ -33,8 +33,7 @@ import java.nio.channels.*;
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 @@ class ServerSocketChannelImpl
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 @@ class ServerSocketChannelImpl
localAddress = Net.localAddress(fd);
}
-
public ServerSocket socket() {
synchronized (stateLock) {
if (socket == null)
@@ -112,6 +107,69 @@ class ServerSocketChannelImpl
}
}
+ @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 @@ class ServerSocketChannelImpl
}
}
- 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 @@ class ServerSocketChannelImpl
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 @@ class ServerSocketChannelImpl
// -- 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
diff --git a/src/share/classes/sun/nio/ch/SocketAdaptor.java b/src/share/classes/sun/nio/ch/SocketAdaptor.java
index dbf796203..8d74663bf 100644
--- a/src/share/classes/sun/nio/ch/SocketAdaptor.java
+++ b/src/share/classes/sun/nio/ch/SocketAdaptor.java
@@ -54,16 +54,9 @@ public class SocketAdaptor
// 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 class SocketAdaptor
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 class SocketAdaptor
}
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 @@ public class SocketAdaptor
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 class SocketAdaptor
}
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 class SocketAdaptor
}
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 class SocketAdaptor
}
public boolean isBound() {
- return sc.isBound();
+ return sc.localAddress() != null;
}
public boolean isClosed() {
diff --git a/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/share/classes/sun/nio/ch/SocketChannelImpl.java
index 2c67270aa..4549eacfd 100644
--- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java
+++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java
@@ -31,6 +31,7 @@ import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
+import java.util.*;
/**
@@ -78,19 +79,16 @@ class SocketChannelImpl
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 @@ class SocketChannelImpl
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_CONNECTED;
+ this.localAddress = Net.localAddress(fd);
this.remoteAddress = remote;
}
@@ -125,6 +124,98 @@ class SocketChannelImpl
}
}
+ @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 @@ class SocketChannelImpl
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 @@ class SocketChannelImpl
}
}
- 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 @@ class SocketChannelImpl
}
public boolean connect(SocketAddress sa) throws IOException {
- int trafficClass = 0; // ## Pick up from options
int localPort = 0;
synchronized (readLock) {
@@ -524,13 +585,24 @@ class SocketChannelImpl
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 @@ class SocketChannelImpl
}
}
- 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 @@ class SocketChannelImpl
boolean block, boolean ready)
throws IOException;
- private static native void shutdown(FileDescriptor fd, int how)
- throws IOException;
-
static {
Util.load();
nd = new SocketDispatcher();
diff --git a/src/share/classes/sun/nio/ch/SocketOpts.java b/src/share/classes/sun/nio/ch/SocketOpts.java
deleted file mode 100644
index 52ef58d8d..000000000
--- a/src/share/classes/sun/nio/ch/SocketOpts.java
+++ /dev/null
@@ -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;
-
- }
-
- }
-
-}
diff --git a/src/share/classes/sun/nio/ch/SocketOptsImpl.java b/src/share/classes/sun/nio/ch/SocketOptsImpl.java
deleted file mode 100644
index 183747de1..000000000
--- a/src/share/classes/sun/nio/ch/SocketOptsImpl.java
+++ /dev/null
@@ -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");
- }
-
- }
- }
-
-}
diff --git a/src/share/native/java/net/net_util.c b/src/share/native/java/net/net_util.c
index 2559a0edb..5634e736a 100644
--- a/src/share/native/java/net/net_util.c
+++ b/src/share/native/java/net/net_util.c
@@ -82,7 +82,7 @@ void init(JNIEnv *env) {
}
}
-jobject
+JNIEXPORT jobject JNICALL
NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
jobject iaObj;
init(env);
@@ -159,7 +159,7 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
return iaObj;
}
-jint
+JNIEXPORT jint JNICALL
NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
{
jint family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
diff --git a/src/share/native/java/net/net_util.h b/src/share/native/java/net/net_util.h
index d00a1c0be..9fded2f9c 100644
--- a/src/share/native/java/net/net_util.h
+++ b/src/share/native/java/net/net_util.h
@@ -116,7 +116,7 @@ NET_AllocSockaddr(struct sockaddr **him, int *len);
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 initLocalAddrTable ();
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
diff --git a/src/share/native/sun/nio/ch/genSocketOptionRegistry.c b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c
new file mode 100644
index 000000000..85088ace8
--- /dev/null
+++ b/src/share/native/sun/nio/ch/genSocketOptionRegistry.c
@@ -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;
+}
diff --git a/src/share/sample/nio/multicast/MulticastAddress.java b/src/share/sample/nio/multicast/MulticastAddress.java
new file mode 100644
index 000000000..e1a3bf3eb
--- /dev/null
+++ b/src/share/sample/nio/multicast/MulticastAddress.java
@@ -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);
+ }
+}
diff --git a/src/share/sample/nio/multicast/Reader.java b/src/share/sample/nio/multicast/Reader.java
new file mode 100644
index 000000000..0d1bd8672
--- /dev/null
+++ b/src/share/sample/nio/multicast/Reader.java
@@ -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());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/share/sample/nio/multicast/Sender.java b/src/share/sample/nio/multicast/Sender.java
new file mode 100644
index 000000000..d72a24d5a
--- /dev/null
+++ b/src/share/sample/nio/multicast/Sender.java
@@ -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();
+ }
+
+}
diff --git a/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c
index 1ff6c48db..460ce1049 100644
--- a/src/solaris/native/java/net/net_util_md.c
+++ b/src/solaris/native/java/net/net_util_md.c
@@ -791,7 +791,7 @@ NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
#endif /* AF_INET6 */
}
-jint
+JNIEXPORT jint JNICALL
NET_GetPortFromSockaddr(struct sockaddr *him) {
#ifdef AF_INET6
if (him->sa_family == AF_INET6) {
diff --git a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
index b1f9f680b..bbbccd725 100644
--- a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
+++ b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
@@ -198,7 +198,7 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
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 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
if (NET_InetAddressToSockaddr(env, destAddress, destPort,
(struct sockaddr *)&sa,
- &sa_len, JNI_TRUE) != 0) {
+ &sa_len, preferIPv6) != 0) {
return IOS_THROWN;
}
diff --git a/src/solaris/native/sun/nio/ch/FileKey.c b/src/solaris/native/sun/nio/ch/FileKey.c
index 511b27f87..fc5618883 100644
--- a/src/solaris/native/sun/nio/ch/FileKey.c
+++ b/src/solaris/native/sun/nio/ch/FileKey.c
@@ -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)
diff --git a/src/solaris/native/sun/nio/ch/Net.c b/src/solaris/native/sun/nio/ch/Net.c
index 9eb31c892..d9bbb6e78 100644
--- a/src/solaris/native/sun/nio/ch/Net.c
+++ b/src/solaris/native/sun/nio/ch/Net.c
@@ -37,61 +37,171 @@
#include "net_util.h"
#include "net_util_md.h"
#include "nio_util.h"
-#include "java_net_SocketOptions.h"
#include "nio.h"
-#ifdef __linux__
-#include <sys/utsname.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
-#define IPV6_MULTICAST_IF 17
-#ifndef SO_BSDCOMPAT
-#define SO_BSDCOMPAT 14
+#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__
+
+#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)
{
/* 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 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk
}
}
+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 @@ Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
}
-
-#ifdef NEEDED
-
-/* ## This is gross. We should generate platform-specific constant
- * ## definitions into a .java file and use those directly.
- */
-
-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;
- }
-
- 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;
- }
-
- return 0;
-}
-#endif
-
-
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;
struct linger linger;
+ u_char carg;
void *arg;
- int arglen;
+ int arglen, n;
- if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
- JNU_ThrowByNameWithLastError(env,
- JNU_JAVANETPKG "SocketException",
- "Unsupported socket option");
- return -1;
+ /* Option value is an int except for a few specific cases */
+
+ arg = (void *)&result;
+ arglen = sizeof(result);
+
+ if (level == IPPROTO_IP &&
+ (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
+ arg = (void*)&carg;
+ arglen = sizeof(carg);
}
- if (opt == java_net_SocketOptions_SO_LINGER) {
+ if (level == SOL_SOCKET && opt == 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 (mayNeedConversion) {
+ n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen);
+ } else {
+ n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
+ }
+ 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 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz,
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 */
diff --git a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c
index da92ed73d..c0019d5ad 100644
--- a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c
+++ b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c
@@ -65,14 +65,6 @@ Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass c)
"(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,
diff --git a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c
index 94c8467cf..7190b1b12 100644
--- a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c
+++ b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c
@@ -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 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this,
}
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);
-}
diff --git a/src/solaris/native/sun/nio/ch/nio_util.h b/src/solaris/native/sun/nio/ch/nio_util.h
index 608b0cc89..02c15ed47 100644
--- a/src/solaris/native/sun/nio/ch/nio_util.h
+++ b/src/solaris/native/sun/nio/ch/nio_util.h
@@ -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 */
diff --git a/src/windows/native/java/net/net_util_md.c b/src/windows/native/java/net/net_util_md.c
index 5fe1dc5d9..ddf149684 100644
--- a/src/windows/native/java/net/net_util_md.c
+++ b/src/windows/native/java/net/net_util_md.c
@@ -889,7 +889,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr
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);
diff --git a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c
index 6d400c213..99cc716eb 100644
--- a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c
+++ b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c
@@ -39,46 +39,9 @@ static jfieldID isa_portID; /* port in java.net.InetSocketAddress */
static jfieldID dci_senderID; /* sender in sun.nio.ch.DatagramChannelImpl */
static jfieldID dci_senderAddrID; /* sender InetAddress in sun.nio.ch.DatagramChannelImpl */
static jfieldID dci_senderPortID; /* sender port in sun.nio.ch.DatagramChannelImpl */
-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 @@ Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz)
"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 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd)
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 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd)
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 @@ jboolean purgeOutstandingICMP(JNIEnv *env, jclass clazz, jint fd)
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 @@ Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this,
{
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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
{
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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
(char *)buf,
len,
0,
- (struct sockaddr *)&psa,
+ (struct sockaddr *)&sa,
&sa_len);
if (n == SOCKET_ERROR) {
@@ -233,21 +164,30 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
}
} while (retry);
- if (!isSenderCached(env, this, &psa)) {
- int port = ntohs(psa.sin_port);
- jobject ia = (*env)->NewObject(env, ia_class, ia_ctorID);
- jobject isa = NULL;
-
- if (psa.sin_family != AF_INET) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family unavailable");
+ /*
+ * 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;
+ 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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
// 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 @@ Java_sun_nio_ch_DatagramChannelImpl_receive0(JNIEnv *env, jobject this,
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 @@ Java_sun_nio_ch_DatagramChannelImpl_send0(JNIEnv *env, jobject this,
buf,
len,
0,
- (struct sockaddr *)&psa,
+ (struct sockaddr *)&sa,
sa_len);
if (rv == SOCKET_ERROR) {
int theErr = (jint)WSAGetLastError();
diff --git a/src/windows/native/sun/nio/ch/Net.c b/src/windows/native/sun/nio/ch/Net.c
index b9fac794e..c89745a21 100644
--- a/src/windows/native/sun/nio/ch/Net.c
+++ b/src/windows/native/sun/nio/ch/Net.c
@@ -36,51 +36,95 @@
#include "sun_nio_ch_Net.h"
+/**
+ * Definitions to allow for building with older SDK include files.
+ */
+
+#ifndef MCAST_BLOCK_SOURCE
+
+#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 */
-static jfieldID ia_addrID;
-static jclass ia_class;
-static jmethodID ia_ctorID;
-static jfieldID ia_famID;
+typedef struct my_ip_mreq_source {
+ IN_ADDR imr_multiaddr;
+ IN_ADDR imr_sourceaddr;
+ IN_ADDR imr_interface;
+};
-/**************************************************************
- * static method to store field IDs in initializers
+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 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz,
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 @@ Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao,
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 @@ Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
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;
}
+ return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+}
- 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));
- }
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
+{
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
- return iao;
+ 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;
-
- if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
- JNU_ThrowByNameWithLastError(env,
- JNU_JAVANETPKG "SocketException",
- "Unsupported socket option");
- return IOS_THROWN;
- }
+ int arglen, n;
- 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 @@ Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz,
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 @@ Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz,
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");
}
}
diff --git a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c
index 36b6006e0..a597d2525 100644
--- a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c
+++ b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c
@@ -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 @@ Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv *env, jclass cls)
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 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this,
{
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 @@ Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv *env, jobject this,
JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
return IOS_THROWN;
}
- (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
- 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);
+ (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
+ remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port);
- isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia,
- ntohs(sa.sin_port));
+ isa = (*env)->NewObject(env, isa_class, isa_ctorID,
+ remote_ia, remote_port);
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
+
return 1;
}
diff --git a/src/windows/native/sun/nio/ch/SocketChannelImpl.c b/src/windows/native/sun/nio/ch/SocketChannelImpl.c
index d49d9bf29..1c8992568 100644
--- a/src/windows/native/sun/nio/ch/SocketChannelImpl.c
+++ b/src/windows/native/sun/nio/ch/SocketChannelImpl.c
@@ -139,12 +139,3 @@ Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv *env, jobject this,
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");
- }
-}
diff --git a/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java
new file mode 100644
index 000000000..03b5daa68
--- /dev/null
+++ b/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java
@@ -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);
+ }
+ }
+}
diff --git a/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
new file mode 100644
index 000000000..11e3b0be0
--- /dev/null
+++ b/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
@@ -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);
+ }
+ }
+}
diff --git a/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java
new file mode 100644
index 000000000..f1d7d5deb
--- /dev/null
+++ b/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java
@@ -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);
+ }
+}
diff --git a/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java
new file mode 100644
index 000000000..e4e85b11f
--- /dev/null
+++ b/test/java/nio/channels/DatagramChannel/SocketOptionTests.java
@@ -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) {
+ }
+ }
+}
diff --git a/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java
new file mode 100644
index 000000000..6c4a443ed
--- /dev/null
+++ b/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java
@@ -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) {
+ }
+ }
+}
diff --git a/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/test/java/nio/channels/SocketChannel/SocketOptionTests.java
new file mode 100644
index 000000000..b6fadced8
--- /dev/null
+++ b/test/java/nio/channels/SocketChannel/SocketOptionTests.java
@@ -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) {
+ }
+ }
+}
diff --git a/test/java/nio/channels/TestUtil.java b/test/java/nio/channels/TestUtil.java
index 63e8537ea..8a8449e00 100644
--- a/test/java/nio/channels/TestUtil.java
+++ b/test/java/nio/channels/TestUtil.java
@@ -38,7 +38,7 @@ public class TestUtil {
// 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 @@ public class TestUtil {
static boolean onWindows() {
return osName.startsWith("Windows");
}
-
}
diff --git a/test/java/nio/channels/etc/NetworkChannelTests.java b/test/java/nio/channels/etc/NetworkChannelTests.java
new file mode 100644
index 000000000..5f03453ca
--- /dev/null
+++ b/test/java/nio/channels/etc/NetworkChannelTests.java
@@ -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);
+ }
+
+}