package rocks.inspectit.shared.all.kryonet;
import static com.esotericsoftware.minlog.Log.DEBUG;
import static com.esotericsoftware.minlog.Log.debug;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import com.esotericsoftware.kryonet.KryoNetException;
/**
* <b>IMPORTANT:</b> The class code is copied/taken/based from
* <a href="https://github.com/EsotericSoftware/kryonet">kryonet</a>. Original author is Nathan
* Sweet. License info can be found
* <a href="https://github.com/EsotericSoftware/kryonet/blob/master/license.txt">here</a>.
*
* @author Nathan Sweet <misc@n4te.com>
*/
@SuppressWarnings("all")
// NOCHKALL
class UdpConnection {
InetSocketAddress connectedAddress;
DatagramChannel datagramChannel;
int keepAliveMillis = 19000;
final ByteBuffer readBuffer, writeBuffer;
private final Serialization serialization;
private SelectionKey selectionKey;
private final Object writeLock = new Object();
private long lastCommunicationTime;
public UdpConnection(Serialization serialization, int bufferSize) {
this.serialization = serialization;
readBuffer = ByteBuffer.allocate(bufferSize);
writeBuffer = ByteBuffer.allocateDirect(bufferSize);
}
public void bind(Selector selector, InetSocketAddress localPort) throws IOException {
close();
readBuffer.clear();
writeBuffer.clear();
try {
datagramChannel = selector.provider().openDatagramChannel();
datagramChannel.socket().bind(localPort);
datagramChannel.configureBlocking(false);
selectionKey = datagramChannel.register(selector, SelectionKey.OP_READ);
lastCommunicationTime = System.currentTimeMillis();
} catch (IOException ex) {
close();
throw ex;
}
}
public void connect(Selector selector, InetSocketAddress remoteAddress) throws IOException {
close();
readBuffer.clear();
writeBuffer.clear();
try {
datagramChannel = selector.provider().openDatagramChannel();
datagramChannel.socket().bind(null);
datagramChannel.socket().connect(remoteAddress);
datagramChannel.configureBlocking(false);
selectionKey = datagramChannel.register(selector, SelectionKey.OP_READ);
lastCommunicationTime = System.currentTimeMillis();
connectedAddress = remoteAddress;
} catch (IOException ex) {
close();
IOException ioEx = new IOException("Unable to connect to: " + remoteAddress);
ioEx.initCause(ex);
throw ioEx;
}
}
public InetSocketAddress readFromAddress() throws IOException {
DatagramChannel datagramChannel = this.datagramChannel;
if (datagramChannel == null) {
throw new SocketException("Connection is closed.");
}
lastCommunicationTime = System.currentTimeMillis();
return (InetSocketAddress) datagramChannel.receive(readBuffer);
}
public Object readObject(Connection connection) {
readBuffer.flip();
try {
try {
Object object = serialization.read(connection, readBuffer);
if (readBuffer.hasRemaining()) {
throw new KryoNetException("Incorrect number of bytes (" + readBuffer.remaining() + " remaining) used to deserialize object: " + object);
}
return object;
} catch (Exception ex) {
throw new KryoNetException("Error during deserialization.", ex);
}
} finally {
readBuffer.clear();
}
}
/** This method is thread safe. */
public int send(Connection connection, Object object, SocketAddress address) throws IOException {
DatagramChannel datagramChannel = this.datagramChannel;
if (datagramChannel == null) {
throw new SocketException("Connection is closed.");
}
synchronized (writeLock) {
try {
try {
serialization.write(connection, writeBuffer, object);
} catch (Exception ex) {
throw new KryoNetException("Error serializing object of type: " + object.getClass().getName(), ex);
}
writeBuffer.flip();
int length = writeBuffer.limit();
datagramChannel.send(writeBuffer, address);
lastCommunicationTime = System.currentTimeMillis();
boolean wasFullWrite = !writeBuffer.hasRemaining();
return wasFullWrite ? length : -1;
} finally {
writeBuffer.clear();
}
}
}
public void close() {
connectedAddress = null;
try {
if (datagramChannel != null) {
datagramChannel.close();
datagramChannel = null;
if (selectionKey != null) {
selectionKey.selector().wakeup();
}
}
} catch (IOException ex) {
if (DEBUG) {
debug("kryonet", "Unable to close UDP connection.", ex);
}
}
}
public boolean needsKeepAlive(long time) {
return (connectedAddress != null) && (keepAliveMillis > 0) && ((time - lastCommunicationTime) > keepAliveMillis);
}
}