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
This commit is contained in:
zzz
2015-04-19 01:32:30 +00:00
parent 57b641bf63
commit be8f7f9676
6 changed files with 206 additions and 33 deletions

View File

@ -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);
}
}

View File

@ -114,7 +114,8 @@ class SubSession extends I2PSessionMuxedImpl {
*/
@Override
public boolean isClosed() {
return getSessionId() == null || _primary.isClosed();
// FIXME
return /* getSessionId() == null || */ _primary.isClosed();
}
/**

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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,11 +119,9 @@ 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())
@ -131,8 +129,6 @@ public class TunnelPool {
else
_settings.readFromProperties(TunnelPoolSettings.PREFIX_OUTBOUND_EXPLORATORY, props);
}
}
}
/**
* when selecting tunnels, stick with the same one for a brief
@ -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;

View File

@ -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)