diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 2a0f9ed4a76cbadcc04cb1677fc4d76bd6bb905d..6990f2a51d73bf323572df1d874e007aa9311365 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 1e75fa409e98d64a29dccb838a6cd8e622329c8b..9dcf04e72d2cbd355286a99e56f9ed7351d3e33a 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 e12205e8305c82d21c10bb3964cce69351e4463e..ead5dcd2628f2123c15294e68455ca6de125031a 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 0000000000000000000000000000000000000000..05132c9adeeee29895b5d94ce63b258970b45501 --- /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 e30a0faddd3d7d9d01b56630105bc775eb823db8..b69caa7896cca678071014a352afba859a02e025 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 6cba6ef4b6dfc1bed1e850339335b13cc255d4dc..f318b479de28b7e3fd68960ec9f1d991288a93a5 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)