From cd62d7170c28819e287df3dfb541e4da7a9610eb Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 18 Jun 2015 15:02:21 +0000 Subject: [PATCH] I2CP: Don't send the first LS request to the client until we have at least one OB tunnel, so the client waits until we are ready. This will reduce drops, retransmissions, and failures on new client tunnels. Fixes to prevent multiple pending LS requests. --- .../router/client/ClientConnectionRunner.java | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java index 3e212d081..f804c3674 100644 --- a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java +++ b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java @@ -123,6 +123,7 @@ class ClientConnectionRunner { SessionId sessionId; SessionConfig config; LeaseRequestState leaseRequest; + Rerequest rerequestTimer; LeaseSet currentLeaseSet; SessionParams(Destination d, boolean isPrimary) { @@ -766,6 +767,8 @@ class ClientConnectionRunner { * within the timeout specified, queue up the onFailedJob. This call does not * block. * + * Job args are always null, may need some fixups if we start using them. + * * @param h the Destination's hash * @param set LeaseSet with requested leases - this object must be updated to contain the * signed version (as well as any changed/added/removed Leases) @@ -800,6 +803,7 @@ class ClientConnectionRunner { // synch so _currentLeaseSet isn't changed out from under us LeaseSet current = null; Destination dest = sp.dest; + LeaseRequestState state; synchronized (this) { current = sp.currentLeaseSet; if (current != null && current.getLeaseCount() == leases) { @@ -817,11 +821,10 @@ class ClientConnectionRunner { } } } - } - if (_log.shouldLog(Log.INFO)) - _log.info("Current leaseSet " + current + "\nNew leaseSet " + set); - LeaseRequestState state; - synchronized (this) { + + if (_log.shouldLog(Log.INFO)) + _log.info("Current leaseSet " + current + "\nNew leaseSet " + set); + state = sp.leaseRequest; if (state != null) { LeaseSet requested = state.getRequested(); @@ -835,7 +838,9 @@ class ClientConnectionRunner { } else { // ours is newer, so wait a few secs and retry set.setDestination(dest); - _context.simpleTimer2().addEvent(new Rerequest(set, expirationTime, onCreateJob, onFailedJob), 3*1000); + Rerequest timer = new Rerequest(set, expirationTime, onCreateJob, onFailedJob); + sp.rerequestTimer = timer; + _context.simpleTimer2().addEvent(timer, 3*1000); if (_log.shouldLog(Log.DEBUG)) _log.debug("Already requesting, ours newer, wait 3 sec: " + state); } @@ -843,10 +848,24 @@ class ClientConnectionRunner { return; // already requesting } else { set.setDestination(dest); - sp.leaseRequest = state = new LeaseRequestState(onCreateJob, onFailedJob, + if (current == null && _context.tunnelManager().getOutboundClientTunnelCount(h) <= 0) { + // at startup of a client, where we don't have a leaseset, wait for + // an outbound tunnel also, so the client doesn't start sending data + // before we are ready + Rerequest timer = new Rerequest(set, expirationTime, onCreateJob, onFailedJob); + sp.rerequestTimer = timer; + _context.simpleTimer2().addEvent(timer, 1000); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("No current LS but no OB tunnels, wait 1 sec for " + h); + return; + } else { + // so the timer won't fire off with an older LS request + sp.rerequestTimer = null; + sp.leaseRequest = state = new LeaseRequestState(onCreateJob, onFailedJob, _context.clock().now() + expirationTime, set); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("New request: " + state); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("New request: " + state); + } } } _context.jobQueue().addJob(new RequestLeaseSetJob(_context, this, state)); @@ -867,6 +886,20 @@ class ClientConnectionRunner { } public void timeReached() { + Hash h = _ls.getDestination().calculateHash(); + SessionParams sp = _sessions.get(h); + if (sp == null) { + if (_log.shouldLog(Log.WARN)) + _log.warn("cancelling rerequest, session went away"); + return; + } + synchronized(ClientConnectionRunner.this) { + if (sp.rerequestTimer != Rerequest.this) { + if (_log.shouldLog(Log.WARN)) + _log.warn("cancelling rerequest, newer request came in"); + return; + } + } requestLeaseSet(_ls.getDestination().calculateHash(), _ls, _expirationTime, _onCreate, _onFailed); } }