0N/A/*
4963N/A * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.nio.ch;
0N/A
0N/Aimport java.io.FileDescriptor;
0N/Aimport java.io.IOException;
0N/Aimport java.net.*;
0N/Aimport java.nio.ByteBuffer;
0N/Aimport java.nio.channels.*;
0N/Aimport java.nio.channels.spi.*;
524N/Aimport java.util.*;
3788N/Aimport sun.net.ResourceManager;
0N/A
0N/A
0N/A/**
0N/A * An implementation of DatagramChannels.
0N/A */
0N/A
0N/Aclass DatagramChannelImpl
0N/A extends DatagramChannel
0N/A implements SelChImpl
0N/A{
0N/A
0N/A // Used to make native read and write calls
0N/A private static NativeDispatcher nd = new DatagramDispatcher();
0N/A
0N/A // Our file descriptor
524N/A private final FileDescriptor fd;
0N/A
0N/A // fd value needed for dev/poll. This value will remain valid
0N/A // even after the value in the file descriptor object has been set to -1
524N/A private final int fdVal;
524N/A
524N/A // The protocol family of the socket
524N/A private final ProtocolFamily family;
0N/A
0N/A // IDs of native threads doing reads and writes, for signalling
0N/A private volatile long readerThread = 0;
0N/A private volatile long writerThread = 0;
0N/A
0N/A // Cached InetAddress and port for unconnected DatagramChannels
0N/A // used by receive0
524N/A private InetAddress cachedSenderInetAddress;
524N/A private int cachedSenderPort;
0N/A
0N/A // Lock held by current reading or connecting thread
0N/A private final Object readLock = new Object();
0N/A
0N/A // Lock held by current writing or connecting thread
0N/A private final Object writeLock = new Object();
0N/A
0N/A // Lock held by any thread that modifies the state fields declared below
0N/A // DO NOT invoke a blocking I/O operation while holding this lock!
0N/A private final Object stateLock = new Object();
0N/A
0N/A // -- The following fields are protected by stateLock
0N/A
0N/A // State (does not necessarily increase monotonically)
0N/A private static final int ST_UNINITIALIZED = -1;
524N/A private static final int ST_UNCONNECTED = 0;
524N/A private static final int ST_CONNECTED = 1;
0N/A private static final int ST_KILLED = 2;
0N/A private int state = ST_UNINITIALIZED;
0N/A
0N/A // Binding
6319N/A private InetSocketAddress localAddress;
6319N/A private InetSocketAddress remoteAddress;
0N/A
0N/A // Our socket adaptor, if any
524N/A private DatagramSocket socket;
524N/A
524N/A // Multicast support
524N/A private MembershipRegistry registry;
0N/A
6272N/A // set true when socket is bound and SO_REUSEADDRESS is emulated
6272N/A private boolean reuseAddressEmulated;
6272N/A
6272N/A // set true/false when socket is already bound and SO_REUSEADDR is emulated
6272N/A private boolean isReuseAddress;
6272N/A
0N/A // -- End of fields protected by stateLock
0N/A
0N/A
0N/A public DatagramChannelImpl(SelectorProvider sp)
0N/A throws IOException
0N/A {
0N/A super(sp);
3788N/A ResourceManager.beforeUdpCreate();
3788N/A try {
3788N/A this.family = Net.isIPv6Available() ?
3788N/A StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
3788N/A this.fd = Net.socket(family, false);
3788N/A this.fdVal = IOUtil.fdVal(fd);
3788N/A this.state = ST_UNCONNECTED;
3788N/A } catch (IOException ioe) {
3788N/A ResourceManager.afterUdpClose();
3788N/A throw ioe;
3788N/A }
524N/A }
524N/A
3788N/A public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
3788N/A throws IOException
3788N/A {
524N/A super(sp);
524N/A if ((family != StandardProtocolFamily.INET) &&
893N/A (family != StandardProtocolFamily.INET6))
893N/A {
893N/A if (family == null)
893N/A throw new NullPointerException("'family' is null");
893N/A else
893N/A throw new UnsupportedOperationException("Protocol family not supported");
524N/A }
524N/A if (family == StandardProtocolFamily.INET6) {
524N/A if (!Net.isIPv6Available()) {
524N/A throw new UnsupportedOperationException("IPv6 not available");
524N/A }
524N/A }
524N/A this.family = family;
524N/A this.fd = Net.socket(family, false);
0N/A this.fdVal = IOUtil.fdVal(fd);
0N/A this.state = ST_UNCONNECTED;
0N/A }
0N/A
0N/A public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
0N/A throws IOException
0N/A {
0N/A super(sp);
524N/A this.family = Net.isIPv6Available() ?
524N/A StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
0N/A this.fd = fd;
0N/A this.fdVal = IOUtil.fdVal(fd);
0N/A this.state = ST_UNCONNECTED;
524N/A this.localAddress = Net.localAddress(fd);
0N/A }
0N/A
0N/A public DatagramSocket socket() {
0N/A synchronized (stateLock) {
0N/A if (socket == null)
0N/A socket = DatagramSocketAdaptor.create(this);
0N/A return socket;
0N/A }
0N/A }
0N/A
524N/A @Override
524N/A public SocketAddress getLocalAddress() throws IOException {
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
893N/A throw new ClosedChannelException();
6319N/A return Net.getRevealedLocalAddress(localAddress);
524N/A }
524N/A }
524N/A
524N/A @Override
893N/A public SocketAddress getRemoteAddress() throws IOException {
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
893N/A throw new ClosedChannelException();
524N/A return remoteAddress;
524N/A }
524N/A }
524N/A
524N/A @Override
893N/A public <T> DatagramChannel setOption(SocketOption<T> name, T value)
524N/A throws IOException
524N/A {
524N/A if (name == null)
524N/A throw new NullPointerException();
893N/A if (!supportedOptions().contains(name))
893N/A throw new UnsupportedOperationException("'" + name + "' not supported");
524N/A
524N/A synchronized (stateLock) {
524N/A ensureOpen();
524N/A
4216N/A if (name == StandardSocketOptions.IP_TOS) {
524N/A // IPv4 only; no-op for IPv6
524N/A if (family == StandardProtocolFamily.INET) {
524N/A Net.setSocketOption(fd, family, name, value);
524N/A }
524N/A return this;
524N/A }
524N/A
4216N/A if (name == StandardSocketOptions.IP_MULTICAST_TTL ||
4216N/A name == StandardSocketOptions.IP_MULTICAST_LOOP)
524N/A {
524N/A // options are protocol dependent
524N/A Net.setSocketOption(fd, family, name, value);
524N/A return this;
524N/A }
524N/A
4216N/A if (name == StandardSocketOptions.IP_MULTICAST_IF) {
524N/A if (value == null)
524N/A throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'");
524N/A NetworkInterface interf = (NetworkInterface)value;
524N/A if (family == StandardProtocolFamily.INET6) {
524N/A int index = interf.getIndex();
524N/A if (index == -1)
524N/A throw new IOException("Network interface cannot be identified");
524N/A Net.setInterface6(fd, index);
524N/A } else {
524N/A // need IPv4 address to identify interface
524N/A Inet4Address target = Net.anyInet4Address(interf);
524N/A if (target == null)
524N/A throw new IOException("Network interface not configured for IPv4");
524N/A int targetAddress = Net.inet4AsInt(target);
524N/A Net.setInterface4(fd, targetAddress);
524N/A }
524N/A return this;
524N/A }
6272N/A if (name == StandardSocketOptions.SO_REUSEADDR &&
6272N/A Net.useExclusiveBind() && localAddress != null)
6272N/A {
6272N/A reuseAddressEmulated = true;
6272N/A this.isReuseAddress = (Boolean)value;
6272N/A }
524N/A
524N/A // remaining options don't need any special handling
524N/A Net.setSocketOption(fd, Net.UNSPEC, name, value);
524N/A return this;
524N/A }
524N/A }
524N/A
524N/A @Override
524N/A @SuppressWarnings("unchecked")
524N/A public <T> T getOption(SocketOption<T> name)
524N/A throws IOException
524N/A {
524N/A if (name == null)
524N/A throw new NullPointerException();
893N/A if (!supportedOptions().contains(name))
893N/A throw new UnsupportedOperationException("'" + name + "' not supported");
524N/A
524N/A synchronized (stateLock) {
524N/A ensureOpen();
524N/A
4216N/A if (name == StandardSocketOptions.IP_TOS) {
524N/A // IPv4 only; always return 0 on IPv6
524N/A if (family == StandardProtocolFamily.INET) {
524N/A return (T) Net.getSocketOption(fd, family, name);
524N/A } else {
524N/A return (T) Integer.valueOf(0);
524N/A }
524N/A }
524N/A
4216N/A if (name == StandardSocketOptions.IP_MULTICAST_TTL ||
4216N/A name == StandardSocketOptions.IP_MULTICAST_LOOP)
524N/A {
524N/A return (T) Net.getSocketOption(fd, family, name);
524N/A }
524N/A
4216N/A if (name == StandardSocketOptions.IP_MULTICAST_IF) {
524N/A if (family == StandardProtocolFamily.INET) {
524N/A int address = Net.getInterface4(fd);
524N/A if (address == 0)
524N/A return null; // default interface
524N/A
524N/A InetAddress ia = Net.inet4FromInt(address);
524N/A NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
524N/A if (ni == null)
524N/A throw new IOException("Unable to map address to interface");
524N/A return (T) ni;
524N/A } else {
524N/A int index = Net.getInterface6(fd);
524N/A if (index == 0)
524N/A return null; // default interface
524N/A
524N/A NetworkInterface ni = NetworkInterface.getByIndex(index);
524N/A if (ni == null)
524N/A throw new IOException("Unable to map index to interface");
524N/A return (T) ni;
524N/A }
524N/A }
524N/A
6272N/A if (name == StandardSocketOptions.SO_REUSEADDR &&
6272N/A reuseAddressEmulated)
6272N/A {
6272N/A return (T)Boolean.valueOf(isReuseAddress);
6272N/A }
6272N/A
524N/A // no special handling
524N/A return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
524N/A }
524N/A }
524N/A
893N/A private static class DefaultOptionsHolder {
524N/A static final Set<SocketOption<?>> defaultOptions = defaultOptions();
524N/A
524N/A private static Set<SocketOption<?>> defaultOptions() {
524N/A HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
4216N/A set.add(StandardSocketOptions.SO_SNDBUF);
4216N/A set.add(StandardSocketOptions.SO_RCVBUF);
4216N/A set.add(StandardSocketOptions.SO_REUSEADDR);
4216N/A set.add(StandardSocketOptions.SO_BROADCAST);
4216N/A set.add(StandardSocketOptions.IP_TOS);
4216N/A set.add(StandardSocketOptions.IP_MULTICAST_IF);
4216N/A set.add(StandardSocketOptions.IP_MULTICAST_TTL);
4216N/A set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
524N/A return Collections.unmodifiableSet(set);
524N/A }
524N/A }
524N/A
524N/A @Override
893N/A public final Set<SocketOption<?>> supportedOptions() {
893N/A return DefaultOptionsHolder.defaultOptions;
524N/A }
524N/A
0N/A private void ensureOpen() throws ClosedChannelException {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A }
0N/A
0N/A private SocketAddress sender; // Set by receive0 (## ugh)
0N/A
0N/A public SocketAddress receive(ByteBuffer dst) throws IOException {
0N/A if (dst.isReadOnly())
0N/A throw new IllegalArgumentException("Read-only buffer");
0N/A if (dst == null)
0N/A throw new NullPointerException();
0N/A synchronized (readLock) {
0N/A ensureOpen();
1021N/A // Socket was not bound before attempting receive
1021N/A if (localAddress() == null)
1021N/A bind(null);
0N/A int n = 0;
0N/A ByteBuffer bb = null;
0N/A try {
0N/A begin();
0N/A if (!isOpen())
0N/A return null;
0N/A SecurityManager security = System.getSecurityManager();
0N/A readerThread = NativeThread.current();
0N/A if (isConnected() || (security == null)) {
0N/A do {
0N/A n = receive(fd, dst);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A if (n == IOStatus.UNAVAILABLE)
0N/A return null;
0N/A } else {
0N/A bb = Util.getTemporaryDirectBuffer(dst.remaining());
0N/A for (;;) {
0N/A do {
0N/A n = receive(fd, bb);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A if (n == IOStatus.UNAVAILABLE)
0N/A return null;
0N/A InetSocketAddress isa = (InetSocketAddress)sender;
0N/A try {
0N/A security.checkAccept(
0N/A isa.getAddress().getHostAddress(),
0N/A isa.getPort());
0N/A } catch (SecurityException se) {
0N/A // Ignore packet
0N/A bb.clear();
0N/A n = 0;
0N/A continue;
0N/A }
0N/A bb.flip();
0N/A dst.put(bb);
0N/A break;
0N/A }
0N/A }
0N/A return sender;
0N/A } finally {
0N/A if (bb != null)
0N/A Util.releaseTemporaryDirectBuffer(bb);
0N/A readerThread = 0;
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private int receive(FileDescriptor fd, ByteBuffer dst)
0N/A throws IOException
0N/A {
0N/A int pos = dst.position();
0N/A int lim = dst.limit();
0N/A assert (pos <= lim);
0N/A int rem = (pos <= lim ? lim - pos : 0);
0N/A if (dst instanceof DirectBuffer && rem > 0)
0N/A return receiveIntoNativeBuffer(fd, dst, rem, pos);
0N/A
0N/A // Substitute a native buffer. If the supplied buffer is empty
0N/A // we must instead use a nonempty buffer, otherwise the call
0N/A // will not block waiting for a datagram on some platforms.
0N/A int newSize = Math.max(rem, 1);
3979N/A ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
0N/A try {
0N/A int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);
0N/A bb.flip();
0N/A if (n > 0 && rem > 0)
0N/A dst.put(bb);
0N/A return n;
0N/A } finally {
0N/A Util.releaseTemporaryDirectBuffer(bb);
0N/A }
0N/A }
0N/A
0N/A private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
0N/A int rem, int pos)
0N/A throws IOException
0N/A {
0N/A int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem,
0N/A isConnected());
0N/A if (n > 0)
0N/A bb.position(pos + n);
0N/A return n;
0N/A }
0N/A
0N/A public int send(ByteBuffer src, SocketAddress target)
0N/A throws IOException
0N/A {
0N/A if (src == null)
0N/A throw new NullPointerException();
0N/A
0N/A synchronized (writeLock) {
0N/A ensureOpen();
5697N/A InetSocketAddress isa = Net.checkAddress(target);
0N/A InetAddress ia = isa.getAddress();
0N/A if (ia == null)
0N/A throw new IOException("Target address not resolved");
0N/A synchronized (stateLock) {
0N/A if (!isConnected()) {
0N/A if (target == null)
0N/A throw new NullPointerException();
0N/A SecurityManager sm = System.getSecurityManager();
0N/A if (sm != null) {
0N/A if (ia.isMulticastAddress()) {
5697N/A sm.checkMulticast(ia);
0N/A } else {
5697N/A sm.checkConnect(ia.getHostAddress(),
0N/A isa.getPort());
0N/A }
0N/A }
0N/A } else { // Connected case; Check address then write
0N/A if (!target.equals(remoteAddress)) {
0N/A throw new IllegalArgumentException(
0N/A "Connected address not equal to target address");
0N/A }
0N/A return write(src);
0N/A }
0N/A }
0N/A
0N/A int n = 0;
0N/A try {
0N/A begin();
0N/A if (!isOpen())
0N/A return 0;
0N/A writerThread = NativeThread.current();
0N/A do {
5697N/A n = send(fd, src, isa);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
524N/A
524N/A synchronized (stateLock) {
524N/A if (isOpen() && (localAddress == null)) {
524N/A localAddress = Net.localAddress(fd);
524N/A }
524N/A }
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A writerThread = 0;
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
5697N/A private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
0N/A throws IOException
0N/A {
0N/A if (src instanceof DirectBuffer)
0N/A return sendFromNativeBuffer(fd, src, target);
0N/A
0N/A // Substitute a native buffer
0N/A int pos = src.position();
0N/A int lim = src.limit();
0N/A assert (pos <= lim);
0N/A int rem = (pos <= lim ? lim - pos : 0);
0N/A
3979N/A ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
0N/A try {
0N/A bb.put(src);
0N/A bb.flip();
0N/A // Do not update src until we see how many bytes were written
0N/A src.position(pos);
0N/A
0N/A int n = sendFromNativeBuffer(fd, bb, target);
0N/A if (n > 0) {
0N/A // now update src
0N/A src.position(pos + n);
0N/A }
0N/A return n;
0N/A } finally {
0N/A Util.releaseTemporaryDirectBuffer(bb);
0N/A }
0N/A }
0N/A
0N/A private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
5697N/A InetSocketAddress target)
0N/A throws IOException
0N/A {
0N/A int pos = bb.position();
0N/A int lim = bb.limit();
0N/A assert (pos <= lim);
0N/A int rem = (pos <= lim ? lim - pos : 0);
0N/A
524N/A boolean preferIPv6 = (family != StandardProtocolFamily.INET);
4704N/A int written;
4704N/A try {
4704N/A written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
5697N/A rem, target.getAddress(), target.getPort());
4704N/A } catch (PortUnreachableException pue) {
4704N/A if (isConnected())
4704N/A throw pue;
4704N/A written = rem;
4704N/A }
0N/A if (written > 0)
0N/A bb.position(pos + written);
0N/A return written;
0N/A }
0N/A
0N/A public int read(ByteBuffer buf) throws IOException {
0N/A if (buf == null)
0N/A throw new NullPointerException();
0N/A synchronized (readLock) {
0N/A synchronized (stateLock) {
0N/A ensureOpen();
0N/A if (!isConnected())
0N/A throw new NotYetConnectedException();
0N/A }
0N/A int n = 0;
0N/A try {
0N/A begin();
0N/A if (!isOpen())
0N/A return 0;
0N/A readerThread = NativeThread.current();
0N/A do {
6050N/A n = IOUtil.read(fd, buf, -1, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A readerThread = 0;
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
2655N/A public long read(ByteBuffer[] dsts, int offset, int length)
2655N/A throws IOException
2655N/A {
2655N/A if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
2655N/A throw new IndexOutOfBoundsException();
0N/A synchronized (readLock) {
0N/A synchronized (stateLock) {
0N/A ensureOpen();
0N/A if (!isConnected())
0N/A throw new NotYetConnectedException();
0N/A }
0N/A long n = 0;
0N/A try {
0N/A begin();
0N/A if (!isOpen())
0N/A return 0;
0N/A readerThread = NativeThread.current();
0N/A do {
2655N/A n = IOUtil.read(fd, dsts, offset, length, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A readerThread = 0;
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public int write(ByteBuffer buf) throws IOException {
0N/A if (buf == null)
0N/A throw new NullPointerException();
0N/A synchronized (writeLock) {
0N/A synchronized (stateLock) {
0N/A ensureOpen();
0N/A if (!isConnected())
0N/A throw new NotYetConnectedException();
0N/A }
0N/A int n = 0;
0N/A try {
0N/A begin();
0N/A if (!isOpen())
0N/A return 0;
0N/A writerThread = NativeThread.current();
0N/A do {
6050N/A n = IOUtil.write(fd, buf, -1, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A writerThread = 0;
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
2655N/A public long write(ByteBuffer[] srcs, int offset, int length)
2655N/A throws IOException
2655N/A {
2655N/A if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
2655N/A throw new IndexOutOfBoundsException();
0N/A synchronized (writeLock) {
0N/A synchronized (stateLock) {
0N/A ensureOpen();
0N/A if (!isConnected())
0N/A throw new NotYetConnectedException();
0N/A }
0N/A long n = 0;
0N/A try {
0N/A begin();
0N/A if (!isOpen())
0N/A return 0;
0N/A writerThread = NativeThread.current();
0N/A do {
2655N/A n = IOUtil.write(fd, srcs, offset, length, nd);
0N/A } while ((n == IOStatus.INTERRUPTED) && isOpen());
0N/A return IOStatus.normalize(n);
0N/A } finally {
0N/A writerThread = 0;
0N/A end((n > 0) || (n == IOStatus.UNAVAILABLE));
0N/A assert IOStatus.check(n);
0N/A }
0N/A }
0N/A }
0N/A
0N/A protected void implConfigureBlocking(boolean block) throws IOException {
0N/A IOUtil.configureBlocking(fd, block);
0N/A }
0N/A
0N/A public SocketAddress localAddress() {
0N/A synchronized (stateLock) {
0N/A return localAddress;
0N/A }
0N/A }
0N/A
0N/A public SocketAddress remoteAddress() {
0N/A synchronized (stateLock) {
0N/A return remoteAddress;
0N/A }
0N/A }
0N/A
524N/A @Override
524N/A public DatagramChannel bind(SocketAddress local) throws IOException {
0N/A synchronized (readLock) {
0N/A synchronized (writeLock) {
0N/A synchronized (stateLock) {
0N/A ensureOpen();
524N/A if (localAddress != null)
0N/A throw new AlreadyBoundException();
524N/A InetSocketAddress isa;
524N/A if (local == null) {
5074N/A // only Inet4Address allowed with IPv4 socket
5074N/A if (family == StandardProtocolFamily.INET) {
5074N/A isa = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
5074N/A } else {
5074N/A isa = new InetSocketAddress(0);
5074N/A }
524N/A } else {
524N/A isa = Net.checkAddress(local);
524N/A
524N/A // only Inet4Address allowed with IPv4 socket
524N/A if (family == StandardProtocolFamily.INET) {
524N/A InetAddress addr = isa.getAddress();
524N/A if (!(addr instanceof Inet4Address))
524N/A throw new UnsupportedAddressTypeException();
524N/A }
524N/A }
0N/A SecurityManager sm = System.getSecurityManager();
524N/A if (sm != null) {
0N/A sm.checkListen(isa.getPort());
524N/A }
524N/A Net.bind(family, fd, isa.getAddress(), isa.getPort());
0N/A localAddress = Net.localAddress(fd);
0N/A }
0N/A }
0N/A }
524N/A return this;
0N/A }
0N/A
0N/A public boolean isConnected() {
0N/A synchronized (stateLock) {
0N/A return (state == ST_CONNECTED);
0N/A }
0N/A }
0N/A
0N/A void ensureOpenAndUnconnected() throws IOException { // package-private
0N/A synchronized (stateLock) {
0N/A if (!isOpen())
0N/A throw new ClosedChannelException();
0N/A if (state != ST_UNCONNECTED)
0N/A throw new IllegalStateException("Connect already invoked");
0N/A }
0N/A }
0N/A
6319N/A @Override
0N/A public DatagramChannel connect(SocketAddress sa) throws IOException {
0N/A int localPort = 0;
0N/A
0N/A synchronized(readLock) {
0N/A synchronized(writeLock) {
0N/A synchronized (stateLock) {
0N/A ensureOpenAndUnconnected();
0N/A InetSocketAddress isa = Net.checkAddress(sa);
0N/A SecurityManager sm = System.getSecurityManager();
0N/A if (sm != null)
0N/A sm.checkConnect(isa.getAddress().getHostAddress(),
0N/A isa.getPort());
524N/A int n = Net.connect(family,
524N/A fd,
0N/A isa.getAddress(),
524N/A isa.getPort());
0N/A if (n <= 0)
0N/A throw new Error(); // Can't happen
0N/A
0N/A // Connection succeeded; disallow further invocation
0N/A state = ST_CONNECTED;
6319N/A remoteAddress = isa;
0N/A sender = isa;
0N/A cachedSenderInetAddress = isa.getAddress();
0N/A cachedSenderPort = isa.getPort();
524N/A
3004N/A // set or refresh local address
3004N/A localAddress = Net.localAddress(fd);
0N/A }
0N/A }
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A public DatagramChannel disconnect() throws IOException {
0N/A synchronized(readLock) {
0N/A synchronized(writeLock) {
0N/A synchronized (stateLock) {
0N/A if (!isConnected() || !isOpen())
0N/A return this;
6319N/A InetSocketAddress isa = remoteAddress;
0N/A SecurityManager sm = System.getSecurityManager();
0N/A if (sm != null)
0N/A sm.checkConnect(isa.getAddress().getHostAddress(),
0N/A isa.getPort());
5205N/A boolean isIPv6 = (family == StandardProtocolFamily.INET6);
5205N/A disconnect0(fd, isIPv6);
0N/A remoteAddress = null;
0N/A state = ST_UNCONNECTED;
3004N/A
3004N/A // refresh local address
3004N/A localAddress = Net.localAddress(fd);
0N/A }
0N/A }
0N/A }
0N/A return this;
0N/A }
0N/A
524N/A /**
524N/A * Joins channel's socket to the given group/interface and
524N/A * optional source address.
524N/A */
524N/A private MembershipKey innerJoin(InetAddress group,
524N/A NetworkInterface interf,
524N/A InetAddress source)
524N/A throws IOException
524N/A {
524N/A if (!group.isMulticastAddress())
524N/A throw new IllegalArgumentException("Group not a multicast address");
524N/A
524N/A // check multicast address is compatible with this socket
3759N/A if (group instanceof Inet4Address) {
3759N/A if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
3979N/A throw new IllegalArgumentException("IPv6 socket cannot join IPv4 multicast group");
3759N/A } else if (group instanceof Inet6Address) {
3759N/A if (family != StandardProtocolFamily.INET6)
3979N/A throw new IllegalArgumentException("Only IPv6 sockets can join IPv6 multicast group");
3759N/A } else {
3759N/A throw new IllegalArgumentException("Address type not supported");
524N/A }
524N/A
524N/A // check source address
524N/A if (source != null) {
524N/A if (source.isAnyLocalAddress())
524N/A throw new IllegalArgumentException("Source address is a wildcard address");
524N/A if (source.isMulticastAddress())
524N/A throw new IllegalArgumentException("Source address is multicast address");
524N/A if (source.getClass() != group.getClass())
524N/A throw new IllegalArgumentException("Source address is different type to group");
524N/A }
524N/A
524N/A SecurityManager sm = System.getSecurityManager();
524N/A if (sm != null)
524N/A sm.checkMulticast(group);
524N/A
524N/A synchronized (stateLock) {
524N/A if (!isOpen())
524N/A throw new ClosedChannelException();
524N/A
524N/A // check the registry to see if we are already a member of the group
524N/A if (registry == null) {
524N/A registry = new MembershipRegistry();
524N/A } else {
524N/A // return existing membership key
524N/A MembershipKey key = registry.checkMembership(group, interf, source);
524N/A if (key != null)
524N/A return key;
524N/A }
524N/A
524N/A MembershipKeyImpl key;
3759N/A if ((family == StandardProtocolFamily.INET6) &&
3759N/A ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
3759N/A {
524N/A int index = interf.getIndex();
524N/A if (index == -1)
524N/A throw new IOException("Network interface cannot be identified");
524N/A
524N/A // need multicast and source address as byte arrays
524N/A byte[] groupAddress = Net.inet6AsByteArray(group);
524N/A byte[] sourceAddress = (source == null) ? null :
524N/A Net.inet6AsByteArray(source);
524N/A
524N/A // join the group
524N/A int n = Net.join6(fd, groupAddress, index, sourceAddress);
524N/A if (n == IOStatus.UNAVAILABLE)
524N/A throw new UnsupportedOperationException();
524N/A
524N/A key = new MembershipKeyImpl.Type6(this, group, interf, source,
524N/A groupAddress, index, sourceAddress);
524N/A
524N/A } else {
524N/A // need IPv4 address to identify interface
524N/A Inet4Address target = Net.anyInet4Address(interf);
524N/A if (target == null)
524N/A throw new IOException("Network interface not configured for IPv4");
524N/A
524N/A int groupAddress = Net.inet4AsInt(group);
524N/A int targetAddress = Net.inet4AsInt(target);
524N/A int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
524N/A
524N/A // join the group
524N/A int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
524N/A if (n == IOStatus.UNAVAILABLE)
524N/A throw new UnsupportedOperationException();
524N/A
524N/A key = new MembershipKeyImpl.Type4(this, group, interf, source,
524N/A groupAddress, targetAddress, sourceAddress);
524N/A }
524N/A
524N/A registry.add(key);
524N/A return key;
524N/A }
524N/A }
524N/A
524N/A @Override
524N/A public MembershipKey join(InetAddress group,
524N/A NetworkInterface interf)
524N/A throws IOException
524N/A {
524N/A return innerJoin(group, interf, null);
524N/A }
524N/A
524N/A @Override
524N/A public MembershipKey join(InetAddress group,
524N/A NetworkInterface interf,
524N/A InetAddress source)
524N/A throws IOException
524N/A {
524N/A if (source == null)
524N/A throw new NullPointerException("source address is null");
524N/A return innerJoin(group, interf, source);
524N/A }
524N/A
524N/A // package-private
893N/A void drop(MembershipKeyImpl key) {
893N/A assert key.channel() == this;
524N/A
524N/A synchronized (stateLock) {
524N/A if (!key.isValid())
524N/A return;
524N/A
893N/A try {
3759N/A if (key instanceof MembershipKeyImpl.Type6) {
893N/A MembershipKeyImpl.Type6 key6 =
893N/A (MembershipKeyImpl.Type6)key;
893N/A Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
893N/A } else {
893N/A MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key;
893N/A Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(),
893N/A key4.source());
893N/A }
893N/A } catch (IOException ioe) {
893N/A // should not happen
893N/A throw new AssertionError(ioe);
524N/A }
524N/A
524N/A key.invalidate();
524N/A registry.remove(key);
524N/A }
524N/A }
524N/A
524N/A /**
524N/A * Block datagrams from given source if a memory to receive all
524N/A * datagrams.
524N/A */
524N/A void block(MembershipKeyImpl key, InetAddress source)
524N/A throws IOException
524N/A {
893N/A assert key.channel() == this;
893N/A assert key.sourceAddress() == null;
524N/A
524N/A synchronized (stateLock) {
524N/A if (!key.isValid())
524N/A throw new IllegalStateException("key is no longer valid");
524N/A if (source.isAnyLocalAddress())
524N/A throw new IllegalArgumentException("Source address is a wildcard address");
524N/A if (source.isMulticastAddress())
524N/A throw new IllegalArgumentException("Source address is multicast address");
893N/A if (source.getClass() != key.group().getClass())
524N/A throw new IllegalArgumentException("Source address is different type to group");
524N/A
524N/A int n;
3759N/A if (key instanceof MembershipKeyImpl.Type6) {
524N/A MembershipKeyImpl.Type6 key6 =
524N/A (MembershipKeyImpl.Type6)key;
893N/A n = Net.block6(fd, key6.groupAddress(), key6.index(),
524N/A Net.inet6AsByteArray(source));
524N/A } else {
524N/A MembershipKeyImpl.Type4 key4 =
524N/A (MembershipKeyImpl.Type4)key;
893N/A n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(),
524N/A Net.inet4AsInt(source));
524N/A }
524N/A if (n == IOStatus.UNAVAILABLE) {
524N/A // ancient kernel
524N/A throw new UnsupportedOperationException();
524N/A }
524N/A }
524N/A }
524N/A
524N/A /**
524N/A * Unblock given source.
524N/A */
893N/A void unblock(MembershipKeyImpl key, InetAddress source) {
893N/A assert key.channel() == this;
893N/A assert key.sourceAddress() == null;
524N/A
524N/A synchronized (stateLock) {
524N/A if (!key.isValid())
524N/A throw new IllegalStateException("key is no longer valid");
524N/A
893N/A try {
3759N/A if (key instanceof MembershipKeyImpl.Type6) {
893N/A MembershipKeyImpl.Type6 key6 =
893N/A (MembershipKeyImpl.Type6)key;
893N/A Net.unblock6(fd, key6.groupAddress(), key6.index(),
893N/A Net.inet6AsByteArray(source));
893N/A } else {
893N/A MembershipKeyImpl.Type4 key4 =
893N/A (MembershipKeyImpl.Type4)key;
893N/A Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(),
893N/A Net.inet4AsInt(source));
893N/A }
893N/A } catch (IOException ioe) {
893N/A // should not happen
893N/A throw new AssertionError(ioe);
524N/A }
524N/A }
524N/A }
524N/A
0N/A protected void implCloseSelectableChannel() throws IOException {
0N/A synchronized (stateLock) {
4963N/A if (state != ST_KILLED)
4963N/A nd.preClose(fd);
3788N/A ResourceManager.afterUdpClose();
524N/A
524N/A // if member of mulitcast group then invalidate all keys
524N/A if (registry != null)
524N/A registry.invalidateAll();
524N/A
0N/A long th;
0N/A if ((th = readerThread) != 0)
0N/A NativeThread.signal(th);
0N/A if ((th = writerThread) != 0)
0N/A NativeThread.signal(th);
0N/A if (!isRegistered())
0N/A kill();
0N/A }
0N/A }
0N/A
0N/A public void kill() throws IOException {
0N/A synchronized (stateLock) {
0N/A if (state == ST_KILLED)
0N/A return;
0N/A if (state == ST_UNINITIALIZED) {
0N/A state = ST_KILLED;
0N/A return;
0N/A }
0N/A assert !isOpen() && !isRegistered();
0N/A nd.close(fd);
0N/A state = ST_KILLED;
0N/A }
0N/A }
0N/A
0N/A protected void finalize() throws IOException {
0N/A // fd is null if constructor threw exception
0N/A if (fd != null)
0N/A close();
0N/A }
0N/A
0N/A /**
0N/A * Translates native poll revent set into a ready operation set
0N/A */
0N/A public boolean translateReadyOps(int ops, int initialOps,
0N/A SelectionKeyImpl sk) {
0N/A int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
0N/A int oldOps = sk.nioReadyOps();
0N/A int newOps = initialOps;
0N/A
0N/A if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
0N/A // This should only happen if this channel is pre-closed while a
0N/A // selection operation is in progress
0N/A // ## Throw an error if this channel has not been pre-closed
0N/A return false;
0N/A }
0N/A
0N/A if ((ops & (PollArrayWrapper.POLLERR
0N/A | PollArrayWrapper.POLLHUP)) != 0) {
0N/A newOps = intOps;
0N/A sk.nioReadyOps(newOps);
0N/A return (newOps & ~oldOps) != 0;
0N/A }
0N/A
0N/A if (((ops & PollArrayWrapper.POLLIN) != 0) &&
0N/A ((intOps & SelectionKey.OP_READ) != 0))
0N/A newOps |= SelectionKey.OP_READ;
0N/A
0N/A if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
0N/A ((intOps & SelectionKey.OP_WRITE) != 0))
0N/A newOps |= SelectionKey.OP_WRITE;
0N/A
0N/A sk.nioReadyOps(newOps);
0N/A return (newOps & ~oldOps) != 0;
0N/A }
0N/A
0N/A public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
0N/A return translateReadyOps(ops, sk.nioReadyOps(), sk);
0N/A }
0N/A
0N/A public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
0N/A return translateReadyOps(ops, 0, sk);
0N/A }
0N/A
0N/A /**
0N/A * Translates an interest operation set into a native poll event set
0N/A */
0N/A public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
0N/A int newOps = 0;
0N/A
0N/A if ((ops & SelectionKey.OP_READ) != 0)
0N/A newOps |= PollArrayWrapper.POLLIN;
0N/A if ((ops & SelectionKey.OP_WRITE) != 0)
0N/A newOps |= PollArrayWrapper.POLLOUT;
0N/A if ((ops & SelectionKey.OP_CONNECT) != 0)
0N/A newOps |= PollArrayWrapper.POLLIN;
0N/A sk.selector.putEventOps(sk, newOps);
0N/A }
0N/A
0N/A public FileDescriptor getFD() {
0N/A return fd;
0N/A }
0N/A
0N/A public int getFDVal() {
0N/A return fdVal;
0N/A }
0N/A
0N/A
0N/A // -- Native methods --
0N/A
0N/A private static native void initIDs();
0N/A
5205N/A private static native void disconnect0(FileDescriptor fd, boolean isIPv6)
0N/A throws IOException;
0N/A
0N/A private native int receive0(FileDescriptor fd, long address, int len,
0N/A boolean connected)
0N/A throws IOException;
0N/A
5697N/A private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
5697N/A int len, InetAddress addr, int port)
0N/A throws IOException;
0N/A
0N/A static {
0N/A Util.load();
0N/A initIDs();
0N/A }
0N/A
0N/A}