Compare commits

...

3 Commits

Author SHA1 Message Date
zzz
020d49d977 Remove call to useSubDbs() which is going away 2023-10-27 07:35:44 -04:00
zzz
238922b923 I2CP: Fix NPEs caused by previous checkin
Because CCR.getFloodfillNetworkDatabaseFacade() may now return null.

- Revert -1 changes to get/setBlindData() calls, we always use main DB now
  (was not addressed in previous fixes for #421)
- Use main DB if runner doesn't have a subdb yet in LookupDestJob

thx drzed
2023-10-25 12:21:22 -04:00
zzz
630617ad1f NetDB: Fix lifecycle issues for subsessions (Gitlab #460, #406)
This fixes bugs introduced in MR !120,
fixes minor issues from that MR that were not addressed,
and merges in my proposed changes from that MR that were not used.

- Don't create subdb for subsession and lose ref for primary subsession;
  this caused the primary LS to not be found when attempting to create subsession LS
  at startup, so subsession LS was not created until primary LS was rebuilt
- Remove useless null checks
- Simplify CCR.getFNDF() to simply return the subdb or null; nothing else is necessary
  because the null return is handled in FNDS.
- Fix javadocs to correct errors and clearly state whether returns non-null or may be null.
- Add KNDF.toString() for use in logging
- Log tweaks
2023-10-25 06:49:20 -04:00
8 changed files with 92 additions and 74 deletions

View File

@@ -375,7 +375,18 @@ public class RouterContext extends I2PAppContext {
public SegmentedNetworkDatabaseFacade netDbSegmentor() { return _netDb; } public SegmentedNetworkDatabaseFacade netDbSegmentor() { return _netDb; }
public FloodfillNetworkDatabaseFacade netDb() { return _netDb.mainNetDB(); } public FloodfillNetworkDatabaseFacade netDb() { return _netDb.mainNetDB(); }
public FloodfillNetworkDatabaseFacade multihomeNetDb() { return _netDb.multiHomeNetDB(); } public FloodfillNetworkDatabaseFacade multihomeNetDb() { return _netDb.multiHomeNetDB(); }
/**
* Get the client netDb for the given id.
* Will return the main netDb if
* the dbid is null or the client db is not found.
*
* @param id may be null
* @return non-null
* @since 0.9.60
*/
public FloodfillNetworkDatabaseFacade clientNetDb(Hash id) { return _netDb.clientNetDB(id); } public FloodfillNetworkDatabaseFacade clientNetDb(Hash id) { return _netDb.clientNetDB(id); }
/** /**
* The actual driver of the router, where all jobs are enqueued and processed. * The actual driver of the router, where all jobs are enqueued and processed.
*/ */

View File

@@ -49,9 +49,8 @@ import net.i2p.router.JobImpl;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.crypto.TransientSessionKeyManager; import net.i2p.router.crypto.TransientSessionKeyManager;
import net.i2p.router.crypto.ratchet.RatchetSKM; import net.i2p.router.crypto.ratchet.RatchetSKM;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseSegmentor;
import net.i2p.router.crypto.ratchet.MuxedSKM; import net.i2p.router.crypto.ratchet.MuxedSKM;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.util.ConcurrentHashSet; import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
@@ -160,8 +159,6 @@ class ClientConnectionRunner {
_alreadyProcessed = new ArrayList<MessageId>(); _alreadyProcessed = new ArrayList<MessageId>();
_acceptedPending = new ConcurrentHashSet<MessageId>(); _acceptedPending = new ConcurrentHashSet<MessageId>();
_messageId = new AtomicInteger(_context.random().nextInt()); _messageId = new AtomicInteger(_context.random().nextInt());
// Set up the per-destination FloodfillNetworkDatabaseFacade to prevent clients from being able to
// update leaseSet entries in the floodfill netDb
} }
private static final AtomicInteger __id = new AtomicInteger(); private static final AtomicInteger __id = new AtomicInteger();
@@ -213,9 +210,6 @@ class ClientConnectionRunner {
_acceptedPending.clear(); _acceptedPending.clear();
if (_sessionKeyManager != null) if (_sessionKeyManager != null)
_sessionKeyManager.shutdown(); _sessionKeyManager.shutdown();
if (_floodfillNetworkDatabaseFacade != null)
if (_floodfillNetworkDatabaseFacade.isClientDb())
_floodfillNetworkDatabaseFacade.shutdown();
if (_encryptedLSHash != null) if (_encryptedLSHash != null)
_manager.unregisterEncryptedDestination(this, _encryptedLSHash); _manager.unregisterEncryptedDestination(this, _encryptedLSHash);
_manager.unregisterConnection(this); _manager.unregisterConnection(this);
@@ -226,12 +220,12 @@ class ClientConnectionRunner {
// _sessions will be empty. // _sessions will be empty.
for (SessionParams sp : _sessions.values()) { for (SessionParams sp : _sessions.values()) {
LeaseSet ls = sp.currentLeaseSet; LeaseSet ls = sp.currentLeaseSet;
if (ls != null && getFloodfillNetworkDatabaseFacade() != null) if (ls != null)
getFloodfillNetworkDatabaseFacade().unpublish(ls); _context.netDb().unpublish(ls);
// unpublish encrypted LS also // unpublish encrypted LS also
ls = sp.currentEncryptedLeaseSet; ls = sp.currentEncryptedLeaseSet;
if (ls != null && getFloodfillNetworkDatabaseFacade() != null) if (ls != null)
getFloodfillNetworkDatabaseFacade().unpublish(ls); _context.netDb().unpublish(ls);
if (!sp.isPrimary) if (!sp.isPrimary)
_context.tunnelManager().removeAlias(sp.dest); _context.tunnelManager().removeAlias(sp.dest);
} }
@@ -242,6 +236,8 @@ class ClientConnectionRunner {
sp.rerequestTimer.cancel(); sp.rerequestTimer.cancel();
} }
} }
if (_floodfillNetworkDatabaseFacade != null)
_floodfillNetworkDatabaseFacade.shutdown();
synchronized (_alreadyProcessed) { synchronized (_alreadyProcessed) {
_alreadyProcessed.clear(); _alreadyProcessed.clear();
} }
@@ -467,12 +463,12 @@ class ClientConnectionRunner {
// Tell client manger // Tell client manger
_manager.unregisterSession(id, sp.dest); _manager.unregisterSession(id, sp.dest);
LeaseSet ls = sp.currentLeaseSet; LeaseSet ls = sp.currentLeaseSet;
if (ls != null && getFloodfillNetworkDatabaseFacade() != null) if (ls != null && _floodfillNetworkDatabaseFacade != null)
getFloodfillNetworkDatabaseFacade().unpublish(ls); _floodfillNetworkDatabaseFacade.unpublish(ls);
// unpublish encrypted LS also // unpublish encrypted LS also
ls = sp.currentEncryptedLeaseSet; ls = sp.currentEncryptedLeaseSet;
if (ls != null && getFloodfillNetworkDatabaseFacade() != null) if (ls != null && _floodfillNetworkDatabaseFacade != null)
getFloodfillNetworkDatabaseFacade().unpublish(ls); _floodfillNetworkDatabaseFacade.unpublish(ls);
isPrimary = sp.isPrimary; isPrimary = sp.isPrimary;
if (isPrimary) if (isPrimary)
_context.tunnelManager().removeTunnels(sp.dest); _context.tunnelManager().removeTunnels(sp.dest);
@@ -492,12 +488,12 @@ class ClientConnectionRunner {
_log.info("Destroying remaining client subsession " + sp.sessionId); _log.info("Destroying remaining client subsession " + sp.sessionId);
_manager.unregisterSession(sp.sessionId, sp.dest); _manager.unregisterSession(sp.sessionId, sp.dest);
LeaseSet ls = sp.currentLeaseSet; LeaseSet ls = sp.currentLeaseSet;
if (ls != null && getFloodfillNetworkDatabaseFacade() != null) if (ls != null && _floodfillNetworkDatabaseFacade != null)
getFloodfillNetworkDatabaseFacade().unpublish(ls); _floodfillNetworkDatabaseFacade.unpublish(ls);
// unpublish encrypted LS also // unpublish encrypted LS also
ls = sp.currentEncryptedLeaseSet; ls = sp.currentEncryptedLeaseSet;
if (ls != null && getFloodfillNetworkDatabaseFacade() != null) if (ls != null && _floodfillNetworkDatabaseFacade != null)
getFloodfillNetworkDatabaseFacade().unpublish(ls); _floodfillNetworkDatabaseFacade.unpublish(ls);
_context.tunnelManager().removeAlias(sp.dest); _context.tunnelManager().removeAlias(sp.dest);
synchronized(this) { synchronized(this) {
if (sp.rerequestTimer != null) if (sp.rerequestTimer != null)
@@ -572,18 +568,6 @@ class ClientConnectionRunner {
public int sessionEstablished(SessionConfig config) { public int sessionEstablished(SessionConfig config) {
Destination dest = config.getDestination(); Destination dest = config.getDestination();
Hash destHash = dest.calculateHash(); Hash destHash = dest.calculateHash();
if (destHash != null){
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Initializing subDb for client" + destHash);
}
_floodfillNetworkDatabaseFacade = new FloodfillNetworkDatabaseFacade(_context, destHash);
_floodfillNetworkDatabaseFacade.startup();
} else {
if (_log.shouldLog(Log.ERROR)) {
_log.error("Initializing subDb for unknown client" + dest, new Exception());
}
_floodfillNetworkDatabaseFacade = null;
}
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("SessionEstablished called for destination " + destHash); _log.debug("SessionEstablished called for destination " + destHash);
if (_sessions.size() > MAX_SESSIONS) if (_sessions.size() > MAX_SESSIONS)
@@ -610,6 +594,7 @@ class ClientConnectionRunner {
_dontSendMSM = "none".equals(opts.getProperty(I2PClient.PROP_RELIABILITY, "").toLowerCase(Locale.US)); _dontSendMSM = "none".equals(opts.getProperty(I2PClient.PROP_RELIABILITY, "").toLowerCase(Locale.US));
_dontSendMSMOnReceive = Boolean.parseBoolean(opts.getProperty(I2PClient.PROP_FAST_RECEIVE)); _dontSendMSMOnReceive = Boolean.parseBoolean(opts.getProperty(I2PClient.PROP_FAST_RECEIVE));
} }
// Set up the // Set up the
// per-destination session key manager to prevent rather easy correlation // per-destination session key manager to prevent rather easy correlation
// based on the specified encryption types in the config // based on the specified encryption types in the config
@@ -661,6 +646,12 @@ class ClientConnectionRunner {
} }
} }
} }
if (isPrimary && _floodfillNetworkDatabaseFacade == null) {
if (_log.shouldDebug())
_log.debug("Initializing subDb for client" + destHash);
_floodfillNetworkDatabaseFacade = new FloodfillNetworkDatabaseFacade(_context, destHash);
_floodfillNetworkDatabaseFacade.startup();
}
return _manager.destinationEstablished(this, dest); return _manager.destinationEstablished(this, dest);
} }
@@ -1172,29 +1163,15 @@ class ClientConnectionRunner {
/** /**
* Get the FloodfillNetworkDatabaseFacade for this runner. This is the client * Get the FloodfillNetworkDatabaseFacade for this runner. This is the client
* netDb if the router is configured to use subDbs, or the main netDb if the * netDb.
* router is configured to use a monolithic netDb.
* *
* If neither a client netDb or the main netDb is available, it will return null. * If a session has not been created yet, it will return null.
* This should be impossible.
* If you get the `getFloodfillNetworkDatabaseFacade is null for runner` warning,
* the main netDb will be returned instead. If the main netDb is null, then null
* will be returned.
* *
* @return _floodfillNetworkDatabaseFacade * @return the client netdb or null if no session was created yet
* @since 0.9.60 * @since 0.9.60
*/ */
public FloodfillNetworkDatabaseFacade getFloodfillNetworkDatabaseFacade() { public FloodfillNetworkDatabaseFacade getFloodfillNetworkDatabaseFacade() {
if (!_context.netDbSegmentor().useSubDbs()) return _floodfillNetworkDatabaseFacade;
return _context.netDb();
if (_log.shouldLog(Log.DEBUG))
_log.debug("getFloodfillNetworkDatabaseFacade is getting the subDb for dbid: " + this.getDestHash());
if (_floodfillNetworkDatabaseFacade == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("getFloodfillNetworkDatabaseFacade is null for runner");
return _context.netDb();
}
return this._floodfillNetworkDatabaseFacade;
} }
private class MessageDeliveryStatusUpdate extends JobImpl { private class MessageDeliveryStatusUpdate extends JobImpl {

View File

@@ -777,8 +777,9 @@ class ClientManager {
* get the FloodfillNetworkDatabaseFacade associated with a particular client destination. * get the FloodfillNetworkDatabaseFacade associated with a particular client destination.
* This is inside the runner, so it won't be there if the runner isn't ready. * This is inside the runner, so it won't be there if the runner isn't ready.
* *
* @param destHash destination hash associated with the client who's subDb we're looking for * @param destHash destination hash associated with the client who's subDb we're looking for, may be null
* @return may be null if it does not exist and the main netDb is not initialized * @return will be null if desthash is null or client does not exist or its netDb is not initialized
* @since 0.9.60
*/ */
public FloodfillNetworkDatabaseFacade getClientFloodfillNetworkDatabaseFacade(Hash destHash) { public FloodfillNetworkDatabaseFacade getClientFloodfillNetworkDatabaseFacade(Hash destHash) {
if (destHash != null) { if (destHash != null) {
@@ -801,15 +802,14 @@ class ClientManager {
* get all of the FloodfillNetworkDatabaseFacades for all of the clients. * get all of the FloodfillNetworkDatabaseFacades for all of the clients.
* *
* @return non-null * @return non-null
* @since 0.9.60
*/ */
public Set<FloodfillNetworkDatabaseFacade> getClientFloodfillNetworkDatabaseFacades() { public Set<FloodfillNetworkDatabaseFacade> getClientFloodfillNetworkDatabaseFacades() {
Set<FloodfillNetworkDatabaseFacade> rv = new HashSet<FloodfillNetworkDatabaseFacade>(); Set<FloodfillNetworkDatabaseFacade> rv = new HashSet<FloodfillNetworkDatabaseFacade>();
for (ClientConnectionRunner runner : _runners.values()) { for (ClientConnectionRunner runner : _runners.values()) {
if (runner != null){ FloodfillNetworkDatabaseFacade fndf = runner.getFloodfillNetworkDatabaseFacade();
FloodfillNetworkDatabaseFacade fndf = runner.getFloodfillNetworkDatabaseFacade(); if (fndf != null)
if (fndf != null) rv.add(fndf);
rv.add(fndf);
}
} }
return rv; return rv;
} }
@@ -817,7 +817,8 @@ class ClientManager {
/** /**
* get all the primary hashes for all the clients and return them as a set * get all the primary hashes for all the clients and return them as a set
* *
* @return * @return non-null
* @since 0.9.60
*/ */
public Set<Hash> getPrimaryHashes() { public Set<Hash> getPrimaryHashes() {
Set<Hash> rv = new HashSet<Hash>(); Set<Hash> rv = new HashSet<Hash>();

View File

@@ -861,9 +861,9 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
_log.warn("Unsupported BlindingInfo type: " + message); _log.warn("Unsupported BlindingInfo type: " + message);
return; return;
} }
BlindData obd = _runner.getFloodfillNetworkDatabaseFacade().getBlindData(spk); BlindData obd = _context.netDb().getBlindData(spk);
if (obd == null) { if (obd == null) {
_runner.getFloodfillNetworkDatabaseFacade().setBlindData(bd); _context.netDb().setBlindData(bd);
if (_log.shouldWarn()) if (_log.shouldWarn())
_log.warn("New: " + bd); _log.warn("New: " + bd);
} else { } else {
@@ -884,7 +884,7 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
return; return;
} }
} }
_runner.getFloodfillNetworkDatabaseFacade().setBlindData(bd); _context.netDb().setBlindData(bd);
if (_log.shouldWarn()) if (_log.shouldWarn())
_log.warn("Updated: " + bd); _log.warn("Updated: " + bd);
} else { } else {
@@ -893,7 +893,7 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
if (nexp > oexp) { if (nexp > oexp) {
obd.setExpiration(nexp); obd.setExpiration(nexp);
// to force save at shutdown // to force save at shutdown
_runner.getFloodfillNetworkDatabaseFacade().setBlindData(obd); _context.netDb().setBlindData(obd);
if (_log.shouldWarn()) if (_log.shouldWarn())
_log.warn("Updated expiration: " + obd); _log.warn("Updated expiration: " + obd);
} else { } else {

View File

@@ -21,6 +21,7 @@ import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.I2CPMessageException; import net.i2p.data.i2cp.I2CPMessageException;
import net.i2p.data.i2cp.SessionId; import net.i2p.data.i2cp.SessionId;
import net.i2p.router.JobImpl; import net.i2p.router.JobImpl;
import net.i2p.router.NetworkDatabaseFacade;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.util.Log; import net.i2p.util.Log;
@@ -91,7 +92,7 @@ class LookupDestJob extends JobImpl {
try { try {
bd = Blinding.decode(context, b); bd = Blinding.decode(context, b);
SigningPublicKey spk = bd.getUnblindedPubKey(); SigningPublicKey spk = bd.getUnblindedPubKey();
BlindData bd2 = _runner.getFloodfillNetworkDatabaseFacade().getBlindData(spk); BlindData bd2 = getContext().netDb().getBlindData(spk);
if (bd2 != null) { if (bd2 != null) {
// BlindData from database may have privkey or secret // BlindData from database may have privkey or secret
// check if we need it but don't have it // check if we need it but don't have it
@@ -110,7 +111,7 @@ class LookupDestJob extends JobImpl {
long exp = now + ((bd.getAuthRequired() || bd.getSecretRequired()) ? 365*24*60*60*1000L long exp = now + ((bd.getAuthRequired() || bd.getSecretRequired()) ? 365*24*60*60*1000L
: 90*24*68*60*1000L); : 90*24*68*60*1000L);
bd.setExpiration(exp); bd.setExpiration(exp);
_runner.getFloodfillNetworkDatabaseFacade().setBlindData(bd); getContext().netDb().setBlindData(bd);
} }
h = bd.getBlindedHash(); h = bd.getBlindedHash();
if (_log.shouldDebug()) if (_log.shouldDebug())
@@ -185,7 +186,10 @@ class LookupDestJob extends JobImpl {
if (timeout > 1500) if (timeout > 1500)
timeout -= 500; timeout -= 500;
// TODO tell router this is an encrypted lookup, skip 38 or earlier ffs? // TODO tell router this is an encrypted lookup, skip 38 or earlier ffs?
_runner.getFloodfillNetworkDatabaseFacade().lookupDestination(_hash, done, timeout, _fromLocalDest); NetworkDatabaseFacade db = _runner.getFloodfillNetworkDatabaseFacade();
if (db == null)
db = getContext().netDb();
db.lookupDestination(_hash, done, timeout, _fromLocalDest);
} else { } else {
// blinding decode fail // blinding decode fail
returnFail(HostReplyMessage.RESULT_DECRYPTION_FAILURE); returnFail(HostReplyMessage.RESULT_DECRYPTION_FAILURE);
@@ -204,10 +208,13 @@ class LookupDestJob extends JobImpl {
} }
public String getName() { return "LeaseSet Lookup Reply to Client"; } public String getName() { return "LeaseSet Lookup Reply to Client"; }
public void runJob() { public void runJob() {
Destination dest = _runner.getFloodfillNetworkDatabaseFacade().lookupDestinationLocally(_hash); NetworkDatabaseFacade db = _runner.getFloodfillNetworkDatabaseFacade();
if (db == null)
db = getContext().netDb();
Destination dest = db.lookupDestinationLocally(_hash);
if (dest == null && _blindData != null) { if (dest == null && _blindData != null) {
// TODO store and lookup original hash instead // TODO store and lookup original hash instead
LeaseSet ls = _runner.getFloodfillNetworkDatabaseFacade().lookupLeaseSetLocally(_hash); LeaseSet ls = db.lookupLeaseSetLocally(_hash);
if (ls != null && ls.getType() == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) { if (ls != null && ls.getType() == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
// already decrypted // already decrypted
EncryptedLeaseSet encls = (EncryptedLeaseSet) ls; EncryptedLeaseSet encls = (EncryptedLeaseSet) ls;

View File

@@ -268,12 +268,13 @@ public class FloodfillNetworkDatabaseSegmentor extends SegmentedNetworkDatabaseF
} }
/** /**
* get the client netDb for the given id * Get the client netDb for the given id.
* Will return the "exploratory(default client)" netDb if * Will return the main netDb if
* the dbid is null. * the dbid is null or the client db is not found.
* *
* @param id may be null
* @return non-null
* @since 0.9.60 * @since 0.9.60
* @return may be null if the client netDb does not exist
*/ */
@Override @Override
public FloodfillNetworkDatabaseFacade clientNetDB(Hash id) { public FloodfillNetworkDatabaseFacade clientNetDB(Hash id) {
@@ -286,7 +287,7 @@ public class FloodfillNetworkDatabaseSegmentor extends SegmentedNetworkDatabaseF
if (fndf != null) if (fndf != null)
return fndf; return fndf;
} }
return mainNetDB(); return _mainDbid;
} }
/** /**

View File

@@ -281,6 +281,8 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
* Cannot be restarted. * Cannot be restarted.
*/ */
public synchronized void shutdown() { public synchronized void shutdown() {
if (_log.shouldWarn())
_log.warn("DB shutdown " + this);
_initialized = false; _initialized = false;
if (!_context.commSystem().isDummy() && isMainDb() && if (!_context.commSystem().isDummy() && isMainDb() &&
_context.router().getUptime() > ROUTER_INFO_EXPIRATION_FLOODFILL + 10*60*1000 + 60*1000) { _context.router().getUptime() > ROUTER_INFO_EXPIRATION_FLOODFILL + 10*60*1000 + 60*1000) {
@@ -376,7 +378,8 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
} }
public synchronized void startup() { public synchronized void startup() {
_log.info("Starting up the kademlia network database"); if (_log.shouldInfo())
_log.info("Starting up the " + this);
RouterInfo ri = _context.router().getRouterInfo(); RouterInfo ri = _context.router().getRouterInfo();
String dbDir = _context.getProperty(PROP_DB_DIR, DEFAULT_DB_DIR); String dbDir = _context.getProperty(PROP_DB_DIR, DEFAULT_DB_DIR);
_kb = new KBucketSet<Hash>(_context, ri.getIdentity().getHash(), _kb = new KBucketSet<Hash>(_context, ri.getIdentity().getHash(),
@@ -1702,4 +1705,16 @@ public abstract class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacad
public void renderStatusHTML(Writer out) throws IOException { public void renderStatusHTML(Writer out) throws IOException {
out.write(_kb.toString().replace("\n", "<br>\n")); out.write(_kb.toString().replace("\n", "<br>\n"));
} }
/**
* @since 0.9.60
*/
@Override
public String toString() {
if (isMainDb())
return "Main NetDB";
if (isMultihomeDb())
return "Multihome NetDB";
return "Client NetDB " + _dbid.toBase64();
}
} }

View File

@@ -9,6 +9,7 @@ import net.i2p.data.TunnelId;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.TunnelInfo; import net.i2p.router.TunnelInfo;
import net.i2p.router.TunnelPoolSettings; import net.i2p.router.TunnelPoolSettings;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
@@ -115,9 +116,14 @@ public class AliasedTunnelPool extends TunnelPool {
@Override @Override
protected LeaseSet locked_buildNewLeaseSet() { protected LeaseSet locked_buildNewLeaseSet() {
LeaseSet ls = _context.clientNetDb(_aliasOf.getSettings().getDestination()).lookupLeaseSetLocally(_aliasOf.getSettings().getDestination()); Hash primary = _aliasOf.getSettings().getDestination();
if (ls == null) FloodfillNetworkDatabaseFacade db = _context.clientNetDb(primary);
LeaseSet ls = db.lookupLeaseSetLocally(primary);
if (ls == null) {
if (_log.shouldWarn())
_log.warn("No primary LS " + primary + " to copy for " + getSettings().getDestination() + " in db " + db);
return null; return null;
}
// copy everything so it isn't corrupted // copy everything so it isn't corrupted
LeaseSet rv = new LeaseSet(); LeaseSet rv = new LeaseSet();
for (int i = 0; i < ls.getLeaseCount(); i++) { for (int i = 0; i < ls.getLeaseCount(); i++) {