forked from I2P_Developers/i2p.i2p
Test: Add random delay and drop options to LocalClientManager
Return failure codes from LCM to client (ticket #1939)
This commit is contained in:
@ -8,12 +8,15 @@ package net.i2p.router.client;
|
||||
*
|
||||
*/
|
||||
|
||||
import gnu.getopt.Getopt;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Payload;
|
||||
import net.i2p.data.i2cp.MessageId;
|
||||
import net.i2p.data.i2cp.MessageStatusMessage;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* For testing clients without a full router.
|
||||
@ -25,6 +28,7 @@ import net.i2p.util.I2PThread;
|
||||
* @since 0.9.8
|
||||
*/
|
||||
class LocalClientManager extends ClientManager {
|
||||
private static int dropX1000 = 0, jitter = 0, latency = 0;
|
||||
|
||||
/**
|
||||
* @param context stub, may be constructed with new RouterContext(null),
|
||||
@ -45,7 +49,7 @@ class LocalClientManager extends ClientManager {
|
||||
|
||||
/**
|
||||
* Local only
|
||||
* TODO: add simulated delay and random drops to test streaming.
|
||||
* TODO: we could have per-destination delay/drop parameters in the client options
|
||||
*
|
||||
* @param flags ignored for local
|
||||
*/
|
||||
@ -56,9 +60,31 @@ class LocalClientManager extends ClientManager {
|
||||
ClientConnectionRunner sender = getRunner(fromDest);
|
||||
ClientConnectionRunner runner = getRunner(toDest);
|
||||
if (runner != null) {
|
||||
runner.receiveMessage(toDest, fromDest, payload);
|
||||
if (sender != null)
|
||||
sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL);
|
||||
if (dropX1000 > 0) {
|
||||
if (100 * 1000 * _ctx.random().nextFloat() < dropX1000) {
|
||||
System.out.println("Message " + msgId + " DROPPED randomly");
|
||||
if (sender != null) {
|
||||
// pretend success
|
||||
sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, MessageStatusMessage.STATUS_SEND_GUARANTEED_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (latency > 0 || jitter > 0) {
|
||||
int delay = latency;
|
||||
if (jitter > 0)
|
||||
delay += (int) (jitter * _ctx.random().nextGaussian());
|
||||
if (delay > 0) {
|
||||
System.out.println("Message " + msgId + " DELAYED " + delay + " ms");
|
||||
DelayedSend ds = new DelayedSend(_ctx, sender, runner, fromDest, toDest, payload, msgId, messageNonce);
|
||||
ds.schedule(delay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean ok = runner.receiveMessage(toDest, fromDest, payload);
|
||||
if (sender != null) {
|
||||
int rc = ok ? MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL : MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL;
|
||||
sender.updateMessageDeliveryStatus(fromDest, msgId, messageNonce, rc);
|
||||
}
|
||||
} else {
|
||||
// remote. ignore.
|
||||
System.out.println("Message " + msgId + " is targeting a REMOTE destination - DROPPED");
|
||||
@ -67,13 +93,87 @@ class LocalClientManager extends ClientManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static class DelayedSend extends SimpleTimer2.TimedEvent {
|
||||
private final ClientConnectionRunner s, r;
|
||||
private final Destination fd, td;
|
||||
private final Payload pl;
|
||||
private final MessageId id;
|
||||
private final long nonce;
|
||||
|
||||
public DelayedSend(RouterContext ctx, ClientConnectionRunner sender, ClientConnectionRunner runner,
|
||||
Destination fromDest, Destination toDest, Payload payload,
|
||||
MessageId msgId, long messageNonce) {
|
||||
super(ctx.simpleTimer2());
|
||||
s = sender; r = runner; fd = fromDest;
|
||||
td = toDest; pl = payload;
|
||||
id = msgId; nonce = messageNonce;
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
boolean ok = r.receiveMessage(td, fd, pl);
|
||||
if (s != null) {
|
||||
int rc = ok ? MessageStatusMessage.STATUS_SEND_SUCCESS_LOCAL : MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL;
|
||||
s.updateMessageDeliveryStatus(fd, id, nonce, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
int dropX1000 = 0, jitter = 0, latency = 0;
|
||||
boolean error = false;
|
||||
Getopt g = new Getopt("router", args, "d:j:l:");
|
||||
try {
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
switch (c) {
|
||||
|
||||
case 'd':
|
||||
dropX1000 = (int) (1000 * Double.parseDouble(g.getOptarg()));
|
||||
if (dropX1000 < 0 || dropX1000 >= 100 * 1000)
|
||||
error = true;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
jitter = Integer.parseInt(g.getOptarg());
|
||||
if (jitter < 0)
|
||||
error = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
latency = Integer.parseInt(g.getOptarg());
|
||||
if (latency < 0)
|
||||
error = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
error = true;
|
||||
}
|
||||
if (error || args.length - g.getOptind() > 0) {
|
||||
usage();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
RouterContext ctx = new RouterContext(null);
|
||||
int port = ClientManagerFacadeImpl.DEFAULT_PORT;
|
||||
ClientManager mgr = new LocalClientManager(ctx, port);
|
||||
LocalClientManager mgr = new LocalClientManager(ctx, port);
|
||||
mgr.dropX1000 = dropX1000;
|
||||
mgr.jitter = jitter;
|
||||
mgr.latency = latency;
|
||||
mgr.start();
|
||||
System.out.println("Listening on port " + port);
|
||||
try { Thread.sleep(60*60*1000); } catch (InterruptedException ie) {}
|
||||
System.out.println("Done listening on port " + port);
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.err.println("usage: LocalClientManager\n" +
|
||||
" [-d droppercent] // 0.0 - 99.99999 (default 0)\n" +
|
||||
" [-j jitter] // (integer ms for 1 std. deviation, default 0)\n" +
|
||||
" [-l latency] // (integer ms, default 0)");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user