org.xnio.nio.NioUdpChannel Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2012 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xnio.nio;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.MembershipKey;
import java.nio.channels.SelectionKey;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.xnio.Buffers;
import org.xnio.Option;
import org.xnio.ChannelListener;
import org.xnio.Options;
import org.xnio.XnioExecutor;
import org.xnio.channels.MulticastMessageChannel;
import org.xnio.channels.ReadListenerSettable;
import org.xnio.channels.SocketAddressBuffer;
import org.xnio.channels.UnsupportedOptionException;
import org.xnio.channels.WriteListenerSettable;
import static org.xnio.Xnio.NIO2;
import static org.xnio.nio.Log.log;
import static org.xnio.nio.Log.udpServerChannelLog;
/**
*
*/
class NioUdpChannel extends AbstractNioChannel implements MulticastMessageChannel, ReadListenerSettable, WriteListenerSettable {
private final NioUdpChannelHandle handle;
private ChannelListener super NioUdpChannel> readListener;
private ChannelListener super NioUdpChannel> writeListener;
private final DatagramChannel datagramChannel;
private final AtomicBoolean callFlag = new AtomicBoolean(false);
NioUdpChannel(final NioXnioWorker worker, final DatagramChannel datagramChannel) throws ClosedChannelException {
super(worker);
this.datagramChannel = datagramChannel;
final WorkerThread workerThread = worker.chooseThread();
final SelectionKey key = workerThread.registerChannel(datagramChannel);
handle = new NioUdpChannelHandle(workerThread, key, this);
key.attach(handle);
}
public SocketAddress getLocalAddress() {
return datagramChannel.socket().getLocalSocketAddress();
}
public A getLocalAddress(final Class type) {
return type.isInstance(getLocalAddress()) ? type.cast(getLocalAddress()) : null;
}
public int receiveFrom(final SocketAddressBuffer addressBuffer, final ByteBuffer buffer) throws IOException {
final int o = buffer.remaining();
final SocketAddress sourceAddress;
try {
sourceAddress = datagramChannel.receive(buffer);
} catch (ClosedChannelException e) {
return -1;
}
if (sourceAddress == null) {
return 0;
} else {
final int t = o - buffer.remaining();
if (addressBuffer != null) {
addressBuffer.setSourceAddress(sourceAddress);
addressBuffer.setDestinationAddress(null);
}
return t;
}
}
public long receiveFrom(final SocketAddressBuffer addressBuffer, final ByteBuffer[] buffers) throws IOException {
return receiveFrom(addressBuffer, buffers, 0, buffers.length);
}
public long receiveFrom(final SocketAddressBuffer addressBuffer, final ByteBuffer[] buffers, final int offs, final int len) throws IOException {
if (len == 0) {
return 0L;
}
if (len == 1) {
return receiveFrom(addressBuffer, buffers[offs]);
}
final int o = (int) Math.min(Buffers.remaining(buffers, offs, len), 65536L);
final ByteBuffer buffer = ByteBuffer.allocate(o);
final SocketAddress sourceAddress;
try {
sourceAddress = datagramChannel.receive(buffer);
} catch (ClosedChannelException e) {
return -1L;
}
if (sourceAddress == null) {
return 0L;
} else {
final int t = o - buffer.remaining();
buffer.flip();
Buffers.copy(buffers, offs, len, buffer);
if (addressBuffer != null) {
addressBuffer.setSourceAddress(sourceAddress);
addressBuffer.setDestinationAddress(null);
}
return t;
}
}
public boolean sendTo(final SocketAddress target, final ByteBuffer buffer) throws IOException {
return datagramChannel.send(buffer, target) != 0;
}
public boolean sendTo(final SocketAddress target, final ByteBuffer[] buffers) throws IOException {
return sendTo(target, buffers, 0, buffers.length);
}
public boolean sendTo(final SocketAddress target, final ByteBuffer[] buffers, final int offset, final int length) throws IOException {
if (length == 0) {
return false;
}
if (length == 1) {
return sendTo(target, buffers[offset]);
}
final long o = Buffers.remaining(buffers, offset, length);
if (o > 65535L) {
// there will never be enough room
throw log.bufferTooLarge();
}
final ByteBuffer buffer = ByteBuffer.allocate((int) o);
Buffers.copy(buffer, buffers, offset, length);
buffer.flip();
return datagramChannel.send(buffer, target) != 0;
}
public ChannelListener super NioUdpChannel> getReadListener() {
return readListener;
}
public void setReadListener(final ChannelListener super NioUdpChannel> readListener) {
this.readListener = readListener;
}
public ChannelListener super NioUdpChannel> getWriteListener() {
return writeListener;
}
public void setWriteListener(final ChannelListener super NioUdpChannel> writeListener) {
this.writeListener = writeListener;
}
public ChannelListener.Setter getReadSetter() {
return new ReadListenerSettable.Setter(this);
}
public ChannelListener.Setter getWriteSetter() {
return new WriteListenerSettable.Setter(this);
}
public boolean flush() throws IOException {
return true;
}
public boolean isOpen() {
return datagramChannel.isOpen();
}
public void close() throws IOException {
if (!callFlag.getAndSet(true)) {
udpServerChannelLog.tracef("Closing %s", this);
try { cancelKeys(); } catch (Throwable ignored) {}
try {
datagramChannel.close();
} finally {
invokeCloseHandler();
}
}
}
private void cancelKeys() {
try { handle.cancelKey(false); } catch (Throwable ignored) {}
}
public void suspendReads() {
handle.suspend(SelectionKey.OP_READ);
}
public void suspendWrites() {
handle.suspend(SelectionKey.OP_WRITE);
}
public void resumeReads() {
handle.resume(SelectionKey.OP_READ);
}
public void resumeWrites() {
handle.resume(SelectionKey.OP_WRITE);
}
public boolean isReadResumed() {
return handle.isResumed(SelectionKey.OP_READ);
}
public boolean isWriteResumed() {
return handle.isResumed(SelectionKey.OP_WRITE);
}
public void wakeupReads() {
handle.wakeup(SelectionKey.OP_READ);
}
public void wakeupWrites() {
handle.wakeup(SelectionKey.OP_WRITE);
}
public void shutdownReads() throws IOException {
throw log.unsupported("shutdownReads");
}
public void shutdownWrites() throws IOException {
throw log.unsupported("shutdownWrites");
}
public void awaitReadable() throws IOException {
SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_READ);
}
public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException {
SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_READ, time, timeUnit);
}
@Deprecated
public XnioExecutor getReadThread() {
return getIoThread();
}
public void awaitWritable() throws IOException {
SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_WRITE);
}
public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException {
SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_WRITE, time, timeUnit);
}
@Deprecated
public XnioExecutor getWriteThread() {
return getIoThread();
}
public Key join(final InetAddress group, final NetworkInterface iface) throws IOException {
return new NioKey(datagramChannel.join(group, iface));
}
public Key join(final InetAddress group, final NetworkInterface iface, final InetAddress source) throws IOException {
return new NioKey(datagramChannel.join(group, iface, source));
}
private static final Set