* Connection limits / throttle:

- Better limits when no inbound TCP
        (limit inbound and outbound separately)
    * GeoIP:
      - Check netDb SSU IP too
      - Check whole netDb at startup
This commit is contained in:
zzz
2009-05-23 19:43:02 +00:00
parent 7feb97e415
commit 7e71ead3e9
4 changed files with 78 additions and 14 deletions

View File

@ -34,7 +34,8 @@ public abstract class CommSystemFacade implements Service {
public int countActivePeers() { return 0; }
public int countActiveSendPeers() { return 0; }
public boolean haveCapacity() { return true; }
public boolean haveInboundCapacity() { return true; }
public boolean haveOutboundCapacity() { return true; }
public List getMostRecentErrorMessages() { return Collections.EMPTY_LIST; }
/**

View File

@ -13,6 +13,7 @@ import java.io.Writer;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -21,6 +22,7 @@ import java.util.Vector;
import net.i2p.data.Hash;
import net.i2p.data.RouterAddress;
import net.i2p.data.RouterInfo;
import net.i2p.router.CommSystemFacade;
import net.i2p.router.OutNetMessage;
import net.i2p.router.RouterContext;
@ -68,7 +70,9 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
@Override
public int countActiveSendPeers() { return (_manager == null ? 0 : _manager.countActiveSendPeers()); }
@Override
public boolean haveCapacity() { return (_manager == null ? false : _manager.haveCapacity()); }
public boolean haveInboundCapacity() { return (_manager == null ? false : _manager.haveInboundCapacity()); }
@Override
public boolean haveOutboundCapacity() { return (_manager == null ? false : _manager.haveOutboundCapacity()); }
/**
* Framed average clock skew of connected peers in seconds, or null if we cannot answer.
@ -352,11 +356,41 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
return;
}
/*
* GeoIP stuff
*
* This is only used in the router console for now, but we put it here because
* 1) it's a lot easier, and 2) we could use it in the future for peer selection,
* tunnel selection, shitlisting, etc.
*/
/* We hope the routerinfos are read in and things have settled down by now, but it's not required to be so */
private static final int START_DELAY = 5*60*1000;
private static final int LOOKUP_TIME = 30*60*1000;
private void startGeoIP() {
_geoIP = new GeoIP(_context);
SimpleScheduler.getInstance().addPeriodicEvent(new Lookup(), START_DELAY, LOOKUP_TIME);
SimpleScheduler.getInstance().addEvent(new QueueAll(), START_DELAY);
}
/**
* Collect the IPs for all routers in the DB, and queue them for lookup,
* then fire off the periodic lookup task for the first time.
*
* We could use getAllRouters() if it were public, and that would be faster, but
* we only do this once.
*/
private class QueueAll implements SimpleTimer.TimedEvent {
public void timeReached() {
Set routers = _context.netDb().findNearestRouters(_context.routerHash(), _context.netDb().getKnownRouters(), null);
for (Iterator iter = routers.iterator(); iter.hasNext(); ) {
RouterInfo ri = (RouterInfo) iter.next();
String host = getIPString(ri);
if (host == null)
continue;
_geoIP.add(host);
}
SimpleScheduler.getInstance().addPeriodicEvent(new Lookup(), 5000, LOOKUP_TIME);
}
}
private class Lookup implements SimpleTimer.TimedEvent {
@ -370,17 +404,35 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
}
/**
* Right now this only uses the transport IP,
* which is present only after you've connected to the peer.
* We could also check the IP in the netDb entry...
* Uses the transport IP first because that lookup is fast,
* then the SSU IP from the netDb.
*/
public String getCountry(Hash peer) {
byte[] ip = TransportImpl.getIP(peer);
if (ip == null)
if (ip != null)
return _geoIP.get(ip);
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(peer);
if (ri == null)
return null;
return _geoIP.get(ip);
String s = getIPString(ri);
if (s != null)
return _geoIP.get(s);
return null;
}
private String getIPString(RouterInfo ri) {
// use SSU only, it is likely to be an IP not a hostname,
// we don't want to generate a lot of DNS queries at startup
RouterAddress ra = ri.getTargetAddress("SSU");
if (ra == null)
return null;
Properties props = ra.getOptions();
if (props == null)
return null;
return props.getProperty("host");
}
/** Provide a consistent "look" for displaying router IDs in the console */
public String renderPeerHTML(Hash peer) {
String h = peer.toBase64().substring(0, 4);
StringBuffer buf = new StringBuffer(128);

View File

@ -204,11 +204,10 @@ public class TransportManager implements TransportEventListener {
}
/**
* Is at least one transport below its connection limit + some margin
* Is at least one transport below its outbound connection limit + some margin
* Use for throttling in the router.
* Perhaps we should just use SSU?
*/
public boolean haveCapacity() {
public boolean haveOutboundCapacity() {
for (int i = 0; i < _transports.size(); i++) {
if (((Transport)_transports.get(i)).haveCapacity())
return true;
@ -216,6 +215,18 @@ public class TransportManager implements TransportEventListener {
return false;
}
/**
* Is at least one transport below its inbound connection limit + some margin
* Use for throttling in the router.
*/
public boolean haveInboundCapacity() {
for (int i = 0; i < _transports.size(); i++) {
if (_transports.get(i).getCurrentAddress() != null && _transports.get(i).haveCapacity())
return true;
}
return false;
}
/**
* Return our peer clock skews on all transports.
* Vector composed of Long, each element representing a peer skew in seconds.

View File

@ -509,9 +509,9 @@ class BuildHandler {
* approaching our connection limit (i.e. !haveCapacity()),
* reject this request.
*/
if (response == 0 && (isInGW || isOutEnd) &&
(Boolean.valueOf(_context.getProperty(PROP_REJECT_NONPARTICIPANT)).booleanValue() ||
! _context.commSystem().haveCapacity())) {
if (response == 0 &&
((isInGW && ! _context.commSystem().haveInboundCapacity()) ||
(isOutEnd && ! _context.commSystem().haveOutboundCapacity()))) {
_context.throttle().setTunnelStatus("Rejecting tunnels: Connection limit");
response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
}