use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.
the class RouterThrottleImpl method cancelShutdownStatus.
/**
* @since 0.8.12
*/
public void cancelShutdownStatus() {
// try hard to guess the state, before we actually get a request
int maxTunnels = _context.getProperty(PROP_MAX_TUNNELS, DEFAULT_MAX_TUNNELS);
RouterInfo ri = _context.router().getRouterInfo();
if (maxTunnels > 0 && !_context.router().isHidden() && ri != null && !ri.getBandwidthTier().equals("K")) {
setTunnelStatus(_x("Accepting tunnels"));
} else {
setTunnelStatus(_x("Rejecting tunnels"));
}
}
use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.
the class StatisticsManager method publishStatistics.
/**
* Retrieve a snapshot of the statistics that should be published.
*
* This includes all standard options (as of 0.9.24, network ID and caps)
*
* @param h current router hash, non-null
* @since 0.9.24
*/
public Properties publishStatistics(Hash h) {
Properties stats = new Properties();
stats.setProperty("router.version", RouterVersion.VERSION);
// never used
// stats.setProperty("coreVersion", CoreVersion.VERSION);
stats.setProperty(RouterInfo.PROP_NETWORK_ID, _networkID);
stats.setProperty(RouterInfo.PROP_CAPABILITIES, _context.router().getCapabilities());
if (_context.getBooleanPropertyDefaultTrue(PROP_PUBLISH_RANKINGS) && _context.random().nextInt(RANDOM_INCLUDE_STATS) == 0) {
// long publishedUptime = _context.router().getUptime();
// Don't publish these for first hour
// Disabled in 0.9
// if (publishedUptime > 62*60*1000)
// includeAverageThroughput(stats);
// includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
// includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
// includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
// includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
// includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
// includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
// includeRate("tunnel.testFailedTime", stats, new long[] { 10*60*1000 });
// includeRate("tunnel.batchDelaySent", stats, new long[] { 10*60*1000, 60*60*1000 });
// includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
// includeRate("tunnel.corruptMessage", stats, new long[] { 60*60*1000l, 3*60*60*1000l });
// includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 });
// includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 });
// includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 });
// includeRate("router.fastPeers", stats, new long[] { 60*60*1000 });
// includeRate("udp.statusOK", stats, new long[] { 20*60*1000 });
// includeRate("udp.statusDifferent", stats, new long[] { 20*60*1000 });
// includeRate("udp.statusReject", stats, new long[] { 20*60*1000 });
// includeRate("udp.statusUnknown", stats, new long[] { 20*60*1000 });
// includeRate("udp.statusKnownCharlie", stats, new long[] { 1*60*1000, 10*60*1000 });
// includeRate("udp.addressUpdated", stats, new long[] { 1*60*1000 });
// includeRate("udp.addressTestInsteadOfUpdate", stats, new long[] { 1*60*1000 });
// includeRate("clock.skew", stats, new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*1000 });
// includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 });
// includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l });
// includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*60*1000 });
// total event count can be used to track uptime
includeRate("tunnel.participatingTunnels", stats, new long[] { 60 * 60 * 1000 }, true);
// includeRate("tunnel.testSuccessTime", stats, new long[] { 10*60*1000l });
// includeRate("client.sendAckTime", stats, new long[] { 60*60*1000 }, true);
// includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
// includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
// includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 60*1000 });
// includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
// includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 });
// includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 });
// stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
// includeRate("tunnel.decryptRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
// includeRate("udp.packetDequeueTime", stats, new long[] { 60*1000 });
// includeRate("udp.packetVerifyTime", stats, new long[] { 60*1000 });
// includeRate("tunnel.buildRequestTime", stats, new long[] { 10*60*1000 });
long rate = 60 * 60 * 1000;
// includeTunnelRates("Client", stats, rate);
includeTunnelRates("Exploratory", stats, rate);
// includeRate("tunnel.rejectTimeout", stats, new long[] { 10*60*1000 });
// includeRate("tunnel.rejectOverloaded", stats, new long[] { 10*60*1000 });
// includeRate("tunnel.acceptLoad", stats, new long[] { 10*60*1000 });
}
// stats.setProperty("stat_uptime", "90m");
if (FloodfillNetworkDatabaseFacade.isFloodfill(_context.router().getRouterInfo())) {
int ri = _context.router().getUptime() > 30 * 60 * 1000 ? _context.netDb().getKnownRouters() : // so it isn't obvious we restarted
3000 + _context.random().nextInt(1000);
stats.setProperty("netdb.knownRouters", String.valueOf(ri));
int ls = _context.router().getUptime() > 30 * 60 * 1000 ? _context.netDb().getKnownLeaseSets() : // so it isn't obvious we restarted
30 + _context.random().nextInt(40);
stats.setProperty("netdb.knownLeaseSets", String.valueOf(ls));
}
String contact = _context.getProperty(PROP_CONTACT_NAME);
if (contact != null)
stats.setProperty("contact", contact);
String family = _context.getProperty(FamilyKeyCrypto.PROP_FAMILY_NAME);
if (family != null) {
stats.setProperty(FamilyKeyCrypto.OPT_NAME, family);
String sig = null;
String key = null;
RouterInfo oldRI = _context.router().getRouterInfo();
if (oldRI != null) {
// don't do it if family changed
if (family.equals(oldRI.getOption(FamilyKeyCrypto.OPT_NAME))) {
// copy over the pubkey and signature
key = oldRI.getOption(FamilyKeyCrypto.OPT_KEY);
if (key != null) {
if (key.contains(";")) {
// we changed the separator from ';' to ':'
key = null;
} else {
stats.setProperty(FamilyKeyCrypto.OPT_KEY, key);
sig = oldRI.getOption(FamilyKeyCrypto.OPT_SIG);
if (sig != null)
stats.setProperty(FamilyKeyCrypto.OPT_SIG, sig);
}
}
}
}
if (sig == null || key == null) {
FamilyKeyCrypto fkc = _context.router().getFamilyKeyCrypto();
if (fkc != null) {
try {
stats.putAll(fkc.sign(family, h));
} catch (GeneralSecurityException gse) {
_log.error("Failed to sign router family", gse);
stats.remove(FamilyKeyCrypto.OPT_KEY);
stats.remove(FamilyKeyCrypto.OPT_SIG);
}
}
}
}
return stats;
}
use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.
the class FloodfillMonitorJob method shouldBeFloodfill.
private boolean shouldBeFloodfill() {
if (!SigType.ECDSA_SHA256_P256.isAvailable())
return false;
// Hidden trumps netDb.floodfillParticipant=true
if (getContext().router().isHidden())
return false;
String enabled = getContext().getProperty(PROP_FLOODFILL_PARTICIPANT, "auto");
if ("true".equals(enabled))
return true;
if ("false".equals(enabled))
return false;
// Only if not shutting down...
if (getContext().router().gracefulShutdownInProgress())
return false;
// ARM ElG decrypt is too slow
if (SystemVersion.isARM() || SystemVersion.isAndroid())
return false;
if (getContext().getBooleanProperty(UDPTransport.PROP_LAPTOP_MODE))
return false;
// need IPv4 - The setting is the same for both SSU and NTCP, so just take the SSU one
if (TransportUtil.getIPv6Config(getContext(), "SSU") == TransportUtil.IPv6Config.IPV6_ONLY)
return false;
// need both transports
if (!TransportManager.isNTCPEnabled(getContext()))
return false;
if (!getContext().getBooleanPropertyDefaultTrue(TransportManager.PROP_ENABLE_UDP))
return false;
if (getContext().commSystem().isInBadCountry())
return false;
String country = getContext().commSystem().getOurCountry();
// anonymous proxy, satellite provider (not in bad country list)
if ("a1".equals(country) || "a2".equals(country))
return false;
// Only if up a while...
if (getContext().router().getUptime() < MIN_UPTIME)
return false;
RouterInfo ri = getContext().router().getRouterInfo();
if (ri == null)
return false;
char bw = ri.getBandwidthTier().charAt(0);
// Only if class M, N, O, P, X
if (bw != Router.CAPABILITY_BW64 && bw != Router.CAPABILITY_BW128 && bw != Router.CAPABILITY_BW256 && bw != Router.CAPABILITY_BW512 && bw != Router.CAPABILITY_BW_UNLIMITED)
return false;
// This list will not include ourselves...
List<Hash> floodfillPeers = _facade.getFloodfillPeers();
long now = getContext().clock().now();
// We know none at all! Must be our turn...
if (floodfillPeers == null || floodfillPeers.isEmpty()) {
_lastChanged = now;
return true;
}
// Only change status every so often
boolean wasFF = _facade.floodfillEnabled();
if (_lastChanged + MIN_CHANGE_DELAY > now)
return wasFF;
// This is similar to the qualification we do in FloodOnlySearchJob.runJob().
// Count the "good" ff peers.
//
// Who's not good?
// the unheard-from, unprofiled, failing, unreachable and banlisted ones.
// We should hear from floodfills pretty frequently so set a 60m time limit.
// If unprofiled we haven't talked to them in a long time.
// We aren't contacting the peer directly, so banlist doesn't strictly matter,
// but it's a bad sign, and we often banlist a peer before we fail it...
//
// Future: use Integration calculation
//
int ffcount = floodfillPeers.size();
int failcount = 0;
long before = now - 60 * 60 * 1000;
for (Hash peer : floodfillPeers) {
PeerProfile profile = getContext().profileOrganizer().getProfile(peer);
if (profile == null || profile.getLastHeardFrom() < before || profile.getIsFailing() || getContext().banlist().isBanlisted(peer) || getContext().commSystem().wasUnreachable(peer))
failcount++;
}
if (wasFF)
ffcount++;
int good = ffcount - failcount;
boolean happy = getContext().router().getRouterInfo().getCapabilities().indexOf('R') >= 0;
// TODO - limit may still be too high
// For reference, the avg lifetime job lag on my Pi is 6.
// Should we consider avg. dropped ff jobs?
RateStat lagStat = getContext().statManager().getRate("jobQueue.jobLag");
RateStat queueStat = getContext().statManager().getRate("router.tunnelBacklog");
happy = happy && lagStat.getRate(60 * 60 * 1000L).getAvgOrLifetimeAvg() < 25;
happy = happy && queueStat.getRate(60 * 60 * 1000L).getAvgOrLifetimeAvg() < 5;
// Only if we're pretty well integrated...
happy = happy && _facade.getKnownRouters() >= 400;
happy = happy && getContext().commSystem().countActivePeers() >= 50;
happy = happy && getContext().tunnelManager().getParticipatingCount() >= 25;
happy = happy && Math.abs(getContext().clock().getOffset()) < 10 * 1000;
// We need an address and no introducers
if (happy) {
RouterAddress ra = getContext().router().getRouterInfo().getTargetAddress("SSU");
if (ra == null)
happy = false;
else {
if (ra.getOption("ihost0") != null)
happy = false;
}
}
double elG = 0;
RateStat stat = getContext().statManager().getRate("crypto.elGamal.decrypt");
if (stat != null) {
Rate rate = stat.getRate(60 * 60 * 1000L);
if (rate != null) {
elG = rate.getAvgOrLifetimeAvg();
happy = happy && elG <= 40.0d;
}
}
if (_log.shouldLog(Log.DEBUG)) {
final RouterContext rc = getContext();
final String log = String.format("FF criteria breakdown: happy=%b, capabilities=%s, maxLag=%d, known=%d, " + "active=%d, participating=%d, offset=%d, ssuAddr=%s ElG=%f", happy, rc.router().getRouterInfo().getCapabilities(), rc.jobQueue().getMaxLag(), _facade.getKnownRouters(), rc.commSystem().countActivePeers(), rc.tunnelManager().getParticipatingCount(), Math.abs(rc.clock().getOffset()), rc.router().getRouterInfo().getTargetAddress("SSU").toString(), elG);
_log.debug(log);
}
// Too few, and we're reachable, let's volunteer
if (good < MIN_FF && happy) {
if (!wasFF) {
_lastChanged = now;
_log.logAlways(Log.INFO, "Only " + good + " ff peers and we want " + MIN_FF + " so we are becoming floodfill");
}
return true;
}
// Too many, or we aren't reachable, let's stop
if (good > MAX_FF || (good > MIN_FF && !happy)) {
if (wasFF) {
_lastChanged = now;
_log.logAlways(Log.INFO, "Have " + good + " ff peers and we need only " + MIN_FF + " to " + MAX_FF + " so we are disabling floodfill; reachable? " + happy);
}
return false;
}
if (_log.shouldLog(Log.INFO))
_log.info("Have " + good + " ff peers, not changing, enabled? " + wasFF + "; reachable? " + happy);
return wasFF;
}
use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.
the class FloodfillNetworkDatabaseFacade method shutdown.
/**
* If we are floodfill, turn it off and tell everybody.
* @since 0.8.9
*/
@Override
public synchronized void shutdown() {
// only if not forced ff or not restarting
if (_floodfillEnabled && (!_context.getBooleanProperty(FloodfillMonitorJob.PROP_FLOODFILL_PARTICIPANT) || !(_context.router().scheduledGracefulExitCode() == Router.EXIT_HARD_RESTART || _context.router().scheduledGracefulExitCode() == Router.EXIT_GRACEFUL_RESTART))) {
// turn off to build a new RI...
_floodfillEnabled = false;
// true -> publish inline
// but job queue is already shut down, so sendStore() called by rebuildRouterInfo() won't work...
_context.router().rebuildRouterInfo(true);
// ...so force a flood here
RouterInfo local = _context.router().getRouterInfo();
if (local != null && _context.router().getUptime() > PUBLISH_JOB_DELAY) {
flood(local);
// let the messages get out...
try {
Thread.sleep(3000);
} catch (InterruptedException ie) {
}
}
}
_context.jobQueue().removeJob(_ffMonitor);
super.shutdown();
}
use of net.i2p.data.router.RouterInfo in project i2p.i2p by i2p.
the class FloodfillPeerSelector method selectFloodfillParticipantsIncludingUs.
/**
* See above for description
* List MAY CONTAIN our own hash unless included in toIgnore
* @param key the ROUTING key (NOT the original key)
* @param toIgnore can be null
* @param kbuckets now unused
*/
private List<Hash> selectFloodfillParticipantsIncludingUs(Hash key, int howMany, Set<Hash> toIgnore, KBucketSet<Hash> kbuckets) {
List<Hash> ffs = selectFloodfillParticipants(toIgnore, kbuckets);
TreeSet<Hash> sorted = new TreeSet<Hash>(new XORComparator<Hash>(key));
sorted.addAll(ffs);
List<Hash> rv = new ArrayList<Hash>(howMany);
List<Hash> okff = new ArrayList<Hash>(ffs.size());
List<Hash> badff = new ArrayList<Hash>(ffs.size());
int found = 0;
long now = _context.clock().now();
long installed = _context.getProperty("router.firstInstalled", 0L);
boolean enforceHeard = installed > 0 && (now - installed) > INSTALL_AGE;
double maxFailRate = 100;
if (_context.router().getUptime() > 60 * 60 * 1000) {
RateStat rs = _context.statManager().getRate("peer.failedLookupRate");
if (rs != null) {
Rate r = rs.getRate(60 * 60 * 1000);
if (r != null) {
double currentFailRate = r.getAverageValue();
maxFailRate = Math.max(0.20d, 1.5d * currentFailRate);
}
}
}
// 5 == FNDF.MAX_TO_FLOOD + 1
int limit = Math.max(5, howMany);
limit = Math.min(limit, ffs.size());
MaskedIPSet maskedIPs = new MaskedIPSet(limit * 3);
// split sorted list into 3 sorted lists
for (int i = 0; found < howMany && i < limit; i++) {
Hash entry = sorted.first();
if (entry == null)
// shouldn't happen
break;
sorted.remove(entry);
// put anybody in the same /16 at the end
RouterInfo info = _context.netDb().lookupRouterInfoLocally(entry);
MaskedIPSet entryIPs = new MaskedIPSet(_context, entry, info, 2);
boolean sameIP = false;
for (String ip : entryIPs) {
if (!maskedIPs.add(ip))
sameIP = true;
}
if (sameIP) {
badff.add(entry);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Same /16, family, or port: " + entry);
} else if (info != null && now - info.getPublished() > 3 * 60 * 60 * 1000) {
badff.add(entry);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Old: " + entry);
} else if (info != null && _context.commSystem().isInBadCountry(info)) {
badff.add(entry);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Bad country: " + entry);
} else if (info != null && info.getBandwidthTier().equals("L")) {
badff.add(entry);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Slow: " + entry);
} else {
PeerProfile prof = _context.profileOrganizer().getProfile(entry);
double maxGoodRespTime = MAX_GOOD_RESP_TIME;
RateStat ttst = _context.statManager().getRate("tunnel.testSuccessTime");
if (ttst != null) {
Rate tunnelTestTime = ttst.getRate(10 * 60 * 1000);
if (tunnelTestTime != null && tunnelTestTime.getAverageValue() > 500)
maxGoodRespTime = 2 * tunnelTestTime.getAverageValue();
}
if (prof != null) {
if (enforceHeard && prof.getFirstHeardAbout() > now - HEARD_AGE) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Bad (new): " + entry);
badff.add(entry);
} else if (prof.getDBHistory() != null) {
if (prof.getDbResponseTime().getRate(10 * 60 * 1000).getAverageValue() < maxGoodRespTime && prof.getDBHistory().getLastStoreFailed() < now - NO_FAIL_STORE_GOOD && prof.getDBHistory().getLastLookupFailed() < now - NO_FAIL_LOOKUP_GOOD && prof.getDBHistory().getFailedLookupRate().getRate(60 * 60 * 1000).getAverageValue() < maxFailRate) {
// good
if (_log.shouldLog(Log.DEBUG))
_log.debug("Good: " + entry);
rv.add(entry);
found++;
} else if (prof.getDBHistory().getLastStoreFailed() <= prof.getDBHistory().getLastStoreSuccessful() || prof.getDBHistory().getLastLookupFailed() <= prof.getDBHistory().getLastLookupSuccessful() || (prof.getDBHistory().getLastStoreFailed() < now - NO_FAIL_STORE_OK && prof.getDBHistory().getLastLookupFailed() < now - NO_FAIL_LOOKUP_OK)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("OK: " + entry);
okff.add(entry);
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Bad (DB): " + entry);
badff.add(entry);
}
} else {
// no DBHistory
if (_log.shouldLog(Log.DEBUG))
_log.debug("Bad (no hist): " + entry);
badff.add(entry);
}
} else {
// no profile
if (_log.shouldLog(Log.DEBUG))
_log.debug("Bad (no prof): " + entry);
badff.add(entry);
}
}
}
if (_log.shouldLog(Log.INFO))
_log.info("Good: " + rv + " OK: " + okff + " Bad: " + badff);
// Put the ok floodfills after the good floodfills
for (int i = 0; found < howMany && i < okff.size(); i++) {
rv.add(okff.get(i));
found++;
}
// Put the "bad" floodfills after the ok floodfills
for (int i = 0; found < howMany && i < badff.size(); i++) {
rv.add(badff.get(i));
found++;
}
return rv;
}
Aggregations