* i2psnark:

- Add support for secondary open trackers
      - Refactor and simplify the TrackerClient code
      - Add welterde's tracker to the default list
      - Don't have eepget retry announces
      - Slow down tracker contacts if they've failed for a while
      - Add some debug support showing connections (?p=2)
This commit is contained in:
zzz
2008-03-25 21:54:54 +00:00
parent 42bbb4a9ff
commit 40a9e959e8
8 changed files with 240 additions and 100 deletions

View File

@ -160,8 +160,8 @@ public class I2PSnarkUtil {
/** /**
* fetch the given URL, returning the file it is stored in, or null on error * fetch the given URL, returning the file it is stored in, or null on error
*/ */
public File get(String url) { return get(url, true, 1); } public File get(String url) { return get(url, true, 0); }
public File get(String url, boolean rewrite) { return get(url, rewrite, 1); } public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
public File get(String url, int retries) { return get(url, true, retries); } public File get(String url, int retries) { return get(url, true, retries); }
public File get(String url, boolean rewrite, int retries) { public File get(String url, boolean rewrite, int retries) {
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy); _log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
@ -227,12 +227,22 @@ public class I2PSnarkUtil {
} }
} }
public String lookup(String name) {
Destination dest = getDestination(name);
if (dest == null)
return null;
return dest.toBase64();
}
/** /**
* Given http://blah.i2p/foo/announce turn it into http://i2p/blah/foo/announce * Given http://KEY.i2p/foo/announce turn it into http://i2p/KEY/foo/announce
* Given http://tracker.blah.i2p/foo/announce leave it alone
*/ */
String rewriteAnnounce(String origAnnounce) { String rewriteAnnounce(String origAnnounce) {
int destStart = "http://".length(); int destStart = "http://".length();
int destEnd = origAnnounce.indexOf(".i2p"); int destEnd = origAnnounce.indexOf(".i2p");
if (destEnd < destStart + 516)
return origAnnounce;
int pathStart = origAnnounce.indexOf('/', destEnd); int pathStart = origAnnounce.indexOf('/', destEnd);
String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart); String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart);
//_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]"); //_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");

View File

@ -114,6 +114,14 @@ public class Peer implements Comparable
return "[unknown id] " + _id; return "[unknown id] " + _id;
} }
/**
* Returns socket (for debug printing)
*/
public String getSocket()
{
return sock.toString();
}
/** /**
* The hash code of a Peer is the hash code of the peerID. * The hash code of a Peer is the hash code of the peerID.
*/ */

View File

