use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.
the class SnarkManager method addMagnet.
/**
* Add a torrent with the info hash alone (magnet / maggot)
* External use is for UpdateRunner.
*
* @param name hex or b32 name from the magnet link
* @param ih 20 byte info hash
* @param trackerURL may be null
* @param updateStatus should we add this magnet to the config file,
* to save it across restarts, in case we don't get
* the metadata before shutdown?
* @param dataDir must exist, or null to default to snark data directory
* @param listener to intercept callbacks, should pass through to this
* @return the new Snark or null on failure
* @throws RuntimeException via Snark.fatal()
* @since 0.9.4
*/
public Snark addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus, boolean autoStart, File dataDir, CompleteListener listener) {
String dirPath = dataDir != null ? dataDir.getAbsolutePath() : getDataDir().getPath();
Snark torrent = new Snark(_util, name, ih, trackerURL, listener, _peerCoordinatorSet, _connectionAcceptor, false, dirPath);
synchronized (_snarks) {
Snark snark = getTorrentByInfoHash(ih);
if (snark != null) {
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return null;
}
// Tell the dir monitor not to delete us
_magnets.add(name);
if (updateStatus)
saveMagnetStatus(ih, dirPath, trackerURL, name);
_snarks.put(name, torrent);
}
if (autoStart) {
startTorrent(ih);
if (false)
addMessage(_t("Fetching {0}", name));
DHT dht = _util.getDHT();
boolean shouldWarn = _util.connected() && _util.getOpenTrackers().isEmpty() && ((!_util.shouldUseDHT()) || dht == null || dht.size() <= 0);
if (shouldWarn) {
addMessage(_t("Open trackers are disabled and we have no DHT peers. " + "Fetch of {0} may not succeed until you start another torrent, enable open trackers, or enable DHT.", name));
}
} else {
addMessage(_t("Adding {0}", name));
}
return torrent;
}
use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.
the class TrackerClient method unannounce.
/**
* Creates a thread for each tracker in parallel if tunnel is still open
* @since 0.9.1
*/
private void unannounce() {
// Local DHT tracker unannounce
DHT dht = _util.getDHT();
if (dht != null)
dht.unannounce(snark.getInfoHash());
int i = 0;
for (TCTracker tr : trackers) {
if (_util.connected() && tr.started && (!tr.stop) && tr.trackerProblems == null) {
try {
(new I2PAppThread(new Unannouncer(tr), _threadName + " U" + (++i), true)).start();
} catch (OutOfMemoryError oom) {
// probably ran out of threads, ignore
tr.reset();
}
} else {
tr.reset();
}
}
}
use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.
the class TrackerClient method loop.
/**
* Announce to all the trackers, get peers from PEX and DHT, then queue up a SimpleTimer2 event.
* This will take several seconds to several minutes.
* @since 0.9.1
*/
private void loop() {
try {
// normally this will only go once, then call queueLoop() and return
while (!stop) {
if (!verifyConnected()) {
stop = true;
return;
}
// Local DHT tracker announce
DHT dht = _util.getDHT();
if (dht != null && (meta == null || !meta.isPrivate()))
dht.announce(snark.getInfoHash(), coordinator.completed());
int oldSeenPeers = snark.getTrackerSeenPeers();
int maxSeenPeers = 0;
if (!trackers.isEmpty()) {
maxSeenPeers = getPeersFromTrackers(trackers);
// fast update for UI at startup
if (maxSeenPeers > oldSeenPeers)
snark.setTrackerSeenPeers(maxSeenPeers);
}
int p = getPeersFromPEX();
if (p > maxSeenPeers)
maxSeenPeers = p;
p = getPeersFromDHT();
if (p > maxSeenPeers) {
maxSeenPeers = p;
// fast update for UI at startup
if (maxSeenPeers > oldSeenPeers)
snark.setTrackerSeenPeers(maxSeenPeers);
}
// backup if DHT needs bootstrapping
if (trackers.isEmpty() && !backupTrackers.isEmpty() && dht != null && dht.size() < 16) {
p = getPeersFromTrackers(backupTrackers);
if (p > maxSeenPeers)
maxSeenPeers = p;
}
// we could try and total the unique peers but that's too hard for now
snark.setTrackerSeenPeers(maxSeenPeers);
if (stop)
return;
try {
// Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
int delay;
Random r = _util.getContext().random();
int random = r.nextInt(120 * 1000);
if (completed && runStarted)
delay = 3 * SLEEP * 60 * 1000 + random;
else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else if ((!runStarted) && _runCount < 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 > 20 * 1000) {
// put ourselves on SimpleTimer2
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requeueing in " + DataHelper.formatDuration(delay) + ": " + Thread.currentThread().getName());
queueLoop(delay);
return;
} else if (delay > 0) {
Thread.sleep(delay);
}
} catch (InterruptedException interrupt) {
}
}
// *** end of while loop
}// try
catch (Throwable t) {
_log.error("TrackerClient: " + t, t);
if (t instanceof OutOfMemoryError)
throw (OutOfMemoryError) t;
}
}
use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.
the class SnarkManager method stopAllTorrents.
/**
* Stop all running torrents, and close the tunnel after a delay
* to allow for announces.
* If called at router shutdown via Jetty shutdown hook -> webapp destroy() -> stop(),
* the tunnel won't actually be closed as the SimpleTimer2 is already shutdown
* or will be soon, so we delay a few seconds inline.
* @param finalShutdown if true, sleep at the end if any torrents were running
* @since 0.9.1
*/
public void stopAllTorrents(boolean finalShutdown) {
_stopping = true;
if (finalShutdown && _log.shouldLog(Log.WARN))
_log.warn("SnarkManager final shutdown");
int count = 0;
for (Snark snark : _snarks.values()) {
if (!snark.isStopped()) {
if (count == 0)
addMessage(_t("Stopping all torrents and closing the I2P tunnel."));
count++;
if (finalShutdown)
snark.stopTorrent(true);
else
stopTorrent(snark, false);
// How to do this without creating a ton of threads?
if (count % 8 == 0) {
try {
Thread.sleep(20);
} catch (InterruptedException ie) {
}
}
} else {
CommentSet cs = snark.getComments();
if (cs != null) {
synchronized (cs) {
if (cs.isModified()) {
locked_saveComments(snark, cs);
}
}
}
}
}
if (_util.connected()) {
if (count > 0) {
DHT dht = _util.getDHT();
if (dht != null)
dht.stop();
addMessage(_t("Closing I2P tunnel after notifying trackers."));
if (finalShutdown) {
long toWait = 5 * 1000;
if (SystemVersion.isARM())
toWait *= 2;
try {
Thread.sleep(toWait);
} catch (InterruptedException ie) {
}
_util.disconnect();
_stopping = false;
} else {
// Only schedule this if not a final shutdown
_context.simpleTimer2().addEvent(new Disconnector(), 60 * 1000);
}
} else {
_util.disconnect();
_stopping = false;
addMessage(_t("I2P tunnel closed."));
}
}
}
use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.
the class TrackerClient method getPeersFromDHT.
/**
* @return max peers seen
*/
private int getPeersFromDHT() {
// Get peers from DHT
// FIXME this needs to be in its own thread
int rv = 0;
DHT dht = _util.getDHT();
if (dht != null && (meta == null || !meta.isPrivate()) && (!stop) && (meta == null || _util.getContext().clock().now() > lastDHTAnnounce + MIN_DHT_ANNOUNCE_INTERVAL)) {
int numwant;
if (!coordinator.needOutboundPeers())
numwant = 1;
else
numwant = _util.getMaxConnections();
Collection<Hash> hashes = dht.getPeersAndAnnounce(snark.getInfoHash(), numwant, 5 * 60 * 1000, DHT_ANNOUNCE_PEERS, 3 * 60 * 1000, coordinator.completed(), numwant <= 1);
if (!hashes.isEmpty()) {
runStarted = true;
lastDHTAnnounce = _util.getContext().clock().now();
rv = hashes.size();
} else {
lastDHTAnnounce = 0;
}
if (_log.shouldLog(Log.INFO))
_log.info("Got " + hashes + " from DHT");
// now try these peers
if ((!stop) && !hashes.isEmpty()) {
List<Peer> peers = new ArrayList<Peer>(hashes.size());
for (Hash h : hashes) {
try {
PeerID pID = new PeerID(h.getData(), _util);
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
} catch (InvalidBEncodingException ibe) {
}
}
Random r = _util.getContext().random();
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
}
}
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting DHT peers");
}
return rv;
}
Aggregations