From be8f7f9676c0f77fbab6fed9505ef733e7ead128 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Sun, 19 Apr 2015 01:32:30 +0000 Subject: [PATCH] I2CP Multisession - Work in progress: Fix sending CreateSessionMessage for subsession New AliasedTunnelPool for subsessions, don't reuse TunnelPool, so it has its own settings Fix addAlias() Simplify refreshSettings() Send status message on subsession create failure Fix settings for subsession --- .../src/net/i2p/client/I2PSessionImpl.java | 2 + core/java/src/net/i2p/client/SubSession.java | 3 +- .../client/ClientMessageEventListener.java | 26 ++-- .../router/tunnel/pool/AliasedTunnelPool.java | 141 ++++++++++++++++++ .../i2p/router/tunnel/pool/TunnelPool.java | 34 ++--- .../router/tunnel/pool/TunnelPoolManager.java | 33 +++- 6 files changed, 206 insertions(+), 33 deletions(-) create mode 100644 router/java/src/net/i2p/router/tunnel/pool/AliasedTunnelPool.java diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 2a0f9ed4a7..6990f2a51d 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -647,6 +647,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa // now send CreateSessionMessages for all subsessions, one at a time, must wait for each response synchronized(_subsessionLock) { for (SubSession ss : _subsessions) { + if (_log.shouldLog(Log.INFO)) + _log.info(getPrefix() + "Connecting subsession " + ss); _producer.connect(ss); } } diff --git a/core/java/src/net/i2p/client/SubSession.java b/core/java/src/net/i2p/client/SubSession.java index 1e75fa409e..9dcf04e72d 100644 --- a/core/java/src/net/i2p/client/SubSession.java +++ b/core/java/src/net/i2p/client/SubSession.java @@ -114,7 +114,8 @@ class SubSession extends I2PSessionMuxedImpl { */ @Override public boolean isClosed() { - return getSessionId() == null || _primary.isClosed(); + // FIXME + return /* getSessionId() == null || */ _primary.isClosed(); } /** diff --git a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java index e12205e830..ead5dcd262 100644 --- a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java +++ b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java @@ -248,9 +248,18 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi SessionConfig cfg = new SessionConfig(dest); cfg.setSignature(in.getSignature()); Properties props = new Properties(); - props.putAll(in.getOptions()); - cfg.setOptions(props); boolean isPrimary = _runner.getSessionIds().isEmpty(); + if (!isPrimary) { + // all the primary options, then the overrides from the alias + SessionConfig pcfg = _runner.getPrimaryConfig(); + if (pcfg != null) { + props.putAll(pcfg.getOptions()); + } else { + _log.error("no primary config?"); + } + } + props.putAll(inProps); + cfg.setOptions(props); // this sets the session id int status = _runner.sessionEstablished(cfg); if (status != SessionStatusMessage.STATUS_CREATED) { @@ -269,28 +278,27 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi } // get the new session ID id = _runner.getSessionId(dest.calculateHash()); - sendStatusMessage(id, status); if (_log.shouldLog(Log.INFO)) _log.info("Session " + id + " established for " + dest.calculateHash()); if (isPrimary) { + sendStatusMessage(id, status); startCreateSessionJob(cfg); } else { SessionConfig pcfg = _runner.getPrimaryConfig(); if (pcfg != null) { - /////////// - // new tunnel name etc. ClientTunnelSettings settings = new ClientTunnelSettings(dest.calculateHash()); - // all the primary options, then the overrides from the alias - props.putAll(pcfg.getOptions()); - props.putAll(props); settings.readFromProperties(props); boolean ok = _context.tunnelManager().addAlias(dest, settings, pcfg.getDestination()); if (!ok) { _log.error("Add alias failed"); - // send status message... + status = SessionStatusMessage.STATUS_REFUSED; } + } else { + _log.error("no primary config?"); + status = SessionStatusMessage.STATUS_INVALID; } + sendStatusMessage(id, status); } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/AliasedTunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/AliasedTunnelPool.java new file mode 100644 index 0000000000..05132c9ade --- /dev/null +++ b/router/java/src/net/i2p/router/tunnel/pool/AliasedTunnelPool.java @@ -0,0 +1,141 @@ +package net.i2p.router.tunnel.pool; + +import java.util.List; + +import net.i2p.data.Hash; +import net.i2p.data.LeaseSet; +import net.i2p.data.TunnelId; +import net.i2p.router.RouterContext; +import net.i2p.router.TunnelInfo; +import net.i2p.router.TunnelPoolSettings; +import net.i2p.util.Log; + +/** + * A tunnel pool with its own settings and Destination, + * but uses another pool for its tunnels. + * + * @since 0.9.20 + */ +public class AliasedTunnelPool extends TunnelPool { + + private final TunnelPool _aliasOf; + + AliasedTunnelPool(RouterContext ctx, TunnelPoolManager mgr, TunnelPoolSettings settings, TunnelPool aliasOf) { + super(ctx, mgr, settings, null); + if (settings.isExploratory()) + throw new IllegalArgumentException(); + if (settings.getAliasOf() == null) + throw new IllegalArgumentException(); + _aliasOf = aliasOf; + } + + @Override + synchronized void startup() { + if (_log.shouldLog(Log.INFO)) + _log.info(toString() + ": Startup() called, was already alive? " + _alive, new Exception()); + _alive = true; + } + + @Override + synchronized void shutdown() { + if (_log.shouldLog(Log.WARN)) + _log.warn(toString() + ": Shutdown called"); + _alive = false; + } + + @Override + TunnelInfo selectTunnel() { + return _aliasOf.selectTunnel(); + } + + @Override + TunnelInfo selectTunnel(Hash closestTo) { + return _aliasOf.selectTunnel(closestTo); + } + + @Override + public TunnelInfo getTunnel(TunnelId gatewayId) { + return _aliasOf.getTunnel(gatewayId); + } + + @Override + public List<TunnelInfo> listTunnels() { + return _aliasOf.listTunnels(); + } + + @Override + boolean needFallback() { + return false; + } + + @Override + public List<PooledTunnelCreatorConfig> listPending() { + return _aliasOf.listPending(); + } + + @Override + public boolean isAlive() { + return _alive && _aliasOf.isAlive(); + } + + @Override + public int size() { + return _aliasOf.size(); + } + + @Override + void addTunnel(TunnelInfo info) { + _aliasOf.addTunnel(info); + } + + @Override + void removeTunnel(TunnelInfo info) { + _aliasOf.removeTunnel(info); + } + + @Override + void tunnelFailed(TunnelInfo cfg) { + _aliasOf.tunnelFailed(cfg); + } + + @Override + void tunnelFailed(TunnelInfo cfg, Hash blamePeer) { + _aliasOf.tunnelFailed(cfg, blamePeer); + } + + @Override + void refreshLeaseSet() {} + + @Override + boolean buildFallback() { + return _aliasOf.buildFallback(); + } + + @Override + protected LeaseSet locked_buildNewLeaseSet() { + return _context.netDb().lookupLeaseSetLocally(_aliasOf.getSettings().getDestination()); + } + + @Override + public long getLifetimeProcessed() { + return _aliasOf.getLifetimeProcessed(); + } + + @Override + int countHowManyToBuild() { + return 0; + } + + @Override + PooledTunnelCreatorConfig configureNewTunnel() { + return null; + } + + @Override + void buildComplete(PooledTunnelCreatorConfig cfg) {} + + @Override + public String toString() { + return "Aliased " + super.toString(); + } +} diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java index e30a0faddd..b69caa7896 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -31,13 +31,13 @@ import net.i2p.util.Log; */ public class TunnelPool { private final List<PooledTunnelCreatorConfig> _inProgress = new ArrayList<PooledTunnelCreatorConfig>(); - private final RouterContext _context; - private final Log _log; + protected final RouterContext _context; + protected final Log _log; private TunnelPoolSettings _settings; private final List<TunnelInfo> _tunnels; private final TunnelPeerSelector _peerSelector; private final TunnelPoolManager _manager; - private volatile boolean _alive; + protected volatile boolean _alive; private long _lifetimeProcessed; private TunnelInfo _lastSelected; private long _lastSelectionPeriod; @@ -119,19 +119,15 @@ public class TunnelPool { } } - void refreshSettings() { - if (!_settings.isExploratory()) { + private void refreshSettings() { + if (!_settings.isExploratory()) return; // don't override client specified settings - } else { - if (_settings.isExploratory()) { - Properties props = new Properties(); - props.putAll(_context.router().getConfigMap()); - if (_settings.isInbound()) - _settings.readFromProperties(TunnelPoolSettings.PREFIX_INBOUND_EXPLORATORY, props); - else - _settings.readFromProperties(TunnelPoolSettings.PREFIX_OUTBOUND_EXPLORATORY, props); - } - } + Properties props = new Properties(); + props.putAll(_context.router().getConfigMap()); + if (_settings.isInbound()) + _settings.readFromProperties(TunnelPoolSettings.PREFIX_INBOUND_EXPLORATORY, props); + else + _settings.readFromProperties(TunnelPoolSettings.PREFIX_OUTBOUND_EXPLORATORY, props); } /** @@ -413,11 +409,15 @@ public class TunnelPool { public List<PooledTunnelCreatorConfig> listPending() { synchronized (_inProgress) { return new ArrayList<PooledTunnelCreatorConfig>(_inProgress); } } /** duplicate of size(), let's pick one */ - int getTunnelCount() { synchronized (_tunnels) { return _tunnels.size(); } } + int getTunnelCount() { return size(); } public TunnelPoolSettings getSettings() { return _settings; } void setSettings(TunnelPoolSettings settings) { + if (settings != null && _settings != null) { + settings.getAliases().addAll(_settings.getAliases()); + settings.setAliasOf(_settings.getAliasOf()); + } _settings = settings; if (_settings != null) { if (_log.shouldLog(Log.INFO)) @@ -717,7 +717,7 @@ public class TunnelPool { * * @return null on failure */ - private LeaseSet locked_buildNewLeaseSet() { + protected LeaseSet locked_buildNewLeaseSet() { if (!_alive) 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 6cba6ef4b6..f318b479de 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -451,14 +451,35 @@ public class TunnelPoolManager implements TunnelManagerFacade { Hash h = dest.calculateHash(); Hash e = existingClient.calculateHash(); synchronized(this) { - TunnelPool inbound = _clientInboundPools.get(e); - TunnelPool outbound = _clientOutboundPools.get(e); -/////// gah same tunnel pool or different? - if (inbound == null || outbound == null) + TunnelPool inbound = _clientInboundPools.get(h); + TunnelPool outbound = _clientOutboundPools.get(h); + if (inbound != null || outbound != null) { + if (_log.shouldLog(Log.WARN)) + _log.warn("already have alias " + dest); + return false; + } + TunnelPool eInbound = _clientInboundPools.get(e); + TunnelPool eOutbound = _clientOutboundPools.get(e); + if (eInbound == null || eOutbound == null) { + if (_log.shouldLog(Log.WARN)) + _log.warn("primary not found " + existingClient); return false; + } + eInbound.getSettings().getAliases().add(h); + eOutbound.getSettings().getAliases().add(h); + TunnelPoolSettings newIn = settings.getInboundSettings(); + TunnelPoolSettings newOut = settings.getOutboundSettings(); + newIn.setAliasOf(e); + newOut.setAliasOf(e); + inbound = new AliasedTunnelPool(_context, this, newIn, eInbound); + outbound = new AliasedTunnelPool(_context, this, newOut, eOutbound); _clientInboundPools.put(h, inbound); _clientOutboundPools.put(h, outbound); + inbound.startup(); + outbound.startup(); } + if (_log.shouldLog(Log.WARN)) + _log.warn("Added " + h + " as alias for " + e + " with settings " + settings); return true; } @@ -483,9 +504,9 @@ public class TunnelPoolManager implements TunnelManagerFacade { } TunnelPool outbound = _clientOutboundPools.remove(h); if (outbound != null) { - Hash p = inbound.getSettings().getAliasOf(); + Hash p = outbound.getSettings().getAliasOf(); if (p != null) { - TunnelPool pri = _clientInboundPools.get(p); + TunnelPool pri = _clientOutboundPools.get(p); if (pri != null) { Set<Hash> aliases = pri.getSettings().getAliases(); if (aliases != null) -- GitLab