package org.opendedup.sdfs.network;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.opendedup.sdfs.Main;
import org.opendedup.sdfs.servers.HashChunkService;
/**
*
* @author Sam Silverberg
*
* This is a UDP server class that can be used to serve client requests
* within the chunk server. It servers a similar function to @see
* com.annesam.sdfs.network.ClientThread . In some cases in may improve
* client performance to enable this function on the server. The UDP
* server will service :
*
* - HASH_EXISTS requests - CLAIM_HASH requests
*
* To enable the UDP server within the chunk store the config option
* use-udp="true must be set.
*
*
*/
public class NioUDPServer implements Runnable {
int datagramSize = 36;
private boolean closed = false;
private transient static Logger log = Logger.getLogger("sdfs");
NioUDPServer() {
Thread th = new Thread(this);
th.start();
}
public static void main(String args[]) {
Main.serverHostName = "localhost";
Main.serverPort = 2222;
new NioUDPServer();
}
public void close() {
this.closed = true;
}
public void run() {
try {
log.info("Starting UDP Server");
InetSocketAddress theInetSocketAddress = new InetSocketAddress(
Main.serverHostName, Main.serverPort);
// make a DatagramChannel
DatagramChannel theDatagramChannel = DatagramChannel.open();
// theDatagramChannel.bind(theInetSocketAddress);
theDatagramChannel.connect(theInetSocketAddress);
// A channel must first be placed in nonblocking mode
// before it can be registered with a selector
theDatagramChannel.configureBlocking(false);
// instantiate a selector
Selector theSelector = Selector.open();
// register the selector on the channel to monitor reading
// datagrams on the DatagramChannel
theDatagramChannel.register(theSelector, SelectionKey.OP_READ);
log.info("UDP Server Started on " + theInetSocketAddress);
// send and read concurrently, but do not block on read:
while (!this.closed) {
int keys = theSelector.select(500);
// which comes first, next send or a read?
// in case millisecsUntilSendNextDatagram <= 0 go right to send
if (keys > 0) {
try {
Iterator<SelectionKey> iter = theSelector
.selectedKeys().iterator();
ByteBuffer buf = ByteBuffer.allocateDirect(33);
ByteBuffer resp = ByteBuffer.allocateDirect(2);
SelectionKey key = null;
while (iter.hasNext()) {
try {
key = iter.next();
if (key.isReadable()) {
DatagramChannel ch = (DatagramChannel) key
.channel();
InetSocketAddress addr = (InetSocketAddress) ch
.receive(buf);
buf.flip();
byte cmd = buf.get();
byte[] hash = new byte[16];
buf.clear();
boolean exists = false;
if (cmd == NetworkCMDS.HASH_EXISTS_CMD)
exists = HashChunkService
.hashExists(hash);
// boolean exists = true;
if (exists)
resp.putShort((short) 1);
else
resp.putShort((short) 0);
resp.flip();
ch.send(resp, addr);
resp.clear();
}
} catch (Exception e) {
log.log(Level.WARNING,
"unable to process hash request", e);
} finally {
iter.remove();
resp.clear();
buf.clear();
}
}
} catch (Exception e) {
log.log(Level.WARNING,
"unable to process hash request", e);
}
}
}
} catch (Exception e) {
log.log(Level.SEVERE, "unable to run udp server", e);
return;
}
}
}