use of net.i2p.router.util.MaskedIPSet in project i2p.i2p by i2p.
the class ProfileOrganizer method locked_selectPeers.
/**
* As of 0.9.24, checks for a netdb family match as well, unless mask == 0.
*
* @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should
* not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match
*/
private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, int mask) {
List<Hash> all = new ArrayList<Hash>(peers.keySet());
MaskedIPSet IPSet = new MaskedIPSet(16);
// use RandomIterator to avoid shuffling the whole thing
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
Hash peer = iter.next();
if (toExclude != null && toExclude.contains(peer))
continue;
if (matches.contains(peer))
continue;
if (_us.equals(peer))
continue;
boolean ok = isSelectable(peer);
if (ok) {
ok = mask <= 0 || notRestricted(peer, IPSet, mask);
if ((!ok) && _log.shouldLog(Log.WARN))
_log.warn("IP restriction prevents " + peer + " from joining " + matches);
}
if (ok)
matches.add(peer);
else
matches.remove(peer);
}
}
use of net.i2p.router.util.MaskedIPSet in project i2p.i2p by i2p.
the class FloodfillVerifyStoreJob method pickTarget.
/**
* Pick a responsive floodfill close to the key, but not the one we sent to
*/
private Hash pickTarget() {
Hash rkey = getContext().routingKeyGenerator().getRoutingKey(_key);
FloodfillPeerSelector sel = (FloodfillPeerSelector) _facade.getPeerSelector();
Certificate keyCert = null;
if (!_isRouterInfo) {
Destination dest = _facade.lookupDestinationLocally(_key);
if (dest != null) {
Certificate cert = dest.getCertificate();
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY)
keyCert = cert;
}
}
if (keyCert != null) {
while (true) {
List<Hash> peers = sel.selectFloodfillParticipants(rkey, 1, _ignore, _facade.getKBuckets());
if (peers.isEmpty())
break;
Hash peer = peers.get(0);
RouterInfo ri = _facade.lookupRouterInfoLocally(peer);
// if (ri != null && StoreJob.supportsCert(ri, keyCert)) {
if (ri != null && StoreJob.shouldStoreTo(ri)) {
Set<String> peerIPs = new MaskedIPSet(getContext(), ri, IP_CLOSE_BYTES);
if (!_ipSet.containsAny(peerIPs)) {
_ipSet.addAll(peerIPs);
return peer;
} else {
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Skipping verify w/ router too close to the store " + peer);
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Skipping verify w/ router that is too old " + peer);
}
_ignore.add(peer);
}
} else {
List<Hash> peers = sel.selectFloodfillParticipants(rkey, 1, _ignore, _facade.getKBuckets());
if (!peers.isEmpty())
return peers.get(0);
}
if (_log.shouldLog(Log.WARN))
_log.warn("No other peers to verify floodfill with, using the one we sent to");
return _sentTo;
}
use of net.i2p.router.util.MaskedIPSet in project i2p.i2p by i2p.
the class IterativeSearchJob method retry.
/**
* Send lookups to one or more peers, up to the configured concurrent and total limits
*/
private void retry() {
long now = getContext().clock().now();
if (_expiration < now) {
failed();
return;
}
if (_expiration - 500 < now) {
// not enough time left to bother
return;
}
while (true) {
Hash peer = null;
final int done, pend;
synchronized (this) {
if (_dead)
return;
pend = _unheardFrom.size();
if (pend >= _maxConcurrent)
return;
done = _failedPeers.size();
}
if (done >= _totalSearchLimit) {
failed();
return;
}
// coming via newPeerToTry()
if (done + pend >= _totalSearchLimit)
return;
synchronized (this) {
if (_alwaysQueryHash != null && !_unheardFrom.contains(_alwaysQueryHash) && !_failedPeers.contains(_alwaysQueryHash)) {
// For testing or local networks... we will
// pretend that the specified router is floodfill, and always closest-to-the-key.
// May be set after startup but can't be changed or unset later.
// Warning - experts only!
peer = _alwaysQueryHash;
} else {
if (_toTry.isEmpty())
return;
for (Iterator<Hash> iter = _toTry.iterator(); iter.hasNext(); ) {
Hash h = iter.next();
iter.remove();
Set<String> peerIPs = new MaskedIPSet(getContext(), h, IP_CLOSE_BYTES);
if (!_ipSet.containsAny(peerIPs)) {
_ipSet.addAll(peerIPs);
peer = h;
break;
}
if (_log.shouldLog(Log.INFO))
_log.info(getJobId() + ": Skipping query w/ router too close to others " + h);
_skippedPeers.add(h);
// go around again
}
if (peer == null)
return;
}
_unheardFrom.add(peer);
}
sendQuery(peer);
}
}
use of net.i2p.router.util.MaskedIPSet 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