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