package net.i2p.router.transport.udp;
import java.util.ArrayList;
import java.util.List;
import net.i2p.data.router.RouterInfo;
import net.i2p.data.i2np.DataMessage;
import net.i2p.data.i2np.I2NPMessage;
import net.i2p.router.OutNetMessage;
import net.i2p.router.RouterContext;
import net.i2p.util.I2PThread;
// import net.i2p.util.Log;
/**
* This sends random data to all UDP peers at a specified rate.
* It is for testing only!
*/
class UDPFlooder implements Runnable {
private RouterContext _context;
// private Log _log;
private UDPTransport _transport;
private final List<PeerState> _peers;
private boolean _alive;
private static final byte _floodData[] = new byte[4096];
public UDPFlooder(RouterContext ctx, UDPTransport transport) {
_context = ctx;
// _log = ctx.logManager().getLog(UDPFlooder.class);
_transport = transport;
_peers = new ArrayList<PeerState>(4);
ctx.random().nextBytes(_floodData);
}
public void addPeer(PeerState peer) {
synchronized (_peers) {
if (!_peers.contains(peer))
_peers.add(peer);
_peers.notifyAll();
}
}
@SuppressWarnings("empty-statement")
public void removePeer(PeerState peer) {
synchronized (_peers) {
while (_peers.remove(peer)) // can this be written better?
;// loops until its empty
_peers.notifyAll();
}
}
public void startup() {
_alive = true;
I2PThread t = new I2PThread(this, "flooder");
t.setDaemon(true);
t.start();
}
public void shutdown() {
_alive = false;
synchronized (_peers) {
_peers.notifyAll();
}
}
public void run() {
long nextSend = _context.clock().now();
while (_alive) {
try {
synchronized (_peers) {
if (_peers.isEmpty())
_peers.wait();
}
} catch (InterruptedException ie) {}
long now = _context.clock().now();
if (now >= nextSend) {
// peers always grows, so this is fairly safe
for (int i = 0; i < _peers.size(); i++) {
PeerState peer = (PeerState)_peers.get(i);
DataMessage m = new DataMessage(_context);
byte data[] = _floodData; // new byte[4096];
//_context.random().nextBytes(data);
m.setData(data);
m.setMessageExpiration(_context.clock().now() + 10*1000);
m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
if (true) {
RouterInfo to = _context.netDb().lookupRouterInfoLocally(peer.getRemotePeer());
if (to == null)
continue;
OutNetMessage msg = new OutNetMessage(_context, m, m.getMessageExpiration(), 500, to);
// warning, getStatLog() can be null
//_context.statManager().getStatLog().addData(peer.getRemotePeer().toBase64().substring(0,6), "udp.floodDataSent", 1, 0);
_transport.send(msg);
} else {
_transport.send(m, peer);
}
}
nextSend = now + calcFloodDelay();
}
long delay = nextSend - now;
if (delay > 0) {
if (delay > 10*1000) {
long fd = calcFloodDelay();
if (delay > fd) {
nextSend = now + fd;
delay = fd;
}
}
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
}
private long calcFloodDelay() {
try {
return Long.parseLong(_context.getProperty("udp.floodDelay", "300000"));
} catch (Exception e) {
return 5*60*1000;
}
}
}