package kg.apc.io;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketOption;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.MembershipKey;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Set;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
public class DatagramChannelWithTimeouts extends DatagramChannel {
protected DatagramChannel channel;
protected Selector selector;
private long readTimeout = 10000;
protected SelectionKey channelKey;
private static final Logger log = LoggingManager.getLoggerForClass();
private boolean fastFirstPacketRead;
protected DatagramChannelWithTimeouts() throws IOException {
super(null);
log.debug("Creating DatagramChannel");
selector = Selector.open();
channel = DatagramChannel.open();
channel.configureBlocking(false);
channelKey = channel.register(selector, SelectionKey.OP_READ);
}
public static DatagramChannel open() throws IOException {
return new DatagramChannelWithTimeouts();
}
@Override
public DatagramChannel bind(SocketAddress socketAddress) throws IOException {
return channel.bind(socketAddress);
}
@Override
public SocketAddress getLocalAddress() throws IOException {
return channel.getLocalAddress();
}
@Override
public <T> DatagramChannel setOption(SocketOption<T> socketOption, T t) throws IOException {
return channel.setOption(socketOption, t);
}
@Override
public <T> T getOption(SocketOption<T> socketOption) throws IOException {
return channel.getOption(socketOption);
}
@Override
public Set<SocketOption<?>> supportedOptions() {
return channel.supportedOptions();
}
public int read(ByteBuffer dst) throws IOException {
int bytesRead = 0;
while (selector.select(readTimeout) > 0) {
if (log.isDebugEnabled()) {
log.debug("Loop " + bytesRead);
}
// damn NPE in unit tests...
if (selector.selectedKeys() != null) {
selector.selectedKeys().remove(channelKey);
}
int cnt = channel.read(dst);
if (cnt < 1) {
if (bytesRead < 1) {
bytesRead = -1;
}
return bytesRead;
} else {
bytesRead += cnt;
if (!fastFirstPacketRead) {
fastFirstPacketRead = true;
return bytesRead;
}
}
}
if (bytesRead < 1) {
throw new SocketTimeoutException("Timeout exceeded while reading from socket");
}
return bytesRead;
}
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public int write(ByteBuffer src) throws IOException {
fastFirstPacketRead = false;
int res = 0;
int size = src.remaining();
while (res < size) {
res += channel.write(src);
}
return res;
}
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
protected void implCloseSelectableChannel() throws IOException {
channel.close();
selector.close();
}
protected void implConfigureBlocking(boolean block) throws IOException {
throw new UnsupportedOperationException("This class is blocking implementation of SocketChannel");
}
public boolean isConnected() {
return channel.isConnected();
}
public void setReadTimeout(int t) {
readTimeout = t;
}
public DatagramSocket socket() {
return channel.socket();
}
public DatagramChannel disconnect() throws IOException {
return channel.disconnect();
}
public SocketAddress receive(ByteBuffer dst) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public int send(ByteBuffer src, SocketAddress target) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public DatagramChannel connect(SocketAddress remote) throws IOException {
return channel.connect(remote);
}
public SocketAddress getRemoteAddress() throws IOException {
return null;
}
@Override
public MembershipKey join(InetAddress inetAddress, NetworkInterface networkInterface) throws IOException {
return channel.join(inetAddress, networkInterface);
}
@Override
public MembershipKey join(InetAddress inetAddress, NetworkInterface networkInterface, InetAddress inetAddress1) throws IOException {
return channel.join(inetAddress, networkInterface, inetAddress1);
}
}