package net.i2p.router.client;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.I2CPMessageException;
import net.i2p.internal.PoisonI2CPMessage;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
/**
* Async writer class so that if a client app hangs, they wont take down the
* whole router with them (since otherwise the JobQueue would block until
* the client reads from their i2cp socket, causing all sorts of bad things to
* happen)
*
* For external I2CP connections only.
*/
class ClientWriterRunner implements Runnable {
private final BlockingQueue<I2CPMessage> _messagesToWrite;
private final ClientConnectionRunner _runner;
//private final Log _log;
//private final long _id;
//private static long __id = 0;
private static final int QUEUE_SIZE = 256;
public ClientWriterRunner(RouterContext context, ClientConnectionRunner runner) {
//_log = context.logManager().getLog(ClientWriterRunner.class);
_messagesToWrite = new LinkedBlockingQueue<I2CPMessage>(QUEUE_SIZE);
_runner = runner;
//_id = ++__id;
}
/**
* Add this message to the writer's queue
*
* Nonblocking, throws exception if queue is full
*/
public void addMessage(I2CPMessage msg) throws I2CPMessageException {
boolean success = _messagesToWrite.offer(msg);
if (!success)
throw new I2CPMessageException("I2CP write to queue failed");
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("["+_id+"] addMessage completed for " + msg.getClass().getName());
}
/**
* No more messages - dont even try to send what we have
*
*/
public void stopWriting() {
_messagesToWrite.clear();
try {
_messagesToWrite.put(new PoisonI2CPMessage());
} catch (InterruptedException ie) {}
}
public void run() {
I2CPMessage msg;
while (!_runner.getIsDead()) {
try {
msg = _messagesToWrite.take();
} catch (InterruptedException ie) {
continue;
}
if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE)
break;
_runner.writeMessage(msg);
}
}
}