diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
index 98bcd4eed4..1908a11937 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
@@ -254,6 +254,7 @@ public class Snark
private boolean stopped;
private byte[] id;
private byte[] infoHash;
+ private String additionalTrackerURL;
private final I2PSnarkUtil _util;
private final PeerCoordinatorSet _peerCoordinatorSet;
private String trackerProblems;
@@ -453,9 +454,10 @@ public class Snark
*
* @param torrent a fake name for now (not a file name)
* @param ih 20-byte info hash
+ * @param trackerURL may be null
* @since 0.8.4
*/
- public Snark(I2PSnarkUtil util, String torrent, byte[] ih,
+ public Snark(I2PSnarkUtil util, String torrent, byte[] ih, String trackerURL,
CompleteListener complistener, PeerCoordinatorSet peerCoordinatorSet,
ConnectionAcceptor connectionAcceptor, boolean start, String rootDir)
{
@@ -465,6 +467,7 @@ public class Snark
acceptor = connectionAcceptor;
this.torrent = torrent;
this.infoHash = ih;
+ this.additionalTrackerURL = trackerURL;
this.rootDataDir = rootDir;
stopped = true;
id = generateID();
@@ -535,7 +538,7 @@ public class Snark
acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator));
}
// TODO pass saved closest DHT nodes to the tracker? or direct to the coordinator?
- trackerclient = new TrackerClient(_util, meta, coordinator, this);
+ trackerclient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this);
}
stopped = false;
@@ -564,11 +567,13 @@ public class Snark
fatal("Could not reopen storage", ioe);
}
}
- TrackerClient newClient = new TrackerClient(_util, meta, coordinator, this);
+ TrackerClient newClient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this);
if (!trackerclient.halted())
trackerclient.halt();
trackerclient = newClient;
trackerclient.start();
+ } else {
+ debug("NOT starting TrackerClient???", NOTICE);
}
}
/**
@@ -825,6 +830,14 @@ public class Snark
return true;
}
+ /**
+ * @return trackerURL string from magnet-mode constructor, may be null
+ * @since 0.8.4
+ */
+ public String getTrackerURL() {
+ return additionalTrackerURL;
+ }
+
/**
* Sets debug, ip and torrent variables then creates a Snark
* instance. Calls usage(), which terminates the program, if
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index f0f7a1f543..29c6a1ed2b 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -643,11 +643,15 @@ public class SnarkManager implements Snark.CompleteListener {
*
* @param name hex or b32 name from the magnet link
* @param ih 20 byte info hash
+ * @param trackerURL may be null
+ * @param udpateStatus should we add this magnet to the config file,
+ * to save it across restarts, in case we don't get
+ * the metadata before shutdown?
* @throws RuntimeException via Snark.fatal()
* @since 0.8.4
*/
- public void addMagnet(String name, byte[] ih, boolean updateStatus) {
- Snark torrent = new Snark(_util, name, ih, this,
+ public void addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus) {
+ Snark torrent = new Snark(_util, name, ih, trackerURL, this,
_peerCoordinatorSet, _connectionAcceptor,
false, getDataDir().getPath());
@@ -1151,6 +1155,10 @@ public class SnarkManager implements Snark.CompleteListener {
saveTorrentStatus(meta, storage.getBitField(), null); // no file priorities
String name = (new File(getDataDir(), storage.getBaseName() + ".torrent")).getAbsolutePath();
try {
+ // put the announce URL in the file
+ String announce = snark.getTrackerURL();
+ if (announce != null)
+ meta = meta.reannounce(announce);
synchronized (_snarks) {
locked_writeMetaInfo(meta, name);
// put it in the list under the new name
@@ -1183,9 +1191,9 @@ public class SnarkManager implements Snark.CompleteListener {
String b64 = k.substring(PROP_META_MAGNET_PREFIX.length());
b64 = b64.replace('$', '=');
byte[] ih = Base64.decode(b64);
- // ignore value
+ // ignore value - TODO put tracker URL in value
if (ih != null && ih.length == 20)
- addMagnet("Magnet: " + I2PSnarkUtil.toHex(ih), ih, false);
+ addMagnet("Magnet: " + I2PSnarkUtil.toHex(ih), ih, null, false);
// else remove from config?
}
}
diff --git a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
index c8f1cd6c96..ad4cdae395 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
@@ -65,6 +65,7 @@ public class TrackerClient extends I2PAppThread
private I2PSnarkUtil _util;
private final MetaInfo meta;
+ private final String additionalTrackerURL;
private final PeerCoordinator coordinator;
private final Snark snark;
private final int port;
@@ -76,8 +77,10 @@ public class TrackerClient extends I2PAppThread
/**
* @param meta null if in magnet mode
+ * @param additionalTrackerURL may be null, from the ?tr= param in magnet mode, otherwise ignored
*/
- public TrackerClient(I2PSnarkUtil util, MetaInfo meta, PeerCoordinator coordinator, Snark snark)
+ public TrackerClient(I2PSnarkUtil util, MetaInfo meta, String additionalTrackerURL,
+ PeerCoordinator coordinator, Snark snark)
{
super();
// Set unique name.
@@ -85,13 +88,11 @@ public class TrackerClient extends I2PAppThread
setName("TrackerClient " + id.substring(id.length() - 12));
_util = util;
this.meta = meta;
+ this.additionalTrackerURL = additionalTrackerURL;
this.coordinator = coordinator;
this.snark = snark;
this.port = 6881; //(port == -1) ? 9 : port;
-
- stop = false;
- started = false;
}
@Override
@@ -138,17 +139,21 @@ public class TrackerClient extends I2PAppThread
// todo: check for b32 matches as well
trackers = new ArrayList(2);
String primary = null;
- if (meta != null) {
+ if (meta != null)
primary = meta.getAnnounce();
+ else if (additionalTrackerURL != null)
+ primary = additionalTrackerURL;
+ if (primary != null) {
if (isValidAnnounce(primary)) {
- trackers.add(new Tracker(meta.getAnnounce(), true));
+ trackers.add(new Tracker(primary, true));
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
} else {
_log.warn("Skipping invalid or non-i2p announce: " + primary);
}
- }
- if (primary == null)
+ } else {
+ _log.warn("No primary announce");
primary = "";
+ }
List tlist = _util.getOpenTrackers();
if (tlist != null) {
for (int i = 0; i < tlist.size(); i++) {
diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index 0b15de790f..a3d77a814a 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -65,7 +65,8 @@ public class I2PSnarkServlet extends Default {
public static final String PROP_CONFIG_FILE = "i2psnark.configFile";
/** BEP 9 */
- private static final String MAGNET = "magnet:?xt=urn:btih:";
+ private static final String MAGNET = "magnet:";
+ private static final String MAGNET_FULL = MAGNET + "?xt=urn:btih:";
/** http://sponge.i2p/files/maggotspec.txt */
private static final String MAGGOT = "maggot://";
@@ -1406,13 +1407,22 @@ public class I2PSnarkServlet extends Default {
private void addMagnet(String url) {
String ihash;
String name;
+ String trackerURL = null;
if (url.startsWith(MAGNET)) {
- ihash = url.substring(MAGNET.length()).trim();
- int amp = ihash.indexOf('&');
- if (amp >= 0)
- ihash = ihash.substring(0, amp);
+ // magnet:?xt=urn:btih:0691e40aae02e552cfcb57af1dca56214680c0c5&tr=http://tracker2.postman.i2p/announce.php
+ String xt = getParam("xt", url);
+ if (xt == null || !xt.startsWith("urn:btih:")) {
+ _manager.addMessage(_("Invalid magnet URL {0}", url));
+ return;
+ }
+ ihash = xt.substring("urn:btih:".length());
+ trackerURL = getParam("tr", url);
name = "Magnet " + ihash;
+ String dn = getParam("dn", url);
+ if (dn != null)
+ name += " (" + Storage.filterName(dn) + ')';
} else if (url.startsWith(MAGGOT)) {
+ // maggot://0691e40aae02e552cfcb57af1dca56214680c0c5:0b557bbdf8718e95d352fbe994dec3a383e2ede7
ihash = url.substring(MAGGOT.length()).trim();
int col = ihash.indexOf(':');
if (col >= 0)
@@ -1439,7 +1449,27 @@ public class I2PSnarkServlet extends Default {
_manager.addMessage(_("Invalid info hash in magnet URL {0}", url));
return;
}
- _manager.addMagnet(name, ih, true);
+ _manager.addMagnet(name, ih, trackerURL, true);
+ }
+
+ private static String getParam(String key, String uri) {
+ int idx = uri.indexOf('?' + key + '=');
+ if (idx >= 0) {
+ idx += key.length() + 2;
+ } else {
+ idx = uri.indexOf('&' + key + '=');
+ if (idx >= 0)
+ idx += key.length() + 2;
+ }
+ if (idx < 0 || idx > uri.length())
+ return null;
+ String rv = uri.substring(idx);
+ idx = rv.indexOf('&');
+ if (idx >= 0)
+ rv = rv.substring(0, idx);
+ else
+ rv = rv.trim();
+ return rv;
}
/** copied from ConfigTunnelsHelper */
@@ -1644,8 +1674,8 @@ public class I2PSnarkServlet extends Default {
String hex = I2PSnarkUtil.toHex(snark.getInfoHash());
buf.append("
").append(toImg("magnet", _("Magnet link"))).append(" ")
- .append(MAGNET).append(hex).append("");
+ .append(MAGNET_FULL).append(hex).append("\">")
+ .append(MAGNET_FULL).append(hex).append("");
// We don't have the hash of the torrent file
//buf.append("
").append(_("Maggot link")).append(": ")
// .append(MAGGOT).append(hex).append(':').append(hex).append("");
diff --git a/history.txt b/history.txt
index ce975c6879..3cee76c487 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,12 @@
+2011-02-10 zzz
+ * I2CP: Correctly close internal connections on the router side
+ when closed by the client, was causing massive memory leak
+ for internal clients using lots of sessions (thanks sponge)
+ * i2psnark:
+ - Improved magnet link parsing, use tr parameter if present
+ * i2ptunnel: Change shared clients default for new clients to false
+ * Streaming: Don't use iter.remove() on a COWAS
+
2011-02-09 sponge
* BOB: fixup delivery in config, adds config file versioning.
* I2CP: Fix most of the I2CP leaks. Two leaks remain, but they are small.
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 4e28a2c8d2..c10128fe62 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 5;
+ public final static long BUILD = 6;
/** for example "-test" */
public final static String EXTRA = "";