4640544: New I/O: Complete socket-channel functionality
authoralanb
Sun Aug 31 18:39:01 2008 +0100 (18 months ago)
changeset 562343253d05123
parent 561f9cf71f806eb
child 5630a427d0e70a7
4640544: New I/O: Complete socket-channel functionality
Reviewed-by: iris, sherman, chegar
make/java/nio/FILES_java.gmk
make/java/nio/Makefile
make/java/nio/mapfile-linux
make/java/nio/mapfile-solaris
make/mksample/nio/Makefile
make/mksample/nio/multicast/Makefile
src/share/classes/java/net/NetworkInterface.java
src/share/classes/java/net/ProtocolFamily.java
src/share/classes/java/net/SocketOption.java
src/share/classes/java/net/StandardProtocolFamily.java
src/share/classes/java/net/StandardSocketOption.java
src/share/classes/java/nio/channels/DatagramChannel.java
src/share/classes/java/nio/channels/MembershipKey.java
src/share/classes/java/nio/channels/MulticastChannel.java
src/share/classes/java/nio/channels/NetworkChannel.java
src/share/classes/java/nio/channels/ServerSocketChannel.java
src/share/classes/java/nio/channels/SocketChannel.java
src/share/classes/java/nio/channels/exceptions
src/share/classes/java/nio/channels/package-info.java
src/share/classes/java/nio/channels/package.html
src/share/classes/java/nio/channels/spi/SelectorProvider.java
src/share/classes/sun/nio/ch/DatagramChannelImpl.java
src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java
src/share/classes/sun/nio/ch/ExtendedSocketOption.java
src/share/classes/sun/nio/ch/MembershipKeyImpl.java
src/share/classes/sun/nio/ch/MembershipRegistry.java
src/share/classes/sun/nio/ch/Net.java
src/share/classes/sun/nio/ch/OptionAdaptor.java
src/share/classes/sun/nio/ch/OptionKey.java
src/share/classes/sun/nio/ch/SelectorProviderImpl.java
src/share/classes/sun/nio/ch/ServerSocketAdaptor.java
src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
src/share/classes/sun/nio/ch/SocketAdaptor.java
src/share/classes/sun/nio/ch/SocketChannelImpl.java
src/share/classes/sun/nio/ch/SocketOpts.java
src/share/classes/sun/nio/ch/SocketOptsImpl.java
src/share/classes/sun/nio/ch/exceptions
src/share/native/java/net/net_util.c
src/share/native/java/net/net_util.h
src/share/native/sun/nio/ch/genSocketOptionRegistry.c
src/share/sample/nio/multicast/MulticastAddress.java
src/share/sample/nio/multicast/Reader.java
src/share/sample/nio/multicast/Sender.java
src/solaris/native/java/net/net_util_md.c
src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
src/solaris/native/sun/nio/ch/FileKey.c
src/solaris/native/sun/nio/ch/Net.c
src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c
src/solaris/native/sun/nio/ch/SocketChannelImpl.c
src/solaris/native/sun/nio/ch/nio_util.h
src/windows/native/java/net/net_util_md.c
src/windows/native/sun/nio/ch/DatagramChannelImpl.c
src/windows/native/sun/nio/ch/Net.c
src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c
src/windows/native/sun/nio/ch/SocketChannelImpl.c
test/java/nio/channels/DatagramChannel/BasicMulticastTests.java
test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
test/java/nio/channels/DatagramChannel/NetworkConfiguration.java
test/java/nio/channels/DatagramChannel/SocketOptionTests.java
test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java
test/java/nio/channels/SocketChannel/SocketOptionTests.java
test/java/nio/channels/TestUtil.java
test/java/nio/channels/etc/NetworkChannelTests.java
--- a/make/java/nio/FILES_java.gmk Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/FILES_java.gmk Sun Aug 31 18:39:01 2008 +0100
@@ -39,6 +39,9 @@ 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)
--- a/make/java/nio/Makefile Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/Makefile Sun Aug 31 18:39:01 2008 +0100
@@ -56,18 +56,18 @@ 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 @@ GEN_EX_CMD = NAWK="$(NAWK)" SH="$(SH)" $
@$(RM) $@.temp
$(GEN_EX_CMD) $(BUF_SRC)/exceptions $(BUF_GEN)
-$(SCH_GEN)/%Exception.java: genExceptions.sh $(SCH_SRC)/exceptions
- $(prep-target)
- @$(RM) $@.temp
- $(GEN_EX_CMD) $(SCH_SRC)/exceptions $(SCH_GEN)
-
-
#
# Generated charset-provider classes
#
@@ -638,4 +632,29 @@ HASHER_JARFILE = $(BUILDTOOLJARDIR)/hash
HASHER="$(BOOT_JAVA_CMD) -jar $(HASHER_JARFILE)" \
$(SH) -e genCharsetProvider.sh $(SCS_SRC)/standard-charsets $(SCS_GEN)
+#
+# Generated channel implementation classes.
+# C source is compiled in TEMPDIR to avoid turds left by Windows compilers.
+#
+
+GENSOR_SRC = $(SHARE_SRC)/native/sun/nio/ch/genSocketOptionRegistry.c
+
+GENSOR_EXE = $(TEMPDIR)/genSocketOptionRegistry$(EXE_SUFFIX)
+
+SOR_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSOR_SRC) | \
+ $(NAWK) '/^.*Copyright.*Sun/ { print $$3 }')
+
+$(TEMPDIR)/$(GENSOR_SRC) : $(GENSOR_SRC)
+ $(install-file)
+
+$(GENSOR_EXE) : $(TEMPDIR)/$(GENSOR_SRC)
+ $(prep-target)
+ ($(CD) $(TEMPDIR); $(CC) $(CPPFLAGS) $(LDDFLAGS) \
+ -o genSocketOptionRegistry$(EXE_SUFFIX) $(GENSOR_SRC))
+
+$(SCH_GEN)/SocketOptionRegistry.java: $(GENSOR_EXE)
+ $(prep-target)
+ NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(SOR_COPYRIGHT_YEARS) > $@
+ $(GENSOR_EXE) >> $@
+
.PHONY: sources
--- a/make/java/nio/mapfile-linux Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/mapfile-linux Sun Aug 31 18:39:01 2008 +0100
@@ -1,3 +1,27 @@
+#
+# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
SUNWprivate_1.1 {
global:
@@ -61,20 +85,29 @@ 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:
*;
--- a/make/java/nio/mapfile-solaris Sun Aug 31 18:32:59 2008 +0100
+++ b/make/java/nio/mapfile-solaris Sun Aug 31 18:39:01 2008 +0100
@@ -1,3 +1,27 @@
+#
+# Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
SUNWprivate_1.1 {
global:
@@ -59,20 +83,29 @@ 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:
*;
--- a/make/mksample/nio/Makefile Sun Aug 31 18:32:59 2008 +0100
+++ b/make/mksample/nio/Makefile Sun Aug 31 18:39:01 2008 +0100
@@ -31,7 +31,7 @@ PRODUCT = java
PRODUCT = java
include $(BUILDDIR)/common/Defs.gmk
-SUBDIRS = server
+SUBDIRS = multicast server
all build clean clobber::
$(SUBDIRS-loop)
--- a/src/share/classes/java/net/NetworkInterface.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/net/NetworkInterface.java Sun Aug 31 18:39:01 2008 +0100
@@ -25,7 +25,6 @@
package java.net;
-import java.net.SocketException;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import sun.security.action.*;
--- a/src/share/classes/java/nio/channels/DatagramChannel.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/DatagramChannel.java Sun Aug 31 18:39:01 2008 +0100
@@ -26,28 +26,21 @@ package java.nio.channels;
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,10 +52,56 @@ 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
@@ -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
*
@@ -97,6 +142,39 @@ public abstract class DatagramChannel
*/
public static DatagramChannel open() throws IOException {
return SelectorProvider.provider().openDatagramChannel();
+ }
+
+ /**
+ * 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);
}
/**
@@ -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>
- *
- * @return <tt>true</tt> if, and only if, this channel's socket
- * is connected
+ * Tells whether or not 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();
@@ -205,6 +309,19 @@ public abstract class DatagramChannel
* If some other I/O error occurs
*/
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.
--- a/src/share/classes/java/nio/channels/ServerSocketChannel.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/ServerSocketChannel.java Sun Aug 31 18:39:01 2008 +0100
@@ -27,32 +27,43 @@ 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
@@ -61,6 +72,7 @@ import java.nio.channels.spi.*;
public abstract class ServerSocketChannel
extends AbstractSelectableChannel
+ implements NetworkChannel
{
/**
@@ -108,6 +120,89 @@ public abstract class ServerSocketChanne
// -- 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.
--- a/src/share/classes/java/nio/channels/SocketChannel.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/SocketChannel.java Sun Aug 31 18:39:01 2008 +0100
@@ -27,24 +27,17 @@ 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}
@@ -58,16 +51,6 @@ import java.nio.channels.spi.*;
* later completion by the {@link #finishConnect finishConnect} method.
* 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.
@@ -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 --
--- a/src/share/classes/java/nio/channels/exceptions Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/exceptions Sun Aug 31 18:39:01 2008 +0100
@@ -146,3 +146,14 @@ 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
+
--- a/src/share/classes/java/nio/channels/spi/SelectorProvider.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/java/nio/channels/spi/SelectorProvider.java Sun Aug 31 18:39:01 2008 +0100
@@ -25,10 +25,8 @@
package java.nio.channels.spi;
-import java.io.FileDescriptor;
import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.Socket;
+import java.net.ProtocolFamily;
import java.nio.channels.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -190,7 +188,25 @@ 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
*/
--- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Sun Aug 31 18:39:01 2008 +0100
@@ -31,7 +31,7 @@ import java.nio.ByteBuffer;
import java.nio.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,18 +101,40 @@ 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;
+ }
+
public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
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() {
@@ -118,6 +143,156 @@ class DatagramChannelImpl
socket = DatagramSocketAdaptor.create(this);
return socket;
}
+ }
+
+ @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 {
@@ -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 {
--- a/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/DatagramSocketAdaptor.java Sun Aug 31 18:39:01 2008 +0100
@@ -45,15 +45,8 @@ 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 {
@@ -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() {
--- a/src/share/classes/sun/nio/ch/Net.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/Net.java Sun Aug 31 18:39:01 2008 +0100
@@ -26,21 +26,43 @@ package sun.nio.ch;
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 {
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,29 +129,230 @@ class Net {
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);
-
- static native void bind(FileDescriptor fd, InetAddress addr, int port)
- throws IOException;
-
- static native int connect(FileDescriptor fd,
- InetAddress remote,
- int remotePort,
- int trafficClass)
- throws IOException;
-
+ 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 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 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;
@@ -135,42 +360,127 @@ class Net {
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 int localPortNumber(FileDescriptor fd) {
- try {
- return localPort(fd);
- } catch (IOException x) {
- throw new Error(x); // Can't happen
- }
- }
-
- private static native int getIntOption0(FileDescriptor fd, int opt)
- throws IOException;
-
- static int getIntOption(FileDescriptor fd, int opt)
- throws IOException
- {
- return getIntOption0(fd, opt);
- }
-
-
- private static native void setIntOption0(FileDescriptor fd,
- int opt, int arg)
- throws IOException;
-
- static void setIntOption(FileDescriptor fd, int opt, int arg)
- throws IOException
- {
- setIntOption0(fd, opt, arg);
- }
+ static InetSocketAddress localAddress(FileDescriptor fd)
+ throws IOException
+ {
+ return new InetSocketAddress(localInetAddress(fd), localPort(fd));
+ }
+
+ 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 blockOrUnblock4(boolean block, FileDescriptor fd, int group,
+ int interf, int source)
+ throws IOException;
+
+ /**
+ * Join IPv6 multicast group
+ */
+ static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
+ throws IOException
+ {
+ return joinOrDrop6(true, fd, group, index, source);
+ }
+
+ /**
+ * Drop membership of IPv6 multicast group
+ */
+ static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source)
+ throws IOException
+ {
+ joinOrDrop6(false, fd, group, index, source);
+ }
+
+ private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
+ throws IOException;
+
+ /**
+ * Block IPv6 source
+ */
+ static int block6(FileDescriptor fd, byte[] group, int index, byte[] source)
+ throws IOException
+ {
+ return blockOrUnblock6(true, fd, group, index, source);
+ }
+
+ /**
+ * Unblock IPv6 source
+ */
+ static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source)
+ throws IOException
+ {
+ blockOrUnblock6(false, fd, group, index, source);
+ }
+
+ static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source)
+ throws IOException;
+
+ static native void setInterface4(FileDescriptor fd, int interf) throws IOException;
+
+ static native int getInterface4(FileDescriptor fd) throws IOException;
+
+ static native void setInterface6(FileDescriptor fd, int index) throws IOException;
+
+ static native int getInterface6(FileDescriptor fd) throws IOException;
private static native void initIDs();
--- a/src/share/classes/sun/nio/ch/SelectorProviderImpl.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/SelectorProviderImpl.java Sun Aug 31 18:39:01 2008 +0100
@@ -29,6 +29,7 @@ import java.io.IOException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.ProtocolFamily;
import java.nio.channels.*;
import java.nio.channels.spi.*;
@@ -39,6 +40,10 @@ public abstract class SelectorProviderIm
public DatagramChannel openDatagramChannel() throws IOException {
return new DatagramChannelImpl(this);
+ }
+
+ public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException {
+ return new DatagramChannelImpl(this, family);
}
public Pipe openPipe() throws IOException {
@@ -54,5 +59,4 @@ public abstract class SelectorProviderIm
public SocketChannel openSocketChannel() throws IOException {
return new SocketChannelImpl(this);
}
-
}
--- a/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ServerSocketAdaptor.java Sun Aug 31 18:39:01 2008 +0100
@@ -43,9 +43,6 @@ public class ServerSocketAdaptor
// 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
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
}
public void setReceiveBufferSize(int size) throws SocketException {
- opts().setReceiveBufferSize(size);
+ // size 0 valid for ServerSocketChannel, invalid for ServerSocket
+ if (size <= 0)
+ throw new IllegalArgumentException("size cannot be 0 or negative");
+ try {
+ ssc.setOption(StandardSocketOption.SO_RCVBUF, size);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
}
public int getReceiveBufferSize() throws SocketException {
- return opts().getReceiveBufferSize();
+ try {
+ return ssc.getOption(StandardSocketOption.SO_RCVBUF).intValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // Never happens
+ }
}
}
--- a/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Sun Aug 31 18:39:01 2008 +0100
@@ -33,8 +33,7 @@ import java.nio.channels.spi.*;
import java.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
--- a/src/share/classes/sun/nio/ch/SocketAdaptor.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/SocketAdaptor.java Sun Aug 31 18:39:01 2008 +0100
@@ -54,15 +54,8 @@ 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) {
@@ -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() {
--- a/src/share/classes/sun/nio/ch/SocketChannelImpl.java Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/classes/sun/nio/ch/SocketChannelImpl.java Sun Aug 31 18:39:01 2008 +0100
@@ -31,6 +31,7 @@ import java.nio.ByteBuffer;
import java.nio.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;
}
@@ -123,6 +122,98 @@ class SocketChannelImpl
socket = SocketAdaptor.create(this);
return socket;
}
+ }
+
+ @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 {
@@ -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);
- }
- }
-
- public void shutdownOutput() throws IOException {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+ if (isInputOpen) {
+ Net.shutdown(fd, Net.SHUT_RD);
+ if (readerThread != 0)
+ NativeThread.signal(readerThread);
+ isInputOpen = false;
+ }
+ return this;
+ }
+ }
+
+ @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();
--- a/src/share/native/java/net/net_util.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/native/java/net/net_util.c Sun Aug 31 18:39:01 2008 +0100
@@ -82,7 +82,7 @@ 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, s
return iaObj;
}
-jint
+JNIEXPORT jint JNICALL
NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
{
jint family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
--- a/src/share/native/java/net/net_util.h Sun Aug 31 18:32:59 2008 +0100
+++ b/src/share/native/java/net/net_util.h Sun Aug 31 18:39:01 2008 +0100
@@ -116,7 +116,7 @@ JNIEXPORT int JNICALL
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
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
--- a/src/solaris/native/java/net/net_util_md.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/java/net/net_util_md.c Sun Aug 31 18:39:01 2008 +0100
@@ -791,7 +791,7 @@ NET_SetTrafficClass(struct sockaddr *him
#endif /* AF_INET6 */
}
-jint
+JNIEXPORT jint JNICALL
NET_GetPortFromSockaddr(struct sockaddr *him) {
#ifdef AF_INET6
if (him->sa_family == AF_INET6) {
--- a/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c Sun Aug 31 18:39:01 2008 +0100
@@ -198,7 +198,7 @@ Java_sun_nio_ch_DatagramChannelImpl_rece
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_send
if (NET_InetAddressToSockaddr(env, destAddress, destPort,
(struct sockaddr *)&sa,
- &sa_len, JNI_TRUE) != 0) {
+ &sa_len, preferIPv6) != 0) {
return IOS_THROWN;
}
--- a/src/solaris/native/sun/nio/ch/FileKey.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/FileKey.c Sun Aug 31 18:39:01 2008 +0100
@@ -33,12 +33,6 @@ static jfieldID key_st_dev; /* id for
static jfieldID key_st_dev; /* id for FileKey.st_dev */
static jfieldID key_st_ino; /* id for FileKey.st_ino */
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while ((_result == -1) && (errno == EINTR)); \
-} while(0)
-
JNIEXPORT void JNICALL
Java_sun_nio_ch_FileKey_initIDs(JNIEnv *env, jclass clazz)
--- a/src/solaris/native/sun/nio/ch/Net.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/Net.c Sun Aug 31 18:39:01 2008 +0100
@@ -37,17 +37,109 @@
#include "net_util.h"
#include "net_util_md.h"
#include "nio_util.h"
-#include "java_net_SocketOptions.h"
#include "nio.h"
+/**
+ * Definitions for source-specific multicast to allow for building
+ * with older header files.
+ */
+
+#ifdef __solaris__
+
+#ifndef IP_BLOCK_SOURCE
+
+#define IP_BLOCK_SOURCE 0x15
+#define IP_UNBLOCK_SOURCE 0x16
+#define IP_ADD_SOURCE_MEMBERSHIP 0x17
+#define IP_DROP_SOURCE_MEMBERSHIP 0x18
+
+#define MCAST_BLOCK_SOURCE 0x2b
+#define MCAST_UNBLOCK_SOURCE 0x2c
+#define MCAST_JOIN_SOURCE_GROUP 0x2d
+#define MCAST_LEAVE_SOURCE_GROUP 0x2e
+
+#endif /* IP_BLOCK_SOURCE */
+
+struct my_ip_mreq_source {
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_sourceaddr;
+ struct in_addr imr_interface;
+};
+
+/*
+ * Use #pragma pack() construct to force 32-bit alignment on amd64.
+ */
+#if defined(amd64)
+#pragma pack(4)
+#endif
+
+struct my_group_source_req {
+ uint32_t gsr_interface; /* interface index */
+ struct sockaddr_storage gsr_group; /* group address */
+ struct sockaddr_storage gsr_source; /* source address */
+};
+
+#if defined(amd64)
+#pragma pack()
+#endif
+
+#endif /* __solaris__ */
+
+
#ifdef __linux__
-#include <sys/utsname.h>
-
-#define IPV6_MULTICAST_IF 17
-#ifndef SO_BSDCOMPAT
-#define SO_BSDCOMPAT 14
-#endif
-#endif
+
+#ifndef IP_BLOCK_SOURCE
+
+#define IP_BLOCK_SOURCE 38
+#define IP_UNBLOCK_SOURCE 37
+#define IP_ADD_SOURCE_MEMBERSHIP 39
+#define IP_DROP_SOURCE_MEMBERSHIP 40
+
+#define MCAST_BLOCK_SOURCE 43
+#define MCAST_UNBLOCK_SOURCE 44
+#define MCAST_JOIN_SOURCE_GROUP 42
+#define MCAST_LEAVE_SOURCE_GROUP 45
+
+#endif /* IP_BLOCK_SOURCE */
+
+struct my_ip_mreq_source {
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_interface;
+ struct in_addr imr_sourceaddr;
+};
+
+struct my_group_source_req {
+ uint32_t gsr_interface; /* interface index */
+ struct sockaddr_storage gsr_group; /* group address */
+ struct sockaddr_storage gsr_source; /* source address */
+};
+
+#endif /* __linux__ */
+
+
+#define COPY_INET6_ADDRESS(env, source, target) \
+ (*env)->GetByteArrayRegion(env, source, 0, 16, target)
+
+/*
+ * Copy IPv6 group, interface index, and IPv6 source address
+ * into group_source_req structure.
+ */
+static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
+ jbyteArray source, struct my_group_source_req* req)
+{
+ struct sockaddr_in6* sin6;
+
+ req->gsr_interface = (uint32_t)index;
+
+ sin6 = (struct sockaddr_in6*)&(req->gsr_group);
+ sin6->sin6_family = AF_INET6;
+ COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
+
+ sin6 = (struct sockaddr_in6*)&(req->gsr_source);
+ sin6->sin6_family = AF_INET6;
+ COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
+}
+
JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
@@ -55,43 +147,61 @@ Java_sun_nio_ch_Net_initIDs(JNIEnv *env,
/* 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;
-
-#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);
-
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+ int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
+
+ 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,26 +211,26 @@ Java_sun_nio_ch_Net_bind(JNIEnv *env, jc
}
}
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz,
- jobject fdo, jobject iao, jint port,
- jint trafficClass)
+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_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) {
@@ -159,119 +269,79 @@ Java_sun_nio_ch_Net_localInetAddress(JNI
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)
-{
- int klevel, kopt;
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+ jboolean mayNeedConversion, jint level, jint opt)
+{
int result;
struct linger linger;
+ u_char carg;
void *arg;
- int arglen;
-
- if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
- JNU_ThrowByNameWithLastError(env,
- JNU_JAVANETPKG "SocketException",
- "Unsupported socket option");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
+ int arglen, n;
+
+ /* 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 (level == SOL_SOCKET && opt == SO_LINGER) {
arg = (void *)&linger;
arglen = sizeof(linger);
+ }
+
+ if (mayNeedConversion) {
+ n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen);
} else {
- arg = (void *)&result;
- arglen = sizeof(result);
- }
-
- if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) {
+ 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;
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz,
- jobject fdo, jint opt, jint arg)
-{
- int klevel, kopt;
+ 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,
+ jboolean mayNeedConversion, jint level, jint opt, jint arg)
+{
int result;
struct linger linger;
+ u_char carg;
void *parg;
- int arglen;
-
- if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
- JNU_ThrowByNameWithLastError(env,
- JNU_JAVANETPKG "SocketException",
- "Unsupported socket option");
- return;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
+ int arglen, n;
+
+ /* 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 (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
linger.l_onoff = 0;
linger.l_linger = 0;
}
+ }
+
+ if (mayNeedConversion) {
+ n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
} else {
- parg = (void *)&arg;
- arglen = sizeof(arg);
- }
-
- if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) {
+ n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
+ }
+ if (n < 0) {
JNU_ThrowByNameWithLastError(env,
JNU_JAVANETPKG "SocketException",
"sun.nio.ch.Net.setIntOption");
}
}
-
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+ jint group, jint interf, jint source)
+{
+ struct ip_mreq mreq;
+ struct my_ip_mreq_source mreq_source;
+ int opt, n, optlen;
+ void* optval;
+
+ if (source == 0) {
+ mreq.imr_multiaddr.s_addr = htonl(group);
+ mreq.imr_interface.s_addr = htonl(interf);
+ opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ optval = (void*)&mreq;
+ optlen = sizeof(mreq);
+ } else {
+ mreq_source.imr_multiaddr.s_addr = htonl(group);
+ mreq_source.imr_sourceaddr.s_addr = htonl(source);
+ mreq_source.imr_interface.s_addr = htonl(interf);
+ opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
+ optval = (void*)&mreq_source;
+ optlen = sizeof(mreq_source);
+ }
+
+ n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
+ if (n < 0) {
+ if (join && (errno == ENOPROTOOPT))
+ return IOS_UNAVAILABLE;
+ handleSocketError(env, errno);
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+ jint group, jint interf, jint source)
+{
+ struct my_ip_mreq_source mreq_source;
+ int n;
+ int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
+
+ mreq_source.imr_multiaddr.s_addr = htonl(group);
+ mreq_source.imr_sourceaddr.s_addr = htonl(source);
+ mreq_source.imr_interface.s_addr = htonl(interf);
+
+ n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
+ (void*)&mreq_source, sizeof(mreq_source));
+ if (n < 0) {
+ if (block && (errno == ENOPROTOOPT))
+ return IOS_UNAVAILABLE;
+ handleSocketError(env, errno);
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+ jbyteArray group, jint index, jbyteArray source)
+{
+ struct ipv6_mreq mreq6;
+ struct my_group_source_req req;
+ int opt, n, optlen;
+ void* optval;
+
+ if (source == NULL) {
+ COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
+ mreq6.ipv6mr_interface = (int)index;
+ opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+ optval = (void*)&mreq6;
+ optlen = sizeof(mreq6);
+ } else {
+#ifdef __linux__
+ /* Include-mode filtering broken on Linux at least to 2.6.24 */
+ return IOS_UNAVAILABLE;
+#else
+ initGroupSourceReq(env, group, index, source, &req);
+ opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
+ optval = (void*)&req;
+ optlen = sizeof(req);
+#endif
+ }
+
+ n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
+ if (n < 0) {
+ if (join && (errno == ENOPROTOOPT))
+ return IOS_UNAVAILABLE;
+ handleSocketError(env, errno);
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+ jbyteArray group, jint index, jbyteArray source)
+{
+ struct my_group_source_req req;
+ int n;
+ int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
+
+ initGroupSourceReq(env, group, index, source, &req);
+
+ n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
+ (void*)&req, sizeof(req));
+ if (n < 0) {
+ if (block && (errno == ENOPROTOOPT))
+ return IOS_UNAVAILABLE;
+ handleSocketError(env, errno);
+ }
+ return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
+{
+ struct in_addr in;
+ int arglen = sizeof(struct in_addr);
+ int n;
+
+ in.s_addr = htonl(interf);
+
+ n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
+ (void*)&(in.s_addr), arglen);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
+{
+ struct in_addr in;
+ int arglen = sizeof(struct in_addr);
+ int n;
+
+ n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ return -1;
+ }
+ return ntohl(in.s_addr);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
+{
+ int value = (jint)index;
+ int arglen = sizeof(value);
+ int n;
+
+ n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ (void*)&(index), arglen);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
+{
+ int index;
+ int arglen = sizeof(index);
+ int n;
+
+ n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ return -1;
+ }
+ return (jint)index;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
+{
+ int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
+ (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
+ if (shutdown(fdval(env, fdo), how) < 0)
+ handleSocketError(env, errno);
+}
/* Declared in nio_util.h */
--- a/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c Sun Aug 31 18:39:01 2008 +0100
@@ -63,14 +63,6 @@ Java_sun_nio_ch_ServerSocketChannelImpl_
isa_class = (*env)->NewGlobalRef(env, cls);
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
"(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
--- a/src/solaris/native/sun/nio/ch/SocketChannelImpl.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/SocketChannelImpl.c Sun Aug 31 18:39:01 2008 +0100
@@ -33,10 +33,6 @@
#if __linux__
#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"
@@ -88,12 +84,3 @@ Java_sun_nio_ch_SocketChannelImpl_checkC
}
return 0;
}
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_SocketChannelImpl_shutdown(JNIEnv *env, jclass cl,
- jobject fdo, jint how)
-{
- if (shutdown(fdval(env, fdo), how) < 0)
- handleSocketError(env, errno);
-}
--- a/src/solaris/native/sun/nio/ch/nio_util.h Sun Aug 31 18:32:59 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/nio_util.h Sun Aug 31 18:39:01 2008 +0100
@@ -27,7 +27,14 @@
#include "jni_util.h"
#include "jvm.h"
#include "jlong.h"
+#include <errno.h>
#include <sys/types.h>
+
+#define RESTARTABLE(_cmd, _result) do { \
+ do { \
+ _result = _cmd; \
+ } while((_result == -1) && (errno == EINTR)); \
+} while(0)
/* NIO utility procedures */
--- a/src/windows/native/java/net/net_util_md.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/java/net/net_util_md.c Sun Aug 31 18:39:01 2008 +0100
@@ -889,7 +889,7 @@ NET_InetAddressToSockaddr(JNIEnv *env, j
return 0;
}
-jint
+JNIEXPORT jint JNICALL
NET_GetPortFromSockaddr(struct sockaddr *him) {
if (him->sa_family == AF_INET6) {
return ntohs(((struct sockaddr_in6*)him)->sin6_port);
--- a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c Sun Aug 31 18:39:01 2008 +0100
@@ -39,46 +39,9 @@ static jfieldID dci_senderID; /* sende
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;
-
-/*
- * 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;
-}
+static jmethodID isa_ctorID; /* java.net.InetSocketAddress(InetAddress, int) */
+
JNIEXPORT void JNICALL
Java_sun_nio_ch_DatagramChannelImpl_initIDs(JNIEnv *env, jclass clazz)
@@ -99,32 +62,6 @@ Java_sun_nio_ch_DatagramChannelImpl_init
"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 *en
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 *en
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 *en
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_disc
{
jint fd = fdval(env, fdo);
int rv = 0;
- struct sockaddr_in psa;
- int sa_len = sizeof(psa);
-
- memset(&psa, 0, sa_len);
-
- rv = connect((SOCKET)fd, (struct sockaddr *)&psa, sa_len);
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
+
+ memset(&sa, 0, 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_rece
{
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_rece
(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_rece
}
} while (retry);
- if (!isSenderCached(env, this, &psa)) {
- int port = ntohs(psa.sin_port);
- jobject ia = (*env)->NewObject(env, ia_class, ia_ctorID);
+ /*
+ * If the source address and port match the cached address
+ * and port in DatagramChannelImpl then we don't need to
+ * create InetAddress and InetSocketAddress objects.
+ */
+ senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
+ if (senderAddr != NULL) {
+ if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
+ senderAddr)) {
+ senderAddr = NULL;
+ } else {
+ jint port = (*env)->GetIntField(env, this, dci_senderPortID);
+ if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) {
+ senderAddr = NULL;
+ }
+ }
+ }
+ if (senderAddr == NULL) {
jobject isa = NULL;
-
- if (psa.sin_family != AF_INET) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family unavailable");
- }
+ int port;
+ jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa,
+ &port);
if (ia != NULL) {
- // populate InetAddress (assumes AF_INET)
- (*env)->SetIntField(env, ia, ia_addrID, ntohl(psa.sin_addr.s_addr));
-
- // create InetSocketAddress
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
}
@@ -258,9 +198,8 @@ Java_sun_nio_ch_DatagramChannelImpl_rece
// 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_rece
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_send
buf,
len,
0,
- (struct sockaddr *)&psa,
+ (struct sockaddr *)&sa,
sa_len);
if (rv == SOCKET_ERROR) {
int theErr = (jint)WSAGetLastError();
--- a/src/windows/native/sun/nio/ch/Net.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/Net.c Sun Aug 31 18:39:01 2008 +0100
@@ -36,51 +36,95 @@
#include "sun_nio_ch_Net.h"
-
-static jfieldID ia_addrID;
-static jclass ia_class;
-static jmethodID ia_ctorID;
-static jfieldID ia_famID;
-
-/**************************************************************
- * static method to store field IDs in initializers
+/**
+ * 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 */
+
+typedef struct my_ip_mreq_source {
+ IN_ADDR imr_multiaddr;
+ IN_ADDR imr_sourceaddr;
+ IN_ADDR imr_interface;
+};
+
+typedef struct my_group_source_req {
+ ULONG gsr_interface;
+ SOCKADDR_STORAGE gsr_group;
+ SOCKADDR_STORAGE gsr_source;
+};
+
+/**
+ * Copy IPv6 address as jbytearray to target
+ */
+#define COPY_INET6_ADDRESS(env, source, target) \
+ (*env)->GetByteArrayRegion(env, source, 0, 16, target)
+
+
+
JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz)
{
- clazz = (*env)->FindClass(env, "java/net/Inet4Address");
- ia_class = (*env)->NewGlobalRef(env, clazz);
- ia_addrID = (*env)->GetFieldID(env, clazz, "address", "I");
- ia_famID = (*env)->GetFieldID(env, clazz, "family", "I");
- ia_ctorID = (*env)->GetMethodID(env, clazz, "<init>", "()V");
-}
-
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream,
- jboolean reuse)
+ /* 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 preferIPv6,
+ jboolean stream, jboolean reuse)
{
SOCKET s;
-
- s = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
+ int domain = (preferIPv6) ? AF_INET6 : AF_INET;
+
+ 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);
-
- if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) {
+ int sa_len;
+
+ 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, jc
NET_ThrowNew(env, WSAGetLastError(), "bind");
}
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, jobject fdo, jobject iao,
- jint port, jint trafficClass)
+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_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, jobject fdo,
+ jobject iao, jint port)
{
SOCKETADDRESS sa;
int rv;
- int sa_len = sizeof(sa);
-
- if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, JNI_FALSE) != 0) {
- return IOS_THROWN;
+ int sa_len;
+
+ if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
+ return IOS_THROWN;
}
rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
@@ -116,7 +169,7 @@ JNIEXPORT jint JNICALL
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 *en
NET_ThrowNew(env, error, "getsockname");
return IOS_THROWN;
}
- return (jint)ntohs(sa.sin_port);
+ return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
}
JNIEXPORT jobject JNICALL
Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
{
- struct sockaddr_in sa;
+ SOCKETADDRESS sa;
int sa_len = sizeof(sa);
- jobject iao;
+ int port;
if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
NET_ThrowNew(env, WSAGetLastError(), "getsockname");
return NULL;
}
-
- iao = (*env)->NewObject(env, ia_class, ia_ctorID);
- if (iao == NULL) {
- JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
- } else {
- (*env)->SetIntField(env, iao, ia_addrID, ntohl(sa.sin_addr.s_addr));
- }
-
- return iao;
-}
-
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz,
- jobject fdo, jint opt)
-{
- int klevel, kopt;
- int result;
+ return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_remotePort(JNIEnv *env, jclass clazz, jobject fdo)
+{
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
+
+ if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+ int error = WSAGetLastError();
+ if (error == WSAEINVAL) {
+ return 0;
+ }
+ NET_ThrowNew(env, error, "getsockname");
+ return IOS_THROWN;
+ }
+ return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
+}
+
+JNIEXPORT jobject JNICALL
+Java_sun_nio_ch_Net_remoteInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
+{
+ SOCKETADDRESS sa;
+ int sa_len = sizeof(sa);
+ int port;
+
+ if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+ NET_ThrowNew(env, WSAGetLastError(), "getsockname");
+ return NULL;
+ }
+ return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+ jboolean mayNeedConversion, jint level, jint opt)
+{
+ 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;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
+ int arglen, n;
+
+ 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
arglen = sizeof(result);
}
- if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption");
- return IOS_THROWN;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER)
+ /**
+ * 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 (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)
-{
- int klevel, kopt;
+Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
+ jboolean mayNeedConversion, jint level, jint opt, jint arg)
+{
struct linger linger;
char *parg;
- int arglen;
-
- if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
- JNU_ThrowByNameWithLastError(env,
- JNU_JAVANETPKG "SocketException",
- "Unsupported socket option");
- return;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
+ int arglen, n;
+
+ 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
arglen = sizeof(arg);
}
- if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "sun.nio.ch.Net.setIntOption");
- }
-}
+ if (mayNeedConversion) {
+ n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
+ } else {
+ n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
+ }
+ if (n < 0)
+ handleSocketError(env, WSAGetLastError());
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+ jint group, jint interf, jint source)
+{
+ struct ip_mreq mreq;
+ struct my_ip_mreq_source mreq_source;
+ int opt, n, optlen;
+ void* optval;
+
+ if (source == 0) {
+ mreq.imr_multiaddr.s_addr = htonl(group);
+ mreq.imr_interface.s_addr = htonl(interf);
+ opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ optval = (void*)&mreq;
+ optlen = sizeof(mreq);
+ } else {
+ mreq_source.imr_multiaddr.s_addr = htonl(group);
+ mreq_source.imr_sourceaddr.s_addr = htonl(source);
+ mreq_source.imr_interface.s_addr = htonl(interf);
+ opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
+ optval = (void*)&mreq_source;
+ optlen = sizeof(mreq_source);
+ }
+
+ n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
+ if (n < 0) {
+ if (join && (WSAGetLastError() == WSAENOPROTOOPT))
+ return IOS_UNAVAILABLE;
+ handleSocketError(env, WSAGetLastError());
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+ jint group, jint interf, jint source)
+{
+ struct my_ip_mreq_source mreq_source;
+ int n;
+ int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
+
+ mreq_source.imr_multiaddr.s_addr = htonl(group);
+ mreq_source.imr_sourceaddr.s_addr = htonl(source);
+ mreq_source.imr_interface.s_addr = htonl(interf);
+
+ n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
+ (void*)&mreq_source, sizeof(mreq_source));
+ if (n < 0) {
+ if (block && (WSAGetLastError() == WSAENOPROTOOPT))
+ return IOS_UNAVAILABLE;
+ handleSocketError(env, WSAGetLastError());
+ }
+ return 0;
+}
+
+/**
+ * Call setsockopt with a IPPROTO_IPV6 level socket option
+ * and a group_source_req structure as the option value. The
+ * given IPv6 group, interface index, and IPv6 source address
+ * are copied into the structure.
+ */
+static int setGroupSourceReqOption(JNIEnv* env,
+ jobject fdo,
+ int opt,
+ jbyteArray group,
+ jint index,
+ jbyteArray source)
+{
+ struct my_group_source_req req;
+ struct sockaddr_in6* sin6;
+
+ req.gsr_interface = (ULONG)index;
+
+ sin6 = (struct sockaddr_in6*)&(req.gsr_group);
+ sin6->sin6_family = AF_INET6;
+ COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
+
+ sin6 = (struct sockaddr_in6*)&(req.gsr_source);
+ sin6->sin6_family = AF_INET6;
+ COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
+
+ return setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, (void*)&req, sizeof(req));
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
+ jbyteArray group, jint index, jbyteArray source)
+{
+ struct ipv6_mreq mreq6;
+ int n;
+
+ if (source == NULL) {
+ int opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+ COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
+ mreq6.ipv6mr_interface = (int)index;
+ n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
+ (void*)&mreq6, sizeof(mreq6));
+ } else {
+ int opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
+ n = setGroupSourceReqOption(env, fdo, opt, group, index, source);
+ }
+
+ if (n < 0) {
+ handleSocketError(env, errno);
+ }
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
+ jbyteArray group, jint index, jbyteArray source)
+{
+ int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
+ int n = setGroupSourceReqOption(env, fdo, opt, group, index, source);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ }
+ return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
+{
+ struct in_addr in;
+ int arglen = sizeof(struct in_addr);
+ int n;
+
+ in.s_addr = htonl(interf);
+
+ n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
+ (void*)&(in.s_addr), arglen);
+ if (n < 0) {
+ handleSocketError(env, WSAGetLastError());
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
+{
+ struct in_addr in;
+ int arglen = sizeof(struct in_addr);
+ int n;
+
+ n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
+ if (n < 0) {
+ handleSocketError(env, WSAGetLastError());
+ return IOS_THROWN;
+ }
+ return ntohl(in.s_addr);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
+{
+ int value = (jint)index;
+ int arglen = sizeof(value);
+ int n;
+
+ n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ (void*)&(index), arglen);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
+{
+ int index;
+ int arglen = sizeof(index);
+ int n;
+
+ n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
+ if (n < 0) {
+ handleSocketError(env, errno);
+ return -1;
+ }
+ return (jint)index;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) {
+ int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SD_RECEIVE :
+ (jhow == sun_nio_ch_Net_SHUT_WR) ? SD_SEND : SD_BOTH;
+ if (shutdown(fdval(env, fdo), how) == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "shutdown");
+ }
+}
--- a/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c Sun Aug 31 18:39:01 2008 +0100
@@ -46,10 +46,6 @@ static jfieldID fd_fdID; /* java.
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_
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_
{
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_
JNU_ThrowIOExceptionWithLastError(env, "Accept failed");
return IOS_THROWN;
}
+
(*env)->SetIntField(env, newfdo, fd_fdID, newfd);
+ remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port);
- ia = (*env)->NewObject(env, ia_class, ia_ctorID);
- (*env)->SetIntField(env, ia, ia_addrID, ntohl(sa.sin_addr.s_addr));
- (*env)->SetIntField(env, ia, ia_famID, sa.sin_family);
+ isa = (*env)->NewObject(env, isa_class, isa_ctorID,
+ remote_ia, remote_port);
+ (*env)->SetObjectArrayElement(env, isaa, 0, isa);
- isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia,
- ntohs(sa.sin_port));
- (*env)->SetObjectArrayElement(env, isaa, 0, isa);
return 1;
}
--- a/src/windows/native/sun/nio/ch/SocketChannelImpl.c Sun Aug 31 18:32:59 2008 +0100
+++ b/src/windows/native/sun/nio/ch/SocketChannelImpl.c Sun Aug 31 18:39:01 2008 +0100
@@ -139,12 +139,3 @@ Java_sun_nio_ch_SocketChannelImpl_checkC
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");
- }
-}
--- a/test/java/nio/channels/TestUtil.java Sun Aug 31 18:32:59 2008 +0100
+++ b/test/java/nio/channels/TestUtil.java Sun Aug 31 18:39:01 2008 +0100
@@ -38,7 +38,7 @@ 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");
}
-
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/mksample/nio/multicast/Makefile Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,52 @@
+#
+# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+#
+# Makefile for the nio/multicast sample code
+#
+
+BUILDDIR = ../../..
+
+PRODUCT = java
+
+include $(BUILDDIR)/common/Defs.gmk
+
+SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/multicast
+SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/multicast
+
+SAMPLE_FILES = \
+ $(SAMPLE_DST_DIR)/Reader.java \
+ $(SAMPLE_DST_DIR)/Sender.java \
+ $(SAMPLE_DST_DIR)/MulticastAddress.java
+
+all build: $(SAMPLE_FILES)
+
+$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/%
+ $(install-file)
+
+clean clobber:
+ $(RM) -r $(SAMPLE_DST_DIR)
+
+.PHONY: all build clean clobber
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/ProtocolFamily.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.net;
+
+/**
+ * Represents a family of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public interface ProtocolFamily {
+ /**
+ * Returns the name of the protocol family.
+ */
+ String name();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/SocketOption.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.net;
+
+/**
+ * A socket option associated with a socket.
+ *
+ * <p> In the {@link java.nio.channels channels} package, the {@link
+ * java.nio.channels.NetworkChannel} interface defines the {@link
+ * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption}
+ * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption}
+ * methods to set and query the channel's socket options.
+ *
+ * @param <T> The type of the socket option value.
+ *
+ * @since 1.7
+ *
+ * @see StandardSocketOption
+ */
+
+public interface SocketOption<T> {
+
+ /**
+ * Returns the name of the socket option.
+ */
+ String name();
+
+ /**
+ * Returns the type of the socket option value.
+ */
+ Class<T> type();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/StandardProtocolFamily.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.net;
+
+/**
+ * Defines the standard family of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public enum StandardProtocolFamily implements ProtocolFamily {
+
+ /**
+ * Internet Protocol Version 4 (IPv4)
+ */
+ INET,
+
+ /**
+ * Internet Protocol Version 6 (IPv6)
+ */
+ INET6
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/net/StandardSocketOption.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.net;
+
+/**
+ * Defines the <em>standard</em> socket options.
+ *
+ * <p> The {@link SocketOption#name name} of each socket option defined by this
+ * class is its field name.
+ *
+ * <p> In this release, the socket options defined here are used by {@link
+ * java.nio.channels.NetworkChannel network} channels in the {@link
+ * java.nio.channels channels} package.
+ *
+ * @since 1.7
+ */
+
+public final class StandardSocketOption {
+ private StandardSocketOption() { }
+
+ // -- SOL_SOCKET --
+
+ /**
+ * Allow transmission of broadcast datagrams.
+ *
+ * <p> The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. The option is specific to
+ * datagram-oriented sockets sending to {@link java.net.Inet4Address IPv4}
+ * broadcast addresses. When the socket option is enabled then the socket
+ * can be used to send <em>broadcast datagrams</em>.
+ *
+ * <p> The initial value of this socket option is {@code FALSE}. The socket
+ * option may be enabled or disabled at any time. Some operating systems may
+ * require that the Java virtual machine be started with implementation
+ * specific privileges to enable this option or send broadcast datagrams.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc919.txt">RFC&nbsp;929:
+ * Broadcasting Internet Datagrams</a>
+ */
+ public static final SocketOption<Boolean> SO_BROADCAST =
+ new StdSocketOption<Boolean>("SO_BROADCAST", Boolean.class);
+
+ /**
+ * Keep connection alive.
+ *
+ * <p> The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE}
+ * option is enabled the operating system may use a <em>keep-alive</em>
+ * mechanism to periodically probe the other end of a connection when the
+ * connection is otherwise idle. The exact semantics of the keep alive
+ * mechanism is system dependent and therefore unspecified.
+ *
+ * <p> The initial value of this socket option is {@code FALSE}. The socket
+ * option may be enabled or disabled at any time.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122
+ * Requirements for Internet Hosts -- Communication Layers</a>
+ */
+ public static final SocketOption<Boolean> SO_KEEPALIVE =
+ new StdSocketOption<Boolean>("SO_KEEPALIVE", Boolean.class);
+
+ /**
+ * The size of the socket send buffer.
+ *
+ * <p> The value of this socket option is an {@code Integer} that is the
+ * size of the socket send buffer in bytes. The socket send buffer is an
+ * output buffer used by the networking implementation. It may need to be
+ * increased for high-volume connections. The value of the socket option is
+ * a <em>hint</em> to the implementation to size the buffer and the actual
+ * size may differ. The socket option can be queried to retrieve the actual
+ * size.
+ *
+ * <p> For datagram-oriented sockets, the size of the send buffer may limit
+ * the size of the datagrams that may be sent by the socket. Whether
+ * datagrams larger than the buffer size are sent or discarded is system
+ * dependent.
+ *
+ * <p> The initial/default size of the socket send buffer and the range of
+ * allowable values is system dependent although a negative size is not
+ * allowed. An attempt to set the socket send buffer to larger than its
+ * maximum size causes it to be set to its maximum size.
+ *
+ * <p> An implementation allows this socket option to be set before the
+ * socket is bound or connected. Whether an implementation allows the
+ * socket send buffer to be changed after the socket is bound is system
+ * dependent.
+ */
+ public static final SocketOption<Integer> SO_SNDBUF =
+ new StdSocketOption<Integer>("SO_SNDBUF", Integer.class);
+
+
+ /**
+ * The size of the socket receive buffer.
+ *
+ * <p> The value of this socket option is an {@code Integer} that is the
+ * size of the socket receive buffer in bytes. The socket receive buffer is
+ * an input buffer used by the networking implementation. It may need to be
+ * increased for high-volume connections or decreased to limit the possible
+ * backlog of incoming data. The value of the socket option is a
+ * <em>hint</em> to the implementation to size the buffer and the actual
+ * size may differ.
+ *
+ * <p> For datagram-oriented sockets, the size of the receive buffer may
+ * limit the size of the datagrams that can be received. Whether datagrams
+ * larger than the buffer size can be received is system dependent.
+ * Increasing the socket receive buffer may be important for cases where
+ * datagrams arrive in bursts faster than they can be processed.
+ *
+ * <p> In the case of stream-oriented sockets and the TCP/IP protocol, the
+ * size of the socket receive buffer may be used when advertising the size
+ * of the TCP receive window to the remote peer.
+ *
+ * <p> The initial/default size of the socket receive buffer and the range
+ * of allowable values is system dependent although a negative size is not
+ * allowed. An attempt to set the socket receive buffer to larger than its
+ * maximum size causes it to be set to its maximum size.
+ *
+ * <p> An implementation allows this socket option to be set before the
+ * socket is bound or connected. Whether an implementation allows the
+ * socket receive buffer to be changed after the socket is bound is system
+ * dependent.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc1323.txt">RFC&nbsp;1323: TCP
+ * Extensions for High Performance</a>
+ */
+ public static final SocketOption<Integer> SO_RCVBUF =
+ new StdSocketOption<Integer>("SO_RCVBUF", Integer.class);
+
+ /**
+ * Re-use address.
+ *
+ * <p> The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. The exact semantics of this
+ * socket option are socket type and system dependent.
+ *
+ * <p> In the case of stream-oriented sockets, this socket option will
+ * usually determine whether the socket can be bound to a socket address
+ * when a previous connection involving that socket address is in the
+ * <em>TIME_WAIT</em> state. On implementations where the semantics differ,
+ * and the socket option is not required to be enabled in order to bind the
+ * socket when a previous connection is in this state, then the
+ * implementation may choose to ignore this option.
+ *
+ * <p> For datagram-oriented sockets the socket option is used to allow
+ * multiple programs bind to the same address. This option should be enabled
+ * when the socket is to be used for Internet Protocol (IP) multicasting.
+ *
+ * <p> An implementation allows this socket option to be set before the
+ * socket is bound or connected. Changing the value of this socket option
+ * after the socket is bound has no effect. The default value of this
+ * socket option is system dependent.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc793.txt">RFC&nbsp;793: Transmission
+ * Control Protocol</a>
+ */
+ public static final SocketOption<Boolean> SO_REUSEADDR =
+ new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
+
+ /**
+ * Linger on close if data is present.
+ *
+ * <p> The value of this socket option is an {@code Integer} that controls
+ * the action taken when unsent data is queued on the socket and a method
+ * to close the socket is invoked. If the value of the socket option is zero
+ * or greater, then it represents a timeout value, in seconds, known as the
+ * <em>linger interval</em>. The linger interval is the timeout for the
+ * {@code close} method to block while the operating system attempts to
+ * transmit the unsent data or it decides that it is unable to transmit the
+ * data. If the value of the socket option is less than zero then the option
+ * is disabled. In that case the {@code close} method does not wait until
+ * unsent data is transmitted; if possible the operating system will transmit
+ * any unsent data before the connection is closed.
+ *
+ * <p> This socket option is intended for use with sockets that are configured
+ * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode
+ * only. The behavior of the {@code close} method when this option is
+ * enabled on a non-blocking socket is not defined.
+ *
+ * <p> The initial value of this socket option is a negative value, meaning
+ * that the option is disabled. The option may be enabled, or the linger
+ * interval changed, at any time. The maximum value of the linger interval
+ * is system dependent. Setting the linger interval to a value that is
+ * greater than its maximum value causes the linger interval to be set to
+ * its maximum value.
+ */
+ public static final SocketOption<Integer> SO_LINGER =
+ new StdSocketOption<Integer>("SO_LINGER", Integer.class);
+
+
+ // -- IPPROTO_IP --
+
+ /**
+ * The Type of Service (ToS) octet in the Internet Protocol (IP) header.
+ *
+ * <p> The value of this socket option is an {@code Integer}, the least
+ * significant 8 bits of which represents the value of the ToS octet in IP
+ * packets sent by sockets to an {@link StandardProtocolFamily#INET IPv4}
+ * socket. The interpretation of the ToS octet is network specific and
+ * is not defined by this class. Further information on the ToS octet can be
+ * found in <a href="http://www.ietf.org/rfc/rfc1349.txt">RFC&nbsp;1349</a>
+ * and <a href="http://www.ietf.org/rfc/rfc2474.txt">RFC&nbsp;2474</a>. The
+ * value of the socket option is a <em>hint</em>. An implementation may
+ * ignore the value, or ignore specific values.
+ *
+ * <p> The initial/default value of the TOS field in the ToS octet is
+ * implementation specific but will typically be {@code 0}. For
+ * datagram-oriented sockets the option may be configured at any time after
+ * the socket has been bound. The new value of the octet is used when sending
+ * subsequent datagrams. It is system dependent whether this option can be
+ * queried or changed prior to binding the socket.
+ *
+ * <p> The behavior of this socket option on a stream-oriented socket, or an
+ * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this
+ * release.
+ */
+ public static final SocketOption<Integer> IP_TOS =
+ new StdSocketOption<Integer>("IP_TOS", Integer.class);
+
+ /**
+ * The network interface for Internet Protocol (IP) multicast datagrams.
+ *
+ * <p> The value of this socket option is a {@link NetworkInterface} that
+ * represents the outgoing interface for multicast datagrams sent by the
+ * datagram-oriented socket. For {@link StandardProtocolFamily#INET6 IPv6}
+ * sockets then it is system dependent whether setting this option also
+ * sets the outgoing interface for multlicast datagrams sent to IPv4
+ * addresses.
+ *
+ * <p> The initial/default value of this socket option may be {@code null}
+ * to indicate that outgoing interface will be selected by the operating
+ * system, typically based on the network routing tables. An implementation
+ * allows this socket option to be set after the socket is bound. Whether
+ * the socket option can be queried or changed prior to binding the socket
+ * is system dependent.
+ *
+ * @see java.nio.channels.MulticastChannel
+ */
+ public static final SocketOption<NetworkInterface> IP_MULTICAST_IF =
+ new StdSocketOption<NetworkInterface>("IP_MULTICAST_IF", NetworkInterface.class);
+
+ /**
+ * The <em>time-to-live</em> for Internet Protocol (IP) multicast datagrams.
+ *
+ * <p> The value of this socket option is an {@code Integer} in the range
+ * <tt>0&nbsp;<=&nbsp;value&nbsp;<=&nbsp;255</tt>. It is used to control
+ * the scope of multicast datagrams sent by the datagram-oriented socket.
+ * In the case of an {@link StandardProtocolFamily#INET IPv4} socket
+ * the option is the time-to-live (TTL) on multicast datagrams sent by the
+ * socket. Datagrams with a TTL of zero are not transmitted on the network
+ * but may be delivered locally. In the case of an {@link
+ * StandardProtocolFamily#INET6 IPv6} socket the option is the
+ * <em>hop limit</em> which is number of <em>hops</em> that the datagram can
+ * pass through before expiring on the network. For IPv6 sockets it is
+ * system dependent whether the option also sets the <em>time-to-live</em>
+ * on multicast datagrams sent to IPv4 addresses.
+ *
+ * <p> The initial/default value of the time-to-live setting is typically
+ * {@code 1}. An implementation allows this socket option to be set after
+ * the socket is bound. Whether the socket option can be queried or changed
+ * prior to binding the socket is system dependent.
+ *
+ * @see java.nio.channels.MulticastChannel
+ */
+ public static final SocketOption<Integer> IP_MULTICAST_TTL =
+ new StdSocketOption<Integer>("IP_MULTICAST_TTL", Integer.class);
+
+ /**
+ * Loopback for Internet Protocol (IP) multicast datagrams.
+ *
+ * <p> The value of this socket option is a {@code Boolean} that controls
+ * the <em>loopback</em> of multicast datagrams. The value of the socket
+ * option represents if the option is enabled or disabled.
+ *
+ * <p> The exact semantics of this socket options are system dependent.
+ * In particular, it is system dependent whether the loopback applies to
+ * multicast datagrams sent from the socket or received by the socket.
+ * For {@link StandardProtocolFamily#INET6 IPv6} sockets then it is
+ * system dependent whether the option also applies to multicast datagrams
+ * sent to IPv4 addresses.
+ *
+ * <p> The initial/default value of this socket option is {@code TRUE}. An
+ * implementation allows this socket option to be set after the socket is
+ * bound. Whether the socket option can be queried or changed prior to
+ * binding the socket is system dependent.
+ *
+ * @see java.nio.channels.MulticastChannel
+ */
+ public static final SocketOption<Boolean> IP_MULTICAST_LOOP =
+ new StdSocketOption<Boolean>("IP_MULTICAST_LOOP", Boolean.class);
+
+
+ // -- IPPROTO_TCP --
+
+ /**
+ * Disable the Nagle algorithm.
+ *
+ * <p> The value of this socket option is a {@code Boolean} that represents
+ * whether the option is enabled or disabled. The socket option is specific to
+ * stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an algorithm
+ * known as <em>The Nagle Algorithm</em> to coalesce short segments and
+ * improve network efficiency.
+ *
+ * <p> The default value of this socket option is {@code FALSE}. The
+ * socket option should only be enabled in cases where it is known that the
+ * coalescing impacts performance. The socket option may be enabled at any
+ * time. In other words, the Nagle Algorithm can be disabled. Once the option
+ * is enabled, it is system dependent whether it can be subsequently
+ * disabled. In that case, invoking the {@code setOption} method to disable
+ * the option has no effect.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122:
+ * Requirements for Internet Hosts -- Communication Layers</a>
+ */
+ public static final SocketOption<Boolean> TCP_NODELAY =
+ new StdSocketOption<Boolean>("TCP_NODELAY", Boolean.class);
+
+
+ private static class StdSocketOption<T> implements SocketOption<T> {
+ private final String name;
+ private final Class<T> type;
+ StdSocketOption(String name, Class<T> type) {
+ this.name = name;
+ this.type = type;
+ }
+ @Override public String name() { return name; }
+ @Override public Class<T> type() { return type; }
+ @Override public String toString() { return name; }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/MembershipKey.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * A token representing the membership of an Internet Protocol (IP) multicast
+ * group.
+ *
+ * <p> A membership key may represent a membership to receive all datagrams sent
+ * to the group, or it may be <em>source-specific</em>, meaning that it
+ * represents a membership that receives only datagrams from a specific source
+ * address. Whether or not a membership key is source-specific may be determined
+ * by invoking its {@link #getSourceAddress() getSourceAddress} method.
+ *
+ * <p> A membership key is valid upon creation and remains valid until the
+ * membership is dropped by invoking the {@link #drop() drop} method, or
+ * the channel is closed. The validity of the membership key may be tested
+ * by invoking its {@link #isValid() isValid} method.
+ *
+ * <p> Where a membership key is not source-specific and the underlying operation
+ * system supports source filtering, then the {@link #block block} and {@link
+ * #unblock unblock} methods can be used to block or unblock multicast datagrams
+ * from particular source addresses.
+ *
+ * @see MulticastChannel
+ *
+ * @since 1.7
+ */
+public abstract class MembershipKey {
+
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected MembershipKey() {
+ }
+
+ /**
+ * Tells whether or not this membership is valid.
+ *
+ * <p> A multicast group membership is valid upon creation and remains
+ * valid until the membership is dropped by invoking the {@link #drop() drop}
+ * method, or the channel is closed.
+ *
+ * @return {@code true} if this membership key is valid, {@code false}
+ * otherwise
+ */
+ public abstract boolean isValid();
+
+ /**
+ * Drop membership.
+ *
+ * <p> If the membership key represents a membership to receive all datagrams
+ * then the membership is dropped and the channel will no longer receive any
+ * datagrams sent to the group. If the membership key is source-specific
+ * then the channel will no longer receive datagrams sent to the group from
+ * that source address.
+ *
+ * <p> After membership is dropped it may still be possible to receive
+ * datagrams sent to the group. This can arise when datagrams are waiting to
+ * be received in the socket's receive buffer. After membership is dropped
+ * then the channel may {@link MulticastChannel#join join} the group again
+ * in which case a new membership key is returned.
+ *
+ * <p> Upon return, this membership object will be {@link #isValid() invalid}.
+ * If the multicast group membership is already invalid then invoking this
+ * method has no effect. Once a multicast group membership is invalid,
+ * it remains invalid forever.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract void drop() throws IOException;
+
+ /**
+ * Block multicast datagrams from the given source address.
+ *
+ * <p> If this membership key is not source-specific, and the underlying
+ * operating system supports source filtering, then this method blocks
+ * multicast datagrams from the given source address. If the given source
+ * address is already blocked then this method has no effect.
+ * After a source address is blocked it may still be possible to receive
+ * datagams from that source. This can arise when datagrams are waiting to
+ * be received in the socket's receive buffer.
+ *
+ * @param source
+ * The source address to block
+ *
+ * @return This membership key
+ *
+ * @throws IllegalArgumentException
+ * If the {@code source} parameter is not a unicast address or
+ * is not the same address type as the multicast group
+ * @throws IllegalStateException
+ * If this membership key is source-specific or is no longer valid
+ * @throws UnsupportedOperationException
+ * If the underlying operating system does not support source
+ * filtering
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract MembershipKey block(InetAddress source) throws IOException;
+
+ /**
+ * Unblock multicast datagrams from the given source address that was
+ * previously blocked using the {@link #block(InetAddress) block} method.
+ *
+ * @param source
+ * The source address to unblock
+ *
+ * @return This membership key
+ *
+ * @throws IllegalStateException
+ * If the given source address is not currently blocked or the
+ * membership key is no longer valid
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract MembershipKey unblock(InetAddress source) throws IOException;
+
+ /**
+ * Returns the channel for which this membership key was created. This
+ * method will continue to return the channel even after the membership
+ * becomes {@link #isValid invalid}.
+ *
+ * @return the channel
+ */
+ public abstract MulticastChannel getChannel();
+
+ /**
+ * Returns the multicast group for which this membership key was created.
+ * This method will continue to return the group even after the membership
+ * becomes {@link #isValid invalid}.
+ *
+ * @return the multicast group
+ */
+ public abstract InetAddress getGroup();
+
+ /**
+ * Returns the network interface for which this membership key was created.
+ * This method will continue to return the network interface even after the
+ * membership becomes {@link #isValid invalid}.
+ *
+ * @return the network interface
+ */
+ public abstract NetworkInterface getNetworkInterface();
+
+ /**
+ * Returns the source address if this membership key is source-specific,
+ * or {@code null} if this membership is not source-specific.
+ *
+ * @return The source address if this membership key is source-specific,
+ * otherwise {@code null}
+ */
+ public abstract InetAddress getSourceAddress();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/MulticastChannel.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.net.ProtocolFamily; // javadoc
+import java.net.StandardProtocolFamily; // javadoc
+import java.net.StandardSocketOption; // javadoc
+
+/**
+ * A network channel that supports Internet Protocol (IP) multicasting.
+ *
+ * <p> IP multicasting is the transmission of IP datagrams to members of
+ * a <em>group</em> that is zero or more hosts identified by a single destination
+ * address.
+ *
+ * <p> In the case of a channel to an {@link StandardProtocolFamily#INET IPv4} socket,
+ * the underlying operating system supports <a href="http://www.ietf.org/rfc/rfc2236.txt">
+ * <i>RFC&nbsp;2236: Internet Group Management Protocol, Version 2 (IGMPv2)</i></a>.
+ * It may optionally support source filtering as specified by <a
+ * href="http://www.ietf.org/rfc/rfc3376.txt"> <i>RFC&nbsp;3376: Internet Group
+ * Management Protocol, Version 3 (IGMPv3)</i></a>.
+ * For channels to an {@link StandardProtocolFamily#INET6 IPv6} socket, the equivalent
+ * standards are <a href="http://www.ietf.org/rfc/rfc2710.txt"> <i>RFC&nbsp;2710:
+ * Multicast Listener Discovery (MLD) for IPv6</i></a> and <a
+ * href="http://www.ietf.org/rfc/rfc3810.txt"> <i>RFC&nbsp;3810: Multicast Listener
+ * Discovery Version 2 (MLDv2) for IPv6</i></a>.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface)} method is used to
+ * join a group and receive all multicast datagrams sent to the group. A channel
+ * may join several multicast groups and may join the same group on several
+ * {@link NetworkInterface interfaces}. Membership is dropped by invoking the {@link
+ * MembershipKey#drop drop} method on the returned {@link MembershipKey}. If the
+ * underlying platform supports source filtering then the {@link MembershipKey#block
+ * block} and {@link MembershipKey#unblock unblock} methods can be used to block or
+ * unblock multicast datagrams from particular source addresses.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface,InetAddress)} method
+ * is used to begin receiving datagrams sent to a group whose source address matches
+ * a given source address. This method throws {@link UnsupportedOperationException}
+ * if the underlying platform does not support source filtering. Membership is
+ * <em>cumulative</em> and this method may be invoked again with the same group
+ * and interface to allow receiving datagrams from other source addresses. The
+ * method returns a {@link MembershipKey} that represents membership to receive
+ * datagrams from the given source address. Invoking the key's {@link
+ * MembershipKey#drop drop} method drops membership so that datagrams from the
+ * source address can no longer be received.
+ *
+ * <h4>Platform dependencies</h4>
+ *
+ * The multicast implementation is intended to map directly to the native
+ * multicasting facility. Consequently, the following items should be considered
+ * when developing an application that receives IP multicast datagrams:
+ *
+ * <ol>
+ *
+ * <li><p> The creation of the channel should specify the {@link ProtocolFamily}
+ * that corresponds to the address type of the multicast groups that the channel
+ * will join. There is no guarantee that a channel to a socket in one protocol
+ * family can join and receive multicast datagrams when the address of the
+ * multicast group corresponds to another protocol family. For example, it is
+ * implementation specific if a channel to an {@link StandardProtocolFamily#INET6 IPv6}
+ * socket can join an {@link StandardProtocolFamily#INET IPv4} multicast group and receive
+ * multicast datagrams sent to the group. </p></li>
+ *
+ * <li><p> The channel's socket should be bound to the {@link
+ * InetAddress#isAnyLocalAddress wildcard} address. If the socket is bound to
+ * a specific address, rather than the wildcard address then it is implementation
+ * specific if multicast datagrams are received by the socket. </p></li>
+ *
+ * <li><p> The {@link StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} option should be
+ * enabled prior to {@link NetworkChannel#bind binding} the socket. This is
+ * required to allow multiple members of the group to bind to the same
+ * address. </p></li>
+ *
+ * </ol>
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ * // join multicast group on this interface, and also use this
+ * // interface for outgoing multicast datagrams
+ * NetworkInterface ni = NetworkInterface.getByName("hme0");
+ *
+ * DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+ * .setOption(StandardSocketOption.SO_REUSEADDR, true)
+ * .bind(new InetSocketAddress(5000))
+ * .setOption(StandardSocketOption.IP_MULTICAST_IF, ni);
+ *
+ * InetAddress group = InetAddress.getByName("225.4.5.6");
+ *
+ * MembershipKey key = dc.join(group, ni);
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface MulticastChannel
+ extends NetworkChannel
+{
+ /**
+ * Joins a multicast group to begin receiving all datagrams sent to the group,
+ * returning a membership key.
+ *
+ * <p> If this channel is currently a member of the group on the given
+ * interface to receive all datagrams then the membership key, representing
+ * that membership, is returned. Otherwise this channel joins the group and
+ * the resulting new membership key is returned. The resulting membership key
+ * is not {@link MembershipKey#getSourceAddress source-specific}.
+ *
+ * <p> A multicast channel may join several multicast groups, including
+ * the same group on more than one interface. An implementation may impose a
+ * limit on the number of groups that may be joined at the same time.
+ *
+ * @param group
+ * The multicast address to join
+ * @param interf
+ * The network interface on which to join the group
+ *
+ * @return The membership key
+ *
+ * @throws IllegalArgumentException
+ * If the group parameter is not a {@link InetAddress#isMulticastAddress
+ * multicast} address, or the group parameter is an address type
+ * that is not supported by this channel
+ * @throws IllegalStateException
+ * If the channel already has source-specific membership of the
+ * group on the interface
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws SecurityException
+ * If a security manager is set, and its
+ * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+ * method denies access to the multiast group
+ */
+ MembershipKey join(InetAddress group, NetworkInterface interf)
+ throws IOException;
+
+ /**
+ * Joins a multicast group to begin receiving datagrams sent to the group
+ * from a given source address.
+ *
+ * <p> If this channel is currently a member of the group on the given
+ * interface to receive datagrams from the given source address then the
+ * membership key, representing that membership, is returned. Otherwise this
+ * channel joins the group and the resulting new membership key is returned.
+ * The resulting membership key is {@link MembershipKey#getSourceAddress
+ * source-specific}.
+ *
+ * <p> Membership is <em>cumulative</em> and this method may be invoked
+ * again with the same group and interface to allow receiving datagrams sent
+ * by other source addresses to the group.
+ *
+ * @param group
+ * The multicast address to join
+ * @param interf
+ * The network interface on which to join the group
+ * @param source
+ * The source address
+ *
+ * @return The membership key
+ *
+ * @throws IllegalArgumentException
+ * If the group parameter is not a {@link
+ * InetAddress#isMulticastAddress multicast} address, the
+ * source parameter is not a unicast address, the group
+ * parameter is an address type that is not supported by this channel,
+ * or the source parameter is not the same address type as the group
+ * @throws IllegalStateException
+ * If the channel is currently a member of the group on the given
+ * interface to receive all datagrams
+ * @throws UnsupportedOperationException
+ * If the underlying operation system does not support source filtering
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws SecurityException
+ * If a security manager is set, and its
+ * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+ * method denies access to the multiast group
+ */
+ MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+ throws IOException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/NetworkChannel.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A channel to a network socket.
+ *
+ * <p> A channel that implements this interface is a channel to a network
+ * socket. The {@link #bind(SocketAddress) bind} method is used to bind the
+ * socket to a local {@link SocketAddress address}, the {@link #getLocalAddress()
+ * getLocalAddress} method returns the address that the socket is bound to, and
+ * the {@link #setOption(SocketOption,Object) setOption} and {@link
+ * #getOption(SocketOption) getOption} methods are used to set and query socket
+ * options. An implementation of this interface should specify the socket options
+ * that it supports.
+ *
+ * <p> The {@link #bind bind} and {@link #setOption setOption} methods that do
+ * not otherwise have a value to return are specified to return the network
+ * channel upon which they are invoked. This allows method invocations to be
+ * chained. Implementations of this interface should specialize the return type
+ * so that method invocations on the implementation class can be chained.
+ *
+ * @since 1.7
+ */
+
+public interface NetworkChannel
+ extends Channel
+{
+ /**
+ * Binds the channel's socket to a local address.
+ *
+ * <p> This method is used to establish an association between the socket and
+ * a local address. Once an association is established then the socket remains
+ * bound until the channel is closed. If the {@code local} parameter has the
+ * value {@code null} then the socket will be bound to an address that is
+ * assigned automatically.
+ *
+ * @param local
+ * The address to bind the socket, or {@code null} to bind the socket
+ * to an automatically assigned socket address
+ *
+ * @return This channel
+ *
+ * @throws AlreadyBoundException
+ * If the socket is already bound
+ * @throws UnsupportedAddressTypeException
+ * If the type of the given address is not supported
+ * @throws ClosedChannelException
+ * If the channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ * @throws SecurityException
+ * If a security manager is installed and it denies an unspecified
+ * permission. An implementation of this interface should specify
+ * any required permissions.
+ *
+ * @see #getLocalAddress
+ */
+ NetworkChannel bind(SocketAddress local) throws IOException;
+
+ /**
+ * Returns the socket address that this channel's socket is bound to, or
+ * {@code null} if the socket is not bound.
+ *
+ * <p> Where the channel is {@link #bind bound} to an Internet Protocol
+ * socket address then the return value from this method is of type {@link
+ * java.net.InetSocketAddress}.
+ *
+ * @return The socket address that the socket is bound to, or {@code null}
+ * if the channel is not {@link #isOpen open} or the channel's socket
+ * is not bound
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ SocketAddress getLocalAddress() throws IOException;
+
+ /**
+ * Sets the value of a socket option.
+ *
+ * @param name
+ * The socket option
+ * @param value
+ * The value of the socket option. A value of {@code null} may be
+ * a valid value for some socket options.
+ *
+ * @return This channel
+ *
+ * @throws IllegalArgumentException
+ * If the socket option is not supported by this channel, or
+ * the value is not a valid value for this socket option
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @see java.net.StandardSocketOption
+ */
+ <T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException;
+
+ /**
+ * Returns the value of a socket option.
+ *
+ * @param name
+ * The socket option
+ *
+ * @return The value of the socket option. A value of {@code null} may be
+ * a valid value for some socket options.
+ *
+ * @throws IllegalArgumentException
+ * If the socket option is not supported by this channel
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @see java.net.StandardSocketOption
+ */
+ <T> T getOption(SocketOption<T> name) throws IOException;
+
+ /**
+ * Returns a set of the socket options supported by this channel.
+ *
+ * <p> This method will continue to return the set of options even after the
+ * channel has been closed.
+ *
+ * @return A set of the socket options supported by this channel
+ */
+ Set<SocketOption<?>> options();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/channels/package-info.java Sun Aug 31 18:39:01 2008 +0100
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2001-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * Defines channels, which represent connections to entities that are capable of
+ * performing I/O operations, such as files and sockets; defines selectors, for
+ * multiplexed, non-blocking I/O operations.
+ *
+ * <a name="channels"></a>
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists channels and their descriptions">
+ * <tr><th><p align="left">Channels</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt><i>{@link java.nio.channels.Channel}</i></tt></td>
+ * <td>A nexus for I/O operations</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ReadableByteChannel}</i></tt></td>
+ * <td>Can read into a buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.ScatteringByteChannel}&nbsp;&nbsp;</i></tt></td>
+ * <td>Can read into a sequence of&nbsp;buffers</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.WritableByteChannel}</i></tt></td>
+ * <td>Can write from a buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.GatheringByteChannel}</i></tt></td>
+ * <td>Can write from a sequence of&nbsp;buffers</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ByteChannel}</i></tt></td>
+ * <td>Can read/write to/from a&nbsp;buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.SeekableByteChannel}</i></tt></td>
+ * <td>A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.NetworkChannel}</i></tt></td>
+ * <td>A channel to a network socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.MulticastChannel}</i></tt></td>
+ * <td>Can join Internet Protocol (IP) multicast groups</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Channels}</tt></td>
+ * <td>Utility methods for channel/stream interoperation</td></tr>
+ * </table></blockquote>
+ *
+ * <p> A <i>channel</i> represents an open connection to an entity such as a
+ * hardware device, a file, a network socket, or a program component that is
+ * capable of performing one or more distinct I/O operations, for example reading
+ * or writing. As specified in the {@link java.nio.channels.Channel} interface,
+ * channels are either open or closed, and they are both <i>asynchronously
+ * closeable</i> and <i>interruptible</i>.
+ *
+ * <p> The {@link java.nio.channels.Channel} interface is extended by several
+ * other interfaces.
+ *
+ * <p> The {@link java.nio.channels.ReadableByteChannel} interface specifies a
+ * {@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes
+ * from the channel into a buffer; similarly, the {@link
+ * java.nio.channels.WritableByteChannel} interface specifies a {@link
+ * java.nio.channels.WritableByteChannel#write write} method that writes bytes
+ * from a buffer to the channel. The {@link java.nio.channels.ByteChannel}
+ * interface unifies these two interfaces for the common case of channels that can
+ * both read and write bytes. The {@link java.nio.channels.SeekableByteChannel}
+ * interface extends the {@code ByteChannel} interface with methods to {@link
+ * java.nio.channels.SeekableByteChannel#position() query} and {@link
+ * java.nio.channels.SeekableByteChannel#position(long) modify} the channel's
+ * current position, and its {@link java.nio.channels.SeekableByteChannel#size
+ * size}.
+ *
+ * <p> The {@link java.nio.channels.ScatteringByteChannel} and {@link
+ * java.nio.channels.GatheringByteChannel} interfaces extend the {@link
+ * java.nio.channels.ReadableByteChannel} and {@link
+ * java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link
+ * java.nio.channels.ScatteringByteChannel#read read} and {@link
+ * java.nio.channels.GatheringByteChannel#write write} methods that take a
+ * sequence of buffers rather than a single buffer.
+ *
+ * <p> The {@link java.nio.channels.NetworkChannel} interface specifies methods
+ * to {@link java.nio.channels.NetworkChannel#bind bind} the channel's socket,
+ * obtain the address to which the socket is bound, and methods to {@link
+ * java.nio.channels.NetworkChannel#getOption get} and {@link
+ * java.nio.channels.NetworkChannel#setOption set} socket options. The {@link
+ * java.nio.channels.MulticastChannel} interface specifies methods to join
+ * Internet Protocol (IP) multicast groups.
+ *
+ * <p> The {@link java.nio.channels.Channels} utility class defines static methods
+ * that support the interoperation of the stream classes of the <tt>{@link
+ * java.io}</tt> package with the channel classes of this package. An appropriate
+ * channel can be constructed from an {@link java.io.InputStream} or an {@link
+ * java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an
+ * {@link java.io.OutputStream} can be constructed from a channel. A {@link
+ * java.io.Reader} can be constructed that uses a given charset to decode bytes
+ * from a given readable byte channel, and conversely a {@link java.io.Writer} can
+ * be constructed that uses a given charset to encode characters into bytes and
+ * write them to a given writable byte channel.
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists file channels and their descriptions">
+ * <tr><th><p align="left">File channels</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.FileChannel}</tt></td>
+ * <td>Reads, writes, maps, and manipulates files</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.FileLock}</tt></td>
+ * <td>A lock on a (region of a) file</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.MappedByteBuffer}/{@link java.nio.MappedBigByteBuffer}&nbsp;&nbsp;</tt></td>
+ * <td>A direct byte buffer or big byte buffer mapped to a region of a&nbsp;file</td></tr>
+ * </table></blockquote>
+ *
+ * <p> The {@link java.nio.channels.FileChannel} class supports the usual
+ * operations of reading bytes from, and writing bytes to, a channel connected to
+ * a file, as well as those of querying and modifying the current file position
+ * and truncating the file to a specific size. It defines methods for acquiring
+ * locks on the whole file or on a specific region of a file; these methods return
+ * instances of the {@link java.nio.channels.FileLock} class. Finally, it defines
+ * methods for forcing updates to the file to be written to the storage device that
+ * contains it, for efficiently transferring bytes between the file and other
+ * channels, and for mapping a region of the file directly into memory.
+ *
+ * <p> A {@code FileChannel} is created by invoking one of its static {@link
+ * java.nio.channels.FileChannel#open open} methods, or by invoking the {@code
+ * getChannel} method of a {@link java.io.FileInputStream}, {@link
+ * java.io.FileOutputStream}, or {@link java.io.RandomAccessFile} to return a
+ * file channel connected to the same underlying file as the <tt>{@link java.io}</tt>
+ * class.
+ *
+ * <a name="multiplex"></a>
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists multi