@ -34,8 +34,12 @@ public class SnarkManager implements Snark.CompleteListener {
public static final String PROP_META_PREFIX = "i2psnark.zmeta."; public static final String PROP_META_PREFIX = "i2psnark.zmeta.";
public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
public static final String PROP_AUTO_START = "i2snark.autoStart"; public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops
public static final String DEFAULT_AUTO_START = "false"; public static final String DEFAULT_AUTO_START = "false";
public static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
public static final String DEFAULT_USE_OPENTRACKERS = "true";
public static final String PROP_OPENTRACKERS = "i2psnark.opentrackers";
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
private SnarkManager() { private SnarkManager() {
_snarks = new HashMap(); _snarks = new HashMap();
@ -72,6 +76,9 @@ public class SnarkManager implements Snark.CompleteListener {
public boolean shouldAutoStart() { public boolean shouldAutoStart() {
return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue(); return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue();
} }
public boolean shouldUseOpenTrackers() {
return Boolean.valueOf(_config.getProperty(PROP_USE_OPENTRACKERS, DEFAULT_USE_OPENTRACKERS)).booleanValue();
}
private int getStartupDelayMinutes() { return 1; } private int getStartupDelayMinutes() { return 1; }
public File getDataDir() { public File getDataDir() {
String dir = _config.getProperty(PROP_DIR); String dir = _config.getProperty(PROP_DIR);
@ -152,7 +159,7 @@ public class SnarkManager implements Snark.CompleteListener {
public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost, public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost,
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts, String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit) { String upLimit, boolean useOpenTrackers, String openTrackers) {
boolean changed = false; boolean changed = false;
if (eepHost != null) { if (eepHost != null) {
int port = I2PSnarkUtil.instance().getEepProxyPort(); int port = I2PSnarkUtil.instance().getEepProxyPort();
@ -170,7 +177,7 @@ public class SnarkManager implements Snark.CompleteListener {
if (upLimit != null) { if (upLimit != null) {
int limit = I2PSnarkUtil.instance().getMaxUploaders(); int limit = I2PSnarkUtil.instance().getMaxUploaders();
try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {} try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {}
if ( limit != I2PSnarkUtil.instance().getEepProxyPort()) { if ( limit != I2PSnarkUtil.instance().getMaxUploaders()) {
if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) { if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) {
I2PSnarkUtil.instance().setMaxUploaders(limit); I2PSnarkUtil.instance().setMaxUploaders(limit);
changed = true; changed = true;
@ -265,6 +272,18 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage("Adjusted autostart to " + autoStart); addMessage("Adjusted autostart to " + autoStart);
changed = true; changed = true;
} }
if (shouldUseOpenTrackers() != useOpenTrackers) {
_config.setProperty(PROP_USE_OPENTRACKERS, useOpenTrackers + "");
addMessage((useOpenTrackers ? "En" : "Dis") + "abled open trackers - torrent restart required to take effect");
changed = true;
}
if (openTrackers != null) {
if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(getOpenTrackerString())) {
_config.setProperty(PROP_OPENTRACKERS, openTrackers.trim());
addMessage("Open Tracker list changed - torrent restart required to take effect");
changed = true;
}
}
if (changed) { if (changed) {
saveConfig(); saveConfig();
} else { } else {
@ -600,6 +619,7 @@ public class SnarkManager implements Snark.CompleteListener {
// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" // , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/"
// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" // , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" // , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
, "welterde", "http://BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
}; };
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
@ -634,6 +654,26 @@ public class SnarkManager implements Snark.CompleteListener {
return trackerMap; return trackerMap;
} }
public String getOpenTrackerString() {
return _config.getProperty(PROP_OPENTRACKERS, DEFAULT_OPENTRACKERS);
}
/** comma delimited list open trackers to use as backups */
/** sorted map of name to announceURL=baseURL */
public List getOpenTrackers() {
if (!shouldUseOpenTrackers())
return null;
List rv = new ArrayList(1);
String trackers = getOpenTrackerString();
StringTokenizer tok = new StringTokenizer(trackers, ", ");
while (tok.hasMoreTokens())
rv.add(tok.nextToken());
if (rv.size() <= 0)
return null;
return rv;
}
private static class TorrentFilenameFilter implements FilenameFilter { private static class TorrentFilenameFilter implements FilenameFilter {
private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter(); private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter();
public static TorrentFilenameFilter instance() { return _filter; } public static TorrentFilenameFilter instance() { return _filter; }

View File

@ -46,6 +46,10 @@ public class TrackerClient extends I2PThread
private final static int SLEEP = 5; // 5 minutes. private final static int SLEEP = 5; // 5 minutes.
private final static int DELAY_MIN = 2000; // 2 secs. private final static int DELAY_MIN = 2000; // 2 secs.
private final static int DELAY_MUL = 1500; // 1.5 secs. private final static int DELAY_MUL = 1500; // 1.5 secs.
private final static int MAX_REGISTER_FAILS = 10; // * INITIAL_SLEEP = 15m to register
private final static int INITIAL_SLEEP = 90*1000;
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
private final MetaInfo meta; private final MetaInfo meta;
private final PeerCoordinator coordinator; private final PeerCoordinator coordinator;
@ -54,8 +58,7 @@ public class TrackerClient extends I2PThread
private boolean stop; private boolean stop;
private boolean started; private boolean started;
private long interval; private List trackers;
private long lastRequestTime;
public TrackerClient(MetaInfo meta, PeerCoordinator coordinator) public TrackerClient(MetaInfo meta, PeerCoordinator coordinator)
{ {
@ -100,13 +103,46 @@ public class TrackerClient extends I2PThread
public void run() public void run()
{ {
// XXX - Support other IPs
String announce = meta.getAnnounce(); //I2PSnarkUtil.instance().rewriteAnnounce(meta.getAnnounce());
String infoHash = urlencode(meta.getInfoHash()); String infoHash = urlencode(meta.getInfoHash());
String peerID = urlencode(coordinator.getID()); String peerID = urlencode(coordinator.getID());
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash _log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash);
+ " xmitAnnounce: [" + announce + "]");
// Construct the list of trackers for this torrent,
// starting with the primary one listed in the metainfo,
// followed by the secondary open trackers
// It's painful, but try to make sure if an open tracker is also
// the primary tracker, that we don't add it twice.
trackers = new ArrayList(2);
trackers.add(new Tracker(meta.getAnnounce(), true));
List tlist = SnarkManager.instance().getOpenTrackers();
if (tlist != null) {
for (int i = 0; i < tlist.size(); i++) {
String url = (String)tlist.get(i);
if (!url.startsWith("http://")) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
int slash = url.indexOf('/', 7);
if (slash <= 7) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
if (meta.getAnnounce().startsWith(url.substring(0, slash)))
continue;
String dest = I2PSnarkUtil.instance().lookup(url.substring(7, slash));
if (dest == null) {
_log.error("Announce host unknown: [" + url + "]");
continue;
}
if (meta.getAnnounce().startsWith("http://" + dest))
continue;
if (meta.getAnnounce().startsWith("http://i2p/" + dest))
continue;
trackers.add(new Tracker(url, false));
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
}
}
long uploaded = coordinator.getUploaded(); long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded(); long downloaded = coordinator.getDownloaded();
@ -119,78 +155,29 @@ public class TrackerClient extends I2PThread
{ {
if (!verifyConnected()) return; if (!verifyConnected()) return;
boolean started = false; boolean started = false;
while (!started) boolean firstTime = true;
{ int consecutiveFails = 0;
sleptTime = 0;
try
{
// Send start.
TrackerInfo info = doRequest(announce, infoHash, peerID,
uploaded, downloaded, left,
STARTED_EVENT);
Set peers = info.getPeers();
coordinator.trackerSeenPeers = peers.size();
coordinator.trackerProblems = null;
if (!completed) {
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer cur = (Peer)it.next();
coordinator.addPeer(cur);
int delay = DELAY_MUL;
delay *= ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
delay += DELAY_MIN;
sleptTime += delay;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
started = true;
}
catch (IOException ioe)
{
// Probably not fatal (if it doesn't last to long...)
Snark.debug
("WARNING: Could not contact tracker at '"
+ announce + "': " + ioe, Snark.WARNING);
coordinator.trackerProblems = ioe.getMessage();
if (coordinator.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
stop = true;
coordinator.snark.stopTorrent();
}
}
if (stop)
break;
if (!started)
{
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
try
{
// Sleep one minutes...
Thread.sleep(60*1000);
}
catch(InterruptedException interrupt)
{
// ignore
}
}
}
Random r = new Random(); Random r = new Random();
while(!stop) while(!stop)
{ {
try try
{ {
// Sleep some minutes... // Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
// except for the first time...
int delay; int delay;
if(coordinator.trackerProblems != null && !completed) { int random = r.nextInt(120*1000);
delay = 60*1000; if (firstTime) {
} else if(completed) { delay = r.nextInt(30*1000);
delay = 3*SLEEP*60*1000 + r.nextInt(120*1000); firstTime = false;
} else { } else if (completed && started)
delay = SLEEP*60*1000 + r.nextInt(120*1000); delay = 3*SLEEP*60*1000 + random;
delay -= sleptTime; else if (coordinator.trackerProblems != null && ++consecutiveFails < MAX_CONSEC_FAILS)
} delay = INITIAL_SLEEP;
else
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
delay = SLEEP*60*1000 + random;
if (delay > 0) if (delay > 0)
Thread.sleep(delay); Thread.sleep(delay);
} }
@ -218,21 +205,37 @@ public class TrackerClient extends I2PThread
else else
event = NO_EVENT; event = NO_EVENT;
// *** loop once for each tracker
// Only do a request when necessary. // Only do a request when necessary.
sleptTime = 0; sleptTime = 0;
if (event == COMPLETED_EVENT int maxSeenPeers = 0;
|| coordinator.needPeers() for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
|| System.currentTimeMillis() > lastRequestTime + interval) Tracker tr = (Tracker)iter.next();
if ((!stop) && (!tr.stop) &&
(completed || coordinator.needPeers()) &&
(event == COMPLETED_EVENT || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
{ {
try try
{ {
TrackerInfo info = doRequest(announce, infoHash, peerID, if (!tr.started)
event = STARTED_EVENT;
TrackerInfo info = doRequest(tr, infoHash, peerID,
uploaded, downloaded, left, uploaded, downloaded, left,
event); event);
coordinator.trackerProblems = null; coordinator.trackerProblems = null;
tr.trackerProblems = null;
tr.registerFails = 0;
tr.consecutiveFails = 0;
if (tr.isPrimary)
consecutiveFails = 0;
started = true;
tr.started = true;
Set peers = info.getPeers(); Set peers = info.getPeers();
coordinator.trackerSeenPeers = peers.size(); tr.seenPeers = peers.size();
if (coordinator.trackerSeenPeers < tr.seenPeers) // update rising number quickly
coordinator.trackerSeenPeers = tr.seenPeers;
if ( (left > 0) && (!completed) ) { if ( (left > 0) && (!completed) ) {
// we only want to talk to new people if we need things // we only want to talk to new people if we need things
// from them (duh) // from them (duh)
@ -257,16 +260,35 @@ public class TrackerClient extends I2PThread
// Probably not fatal (if it doesn't last to long...) // Probably not fatal (if it doesn't last to long...)
Snark.debug Snark.debug
("WARNING: Could not contact tracker at '" ("WARNING: Could not contact tracker at '"
+ announce + "': " + ioe, Snark.WARNING); + tr.announce + "': " + ioe, Snark.WARNING);
coordinator.trackerProblems = ioe.getMessage(); tr.trackerProblems = ioe.getMessage();
if (coordinator.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) { // don't show secondary tracker problems to the user
stop = true; if (tr.isPrimary)
coordinator.snark.stopTorrent(); coordinator.trackerProblems = tr.trackerProblems;
if (tr.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
// Give a guy some time to register it if using opentrackers too
if (trackers.size() == 1) {
stop = true;
coordinator.snark.stopTorrent();
} else { // hopefully each on the opentrackers list is really open
if (tr.registerFails++ > MAX_REGISTER_FAILS)
tr.stop = true;
}
} }
if (++tr.consecutiveFails == MAX_CONSEC_FAILS && tr.interval < LONG_SLEEP)
tr.interval = LONG_SLEEP; // slow down
} }
} }
} if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
} maxSeenPeers = tr.seenPeers;
} // *** end of trackers loop here
// we could try and total the unique peers but that's too hard for now
coordinator.trackerSeenPeers = maxSeenPeers;
if (!started)
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
} // *** end of while loop
} // try
catch (Throwable t) catch (Throwable t)
{ {
I2PSnarkUtil.instance().debug("TrackerClient: " + t, Snark.ERROR, t); I2PSnarkUtil.instance().debug("TrackerClient: " + t, Snark.ERROR, t);
@ -277,21 +299,27 @@ public class TrackerClient extends I2PThread
{ {
try try
{ {
if (!verifyConnected()) return; // try to contact everybody we can
TrackerInfo info = doRequest(announce, infoHash, peerID, uploaded, // We don't need I2CP connection for eepget
// if (!verifyConnected()) return;
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
Tracker tr = (Tracker)iter.next();
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
doRequest(tr, infoHash, peerID, uploaded,
downloaded, left, STOPPED_EVENT); downloaded, left, STOPPED_EVENT);
}
} }
catch(IOException ioe) { /* ignored */ } catch(IOException ioe) { /* ignored */ }
} }
} }
private TrackerInfo doRequest(String announce, String infoHash, private TrackerInfo doRequest(Tracker tr, String infoHash,
String peerID, long uploaded, String peerID, long uploaded,
long downloaded, long left, String event) long downloaded, long left, String event)
throws IOException throws IOException
{ {
String s = announce String s = tr.announce
+ "?info_hash=" + infoHash + "?info_hash=" + infoHash
+ "&peer_id=" + peerID + "&peer_id=" + peerID
+ "&port=" + port + "&port=" + port
@ -302,6 +330,7 @@ public class TrackerClient extends I2PThread
+ ((event != NO_EVENT) ? ("&event=" + event) : ""); + ((event != NO_EVENT) ? ("&event=" + event) : "");
Snark.debug("Sending TrackerClient request: " + s, Snark.INFO); Snark.debug("Sending TrackerClient request: " + s, Snark.INFO);
tr.lastRequestTime = System.currentTimeMillis();
File fetched = I2PSnarkUtil.instance().get(s); File fetched = I2PSnarkUtil.instance().get(s);
if (fetched == null) { if (fetched == null) {
throw new IOException("Error fetching " + s); throw new IOException("Error fetching " + s);
@ -315,13 +344,12 @@ public class TrackerClient extends I2PThread
TrackerInfo info = new TrackerInfo(in, coordinator.getID(), TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
coordinator.getMetaInfo()); coordinator.getMetaInfo());
Snark.debug("TrackerClient response: " + info, Snark.INFO); Snark.debug("TrackerClient response: " + info, Snark.INFO);
lastRequestTime = System.currentTimeMillis();
String failure = info.getFailureReason(); String failure = info.getFailureReason();
if (failure != null) if (failure != null)
throw new IOException(failure); throw new IOException(failure);
interval = info.getInterval() * 1000; tr.interval = info.getInterval() * 1000;
return info; return info;
} finally { } finally {
if (in != null) try { in.close(); } catch (IOException ioe) {} if (in != null) try { in.close(); } catch (IOException ioe) {}
@ -347,4 +375,32 @@ public class TrackerClient extends I2PThread
return sb.toString(); return sb.toString();
} }
private class Tracker
{
String announce;
boolean isPrimary;
long interval;
long lastRequestTime;
String trackerProblems;
boolean stop;
boolean started;
int registerFails;
int consecutiveFails;
int seenPeers;
public Tracker(String a, boolean p)
{
announce = a;
isPrimary = p;
interval = INITIAL_SLEEP;
lastRequestTime = 0;
trackerProblems = null;
stop = false;
started = false;
registerFails = 0;
consecutiveFails = 0;
seenPeers = 0;
}
}
} }

View File

@ -115,8 +115,9 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("</th></tr></thead>\n"); out.write("</th></tr></thead>\n");
for (int i = 0; i < snarks.size(); i++) { for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i); Snark snark = (Snark)snarks.get(i);
boolean showPeers = "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam); boolean showDebug = "2".equals(peerParam);
displaySnark(out, snark, uri, i, stats, showPeers); boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
displaySnark(out, snark, uri, i, stats, showPeers, showDebug);
} }
if (snarks.size() <= 0) { if (snarks.size() <= 0) {
out.write(TABLE_EMPTY); out.write(TABLE_EMPTY);
@ -292,7 +293,9 @@ public class I2PSnarkServlet extends HttpServlet {
String i2cpPort = req.getParameter("i2cpPort"); String i2cpPort = req.getParameter("i2cpPort");
String i2cpOpts = req.getParameter("i2cpOpts"); String i2cpOpts = req.getParameter("i2cpOpts");
String upLimit = req.getParameter("upLimit"); String upLimit = req.getParameter("upLimit");
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit); boolean useOpenTrackers = req.getParameter("useOpenTrackers") != null;
String openTrackers = req.getParameter("openTrackers");
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit, useOpenTrackers, openTrackers);
} else if ("Create torrent".equals(action)) { } else if ("Create torrent".equals(action)) {
String baseData = req.getParameter("baseFile"); String baseData = req.getParameter("baseFile");
if (baseData != null) { if (baseData != null) {
@ -367,7 +370,7 @@ public class I2PSnarkServlet extends HttpServlet {
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60; private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60;
private static final int MAX_DISPLAYED_ERROR_LENGTH = 40; private static final int MAX_DISPLAYED_ERROR_LENGTH = 40;
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers) throws IOException { private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, boolean showDebug) throws IOException {
String filename = snark.torrent; String filename = snark.torrent;
File f = new File(filename); File f = new File(filename);
filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
@ -551,6 +554,8 @@ public class I2PSnarkServlet extends HttpServlet {
else else
client = "Unknown"; client = "Unknown";
out.write("<font size=-1>" + client + "</font>&nbsp;&nbsp;<tt>" + peer.toString().substring(5, 9) + "</tt>"); out.write("<font size=-1>" + client + "</font>&nbsp;&nbsp;<tt>" + peer.toString().substring(5, 9) + "</tt>");
if (showDebug)
out.write(" inactive " + (peer.getInactiveTime() / 1000) + "s");
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td>\n\t"); out.write("</td>\n\t");
@ -599,6 +604,8 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td></tr>\n\t"); out.write("</td></tr>\n\t");
if (showDebug)
out.write("<tr><td colspan=\"8\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">" + peer.getSocket() + "</td></tr>");
} }
} }
} }
@ -660,6 +667,8 @@ public class I2PSnarkServlet extends HttpServlet {
String uri = req.getRequestURI(); String uri = req.getRequestURI();
String dataDir = _manager.getDataDir().getAbsolutePath(); String dataDir = _manager.getDataDir().getAbsolutePath();
boolean autoStart = _manager.shouldAutoStart(); boolean autoStart = _manager.shouldAutoStart();
boolean useOpenTrackers = _manager.shouldUseOpenTrackers();
String openTrackers = _manager.getOpenTrackerString();
//int seedPct = 0; //int seedPct = 0;
out.write("<form action=\"" + uri + "\" method=\"POST\">\n"); out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
@ -693,6 +702,12 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("Total uploader limit: <input type=\"text\" name=\"upLimit\" value=\"" out.write("Total uploader limit: <input type=\"text\" name=\"upLimit\" value=\""
+ I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" /> peers<br />\n"); + I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" /> peers<br />\n");
out.write("Use open trackers also: <input type=\"checkbox\" name=\"useOpenTrackers\" value=\"true\" "
+ (useOpenTrackers ? "checked " : "")
+ "title=\"If true, uses open trackers in addition\" /> ");
out.write("Announce URLs: <input type=\"text\" name=\"openTrackers\" value=\""
+ openTrackers + "\" size=\"50\" /><br />\n");
//out.write("<hr />\n"); //out.write("<hr />\n");
out.write("EepProxy host: <input type=\"text\" name=\"eepHost\" value=\"" out.write("EepProxy host: <input type=\"text\" name=\"eepHost\" value=\""
+ I2PSnarkUtil.instance().getEepProxyHost() + "\" size=\"15\" /> "); + I2PSnarkUtil.instance().getEepProxyHost() + "\" size=\"15\" /> ");

View File

@ -1,3 +1,12 @@
2008-03-25 zzz
* i2psnark:
- Add support for secondary open trackers
- Refactor and simplify the TrackerClient code
- Add welterde's tracker to the default list
- Don't have eepget retry announces
- Slow down tracker contacts if they've failed for a while
- Add some debug support showing connections (?p=2)
2008-03-22 zzz 2008-03-22 zzz
* NewsFetcher: Fix bug causing fetch every 10m * NewsFetcher: Fix bug causing fetch every 10m

View File

@ -300,3 +300,5 @@ true.i2p=Jeb1Ctlh55wWezbA~sCxYQsreDPS~qFJ6DeNMPl7~Kx0w1Odh8YE3QKrZS7WlNqeoRNJLyP
krabs.i2p=k6qIwzff6s1RiRQQy9O6cliBTfHffKZ2F~pVG8nmCqMxEpPnywynFa9XVS6VBbhxGRAMG~PIb2IaFRYS5GFdM3fnnJ~Cn2AbN-qsqbl6cXExj5Fy9Cd-aPR44XW0NE9qjFPiN~6JUOg0fitF65RmsMrFvHq9LM2zOFxOfnPKVsBJGRpjhp6EPRNrkXvzQTw7x6~kqUJ-VGW0avjrz4EmgT6Wias5z0EPioneKOhG-1NepL8HqEv9ryGt31~kmI1-B0cS8v1riaXH0rZWjJ0VvUFEoJ3sHCir4vsnSf1YQIKMUO~zKlgTVZBsw8P2ILFFihs0g9KMIWVjJqqo0PzCM1O-LW90hirn~Ryh4zOZI-orIiV9Oqu96Fj2bvBYSka11TY7erLOCk64tc5NwxvlJQ3F-lk0ZFGvYuU~l45mi0khFLnDnzhDFtcY6YNLRG8hmv9IR2MrG9TJFfSwXdx11LI-57tkRi9Jw4s8OjLijNNDOJX~rVgwZVVIEQcOhGxkAAAA krabs.i2p=k6qIwzff6s1RiRQQy9O6cliBTfHffKZ2F~pVG8nmCqMxEpPnywynFa9XVS6VBbhxGRAMG~PIb2IaFRYS5GFdM3fnnJ~Cn2AbN-qsqbl6cXExj5Fy9Cd-aPR44XW0NE9qjFPiN~6JUOg0fitF65RmsMrFvHq9LM2zOFxOfnPKVsBJGRpjhp6EPRNrkXvzQTw7x6~kqUJ-VGW0avjrz4EmgT6Wias5z0EPioneKOhG-1NepL8HqEv9ryGt31~kmI1-B0cS8v1riaXH0rZWjJ0VvUFEoJ3sHCir4vsnSf1YQIKMUO~zKlgTVZBsw8P2ILFFihs0g9KMIWVjJqqo0PzCM1O-LW90hirn~Ryh4zOZI-orIiV9Oqu96Fj2bvBYSka11TY7erLOCk64tc5NwxvlJQ3F-lk0ZFGvYuU~l45mi0khFLnDnzhDFtcY6YNLRG8hmv9IR2MrG9TJFfSwXdx11LI-57tkRi9Jw4s8OjLijNNDOJX~rVgwZVVIEQcOhGxkAAAA
www.i2p2.i2p=-KR6qyfPWXoN~F3UzzYSMIsaRy4udcRkHu2Dx9syXSzUQXQdi2Af1TV2UMH3PpPuNu-GwrqihwmLSkPFg4fv4yQQY3E10VeQVuI67dn5vlan3NGMsjqxoXTSHHt7C3nX3szXK90JSoO~tRMDl1xyqtKm94-RpIyNcLXofd0H6b02683CQIjb-7JiCpDD0zharm6SU54rhdisIUVXpi1xYgg2pKVpssL~KCp7RAGzpt2rSgz~RHFsecqGBeFwJdiko-6CYW~tcBcigM8ea57LK7JjCFVhOoYTqgk95AG04-hfehnmBtuAFHWklFyFh88x6mS9sbVPvi-am4La0G0jvUJw9a3wQ67jMr6KWQ~w~bFe~FDqoZqVXl8t88qHPIvXelvWw2Y8EMSF5PJhWw~AZfoWOA5VQVYvcmGzZIEKtFGE7bgQf3rFtJ2FAtig9XXBsoLisHbJgeVb29Ew5E7bkwxvEe9NYkIqvrKvUAt1i55we0Nkt6xlEdhBqg6xXOyIAAAA www.i2p2.i2p=-KR6qyfPWXoN~F3UzzYSMIsaRy4udcRkHu2Dx9syXSzUQXQdi2Af1TV2UMH3PpPuNu-GwrqihwmLSkPFg4fv4yQQY3E10VeQVuI67dn5vlan3NGMsjqxoXTSHHt7C3nX3szXK90JSoO~tRMDl1xyqtKm94-RpIyNcLXofd0H6b02683CQIjb-7JiCpDD0zharm6SU54rhdisIUVXpi1xYgg2pKVpssL~KCp7RAGzpt2rSgz~RHFsecqGBeFwJdiko-6CYW~tcBcigM8ea57LK7JjCFVhOoYTqgk95AG04-hfehnmBtuAFHWklFyFh88x6mS9sbVPvi-am4La0G0jvUJw9a3wQ67jMr6KWQ~w~bFe~FDqoZqVXl8t88qHPIvXelvWw2Y8EMSF5PJhWw~AZfoWOA5VQVYvcmGzZIEKtFGE7bgQf3rFtJ2FAtig9XXBsoLisHbJgeVb29Ew5E7bkwxvEe9NYkIqvrKvUAt1i55we0Nkt6xlEdhBqg6xXOyIAAAA
i2p-projekt.i2p=8ZAW~KzGFMUEj0pdchy6GQOOZbuzbqpWtiApEj8LHy2~O~58XKxRrA43cA23a9oDpNZDqWhRWEtehSnX5NoCwJcXWWdO1ksKEUim6cQLP-VpQyuZTIIqwSADwgoe6ikxZG0NGvy5FijgxF4EW9zg39nhUNKRejYNHhOBZKIX38qYyXoB8XCVJybKg89aMMPsCT884F0CLBKbHeYhpYGmhE4YW~aV21c5pebivvxeJPWuTBAOmYxAIgJE3fFU-fucQn9YyGUFa8F3t-0Vco-9qVNSEWfgrdXOdKT6orr3sfssiKo3ybRWdTpxycZ6wB4qHWgTSU5A-gOA3ACTCMZBsASN3W5cz6GRZCspQ0HNu~R~nJ8V06Mmw~iVYOu5lDvipmG6-dJky6XRxCedczxMM1GWFoieQ8Ysfuxq-j8keEtaYmyUQme6TcviCEvQsxyVirr~dTC-F8aZ~y2AlG5IJz5KD02nO6TRkI2fgjHhv9OZ9nskh-I2jxAzFP6Is1kyAAAA i2p-projekt.i2p=8ZAW~KzGFMUEj0pdchy6GQOOZbuzbqpWtiApEj8LHy2~O~58XKxRrA43cA23a9oDpNZDqWhRWEtehSnX5NoCwJcXWWdO1ksKEUim6cQLP-VpQyuZTIIqwSADwgoe6ikxZG0NGvy5FijgxF4EW9zg39nhUNKRejYNHhOBZKIX38qYyXoB8XCVJybKg89aMMPsCT884F0CLBKbHeYhpYGmhE4YW~aV21c5pebivvxeJPWuTBAOmYxAIgJE3fFU-fucQn9YyGUFa8F3t-0Vco-9qVNSEWfgrdXOdKT6orr3sfssiKo3ybRWdTpxycZ6wB4qHWgTSU5A-gOA3ACTCMZBsASN3W5cz6GRZCspQ0HNu~R~nJ8V06Mmw~iVYOu5lDvipmG6-dJky6XRxCedczxMM1GWFoieQ8Ysfuxq-j8keEtaYmyUQme6TcviCEvQsxyVirr~dTC-F8aZ~y2AlG5IJz5KD02nO6TRkI2fgjHhv9OZ9nskh-I2jxAzFP6Is1kyAAAA
nickyb.i2p=9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA
tracker.welterde.i2p=BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA

View File

@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion { public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $"; public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $";
public final static String VERSION = "0.6.1.32"; public final static String VERSION = "0.6.1.32";
public final static long BUILD = 10; public final static long BUILD = 11;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);