diff --git a/router/java/src/net/i2p/router/TunnelManagerFacade.java b/router/java/src/net/i2p/router/TunnelManagerFacade.java index 3a24e2e89e..eea461bd52 100644 --- a/router/java/src/net/i2p/router/TunnelManagerFacade.java +++ b/router/java/src/net/i2p/router/TunnelManagerFacade.java @@ -148,6 +148,12 @@ public interface TunnelManagerFacade extends Service { */ public void buildTunnels(Destination client, ClientTunnelSettings settings); + /** + * Must be called AFTER deregistration by the client manager. + * @since 0.9.48 + */ + public void removeTunnels(Destination client); + /** * Add another destination to the same tunnels. * Must have same encryption key and a different signing key. diff --git a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java index 16853a206a..1aff4a7276 100644 --- a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java +++ b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java @@ -212,6 +212,9 @@ class ClientConnectionRunner { _manager.unregisterConnection(this); // netdb may be null in unit tests if (_context.netDb() != null) { + // Note that if the client sent us a destroy message, + // removeSession() was called just before this, and + // _sessions will be empty. for (SessionParams sp : _sessions.values()) { LeaseSet ls = sp.currentLeaseSet; if (ls != null) @@ -223,6 +226,10 @@ class ClientConnectionRunner { if (!sp.isPrimary) _context.tunnelManager().removeAlias(sp.dest); } + for (SessionParams sp : _sessions.values()) { + if (sp.isPrimary) + _context.tunnelManager().removeTunnels(sp.dest); + } } synchronized (_alreadyProcessed) { _alreadyProcessed.clear(); @@ -455,7 +462,9 @@ class ClientConnectionRunner { if (ls != null) _context.netDb().unpublish(ls); isPrimary = sp.isPrimary; - if (!isPrimary) + if (isPrimary) + _context.tunnelManager().removeTunnels(sp.dest); + else _context.tunnelManager().removeAlias(sp.dest); break; } @@ -475,6 +484,7 @@ class ClientConnectionRunner { _context.netDb().unpublish(ls); _context.tunnelManager().removeAlias(sp.dest); } + _sessions.clear(); } } diff --git a/router/java/src/net/i2p/router/dummy/DummyTunnelManagerFacade.java b/router/java/src/net/i2p/router/dummy/DummyTunnelManagerFacade.java index 6f8edafb9b..e11a8129e2 100644 --- a/router/java/src/net/i2p/router/dummy/DummyTunnelManagerFacade.java +++ b/router/java/src/net/i2p/router/dummy/DummyTunnelManagerFacade.java @@ -51,6 +51,7 @@ public class DummyTunnelManagerFacade implements TunnelManagerFacade { public int getOutboundClientTunnelCount(Hash destination) { return 0; } public long getLastParticipatingExpiration() { return -1; } public void buildTunnels(Destination client, ClientTunnelSettings settings) {} + public void removeTunnels(Destination client) {} public boolean addAlias(Destination dest, ClientTunnelSettings settings, Destination existingClient) { return false; } public void removeAlias(Destination dest) {} public TunnelPoolSettings getInboundSettings() { return null; } diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java index 15c9d347dc..a917f52235 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -533,9 +533,21 @@ public class TunnelPoolManager implements TunnelManagerFacade { } } + /** + * Must be called AFTER deregistration by the client manager. + * + * @since 0.9.48 + */ + public void removeTunnels(Destination dest) { + removeTunnels(dest.calculateHash()); + } + /** * This will be called twice, once by the inbound and once by the outbound pool. * Synched with buildTunnels() above. + * + * Must be called AFTER deregistration by the client manager. + * */ public synchronized void removeTunnels(Hash destination) { if (destination == null) return;