diff --git a/core/java/build.xml b/core/java/build.xml index ad7597559fd9efb4794fc1fa4f05f8c954673675..2038fd505c98848e61d34081373ce9e145c90709 100644 --- a/core/java/build.xml +++ b/core/java/build.xml @@ -223,7 +223,11 @@ <!-- warning - The junit.test target below doesn't actually include i2ptest.jar in the classpath, only the build/obj directory. --> - <jar destfile="./build/i2ptest.jar" basedir="./build/obj" includes="**/*.class **/test.data **/baseDblPrecmp **/basePrecmp" /> + <jar destfile="./build/i2ptest.jar" basedir="./build/obj" > + <fileset dir="./build/obj" includes="**/*.class **/test.data **/baseDblPrecmp **/basePrecmp" /> + <!-- the getopt translation files --> + <fileset dir="src" includes="${translation.includes}" /> + </jar> </target> <!-- preparation of code coverage tool of choice --> <target name="prepareClover" depends="compile" if="with.clover"> diff --git a/router/java/test/junit/net/i2p/router/client/LocalClientManager.java b/router/java/test/junit/net/i2p/router/client/LocalClientManager.java index 0f9ba30aba09a57458f966b4046262ce7d8347c5..2d000317960e56acaa7eebcfbf3cc17bd94a0f8a 100644 --- a/router/java/test/junit/net/i2p/router/client/LocalClientManager.java +++ b/router/java/test/junit/net/i2p/router/client/LocalClientManager.java @@ -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)"); + } }