private void x_startTorrent() { boolean ok = _util.connect(); if (!ok) fatal("Unable to connect to I2P"); if (coordinator == null) { I2PServerSocket serversocket = _util.getServerSocket(); if (serversocket == null) fatal("Unable to listen for I2P connections"); else { Destination d = serversocket.getManager().getSession().getMyDestination(); if (_log.shouldLog(Log.INFO)) _log.info( "Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64()); } if (_log.shouldLog(Log.INFO)) _log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient"); activity = "Collecting pieces"; coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this); coordinator.setUploaded(savedUploaded); if (_peerCoordinatorSet != null) { // multitorrent _peerCoordinatorSet.add(coordinator); } else { // single torrent acceptor = new ConnectionAcceptor(_util, new PeerAcceptor(coordinator)); } // TODO pass saved closest DHT nodes to the tracker? or direct to the coordinator? trackerclient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this); } // ensure acceptor is running when in multitorrent if (_peerCoordinatorSet != null && acceptor != null) { acceptor.startAccepting(); } stopped = false; if (coordinator.halted()) { coordinator.restart(); if (_peerCoordinatorSet != null) _peerCoordinatorSet.add(coordinator); } if (!trackerclient.started()) { trackerclient.start(); } else if (trackerclient.halted()) { if (storage != null) { try { storage.reopen(); } catch (IOException ioe) { try { storage.close(); } catch (IOException ioee) { ioee.printStackTrace(); } fatal("Could not reopen storage", ioe); } } trackerclient.start(); } else { if (_log.shouldLog(Log.INFO)) _log.info("NOT starting TrackerClient???"); } }
public boolean overUpBWLimit() { if (_peerCoordinatorSet == null) return false; long total = 0; for (PeerCoordinator c : _peerCoordinatorSet) { if (!c.halted()) total += c.getCurrentUploadRate(); } long limit = 1024l * _util.getMaxUpBW(); if (_log.shouldLog(Log.INFO)) _log.info("Total up bw: " + total + " Limit: " + limit); return total > limit; }
public boolean overUploadLimit(int uploaders) { if (_peerCoordinatorSet == null || uploaders <= 0) return false; int totalUploaders = 0; for (PeerCoordinator c : _peerCoordinatorSet) { if (!c.halted()) totalUploaders += c.uploaders; } int limit = _util.getMaxUploaders(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Total uploaders: " + totalUploaders + " Limit: " + limit); return totalUploaders > limit; }
private TrackerInfo doRequest( String announce, String infoHash, String peerID, long uploaded, long downloaded, long left, String event) throws IOException { String s = announce + "?info_hash=" + infoHash + "&peer_id=" + peerID + "&port=" + port + "&uploaded=" + uploaded + "&downloaded=" + downloaded + "&left=" + left + ((event != NO_EVENT) ? ("&event=" + event) : ""); URL u = new URL(s); if (Snark.debug >= Snark.INFO) Snark.debug("Sending TrackerClient request: " + u, Snark.INFO); URLConnection c = u.openConnection(); c.connect(); InputStream in = c.getInputStream(); if (c instanceof HttpURLConnection) { // Check whether the page exists int code = ((HttpURLConnection) c).getResponseCode(); if (code / 100 != 2) // We can only handle 200 OK responses throw new IOException( "Loading '" + s + "' gave error code " + code + ", it probably doesn't exists"); } TrackerInfo info = new TrackerInfo(in, coordinator.getID(), coordinator.getMetaInfo()); if (Snark.debug >= Snark.INFO) Snark.debug("TrackerClient response: " + info, Snark.INFO); lastRequestTime = System.currentTimeMillis(); String failure = info.getFailureReason(); if (failure != null) throw new IOException(failure); interval = info.getInterval() * 1000; return info; }
/** * Called when the PeerCoordinator got the MetaInfo via magnet. CoordinatorListener. Create the * storage, tell SnarkManager, and give the storage back to the coordinator. * * @throws RuntimeException via fatal() * @since 0.8.4 */ public void gotMetaInfo(PeerCoordinator coordinator, MetaInfo metainfo) { try { String base = Storage.filterName(metainfo.getName()); File baseFile; if (_util.getFilesPublic()) baseFile = new File(rootDataDir, base); else baseFile = new SecureFile(rootDataDir, base); // The following two may throw IOE... storage = new Storage(_util, baseFile, metainfo, this, false); storage.check(); // ... so don't set meta until here meta = metainfo; if (completeListener != null) { String newName = completeListener.gotMetaInfo(this); if (newName != null) torrent = newName; // else some horrible problem } coordinator.setStorage(storage); } catch (IOException ioe) { if (storage != null) { try { storage.close(); } catch (IOException ioee) { } } fatal("Could not check or create storage", ioe); } }
public TrackerClient(MetaInfo meta, PeerCoordinator coordinator, int port) { // Set unique name. super("TrackerClient-" + urlencode(coordinator.getID())); this.meta = meta; this.coordinator = coordinator; // XXX - No way to actaully give the tracker feedback that we // don't run a peer acceptor on any port so use discard 9/tcp sink null this.port = (port == -1) ? 9 : port; stop = false; }
/** * Stop contacting the tracker and talking with peers * * @param fast if true, limit the life of the unannounce threads * @since 0.9.1 */ public synchronized void stopTorrent(boolean fast) { stopped = true; TrackerClient tc = trackerclient; if (tc != null) tc.halt(fast); PeerCoordinator pc = coordinator; if (pc != null) pc.halt(); Storage st = storage; if (st != null) { // TODO: Cache the config-in-mem to compare vs config-on-disk // (needed for auto-save to not double-save in some cases) // boolean changed = storage.isChanged() || getUploaded() != savedUploaded; boolean changed = true; try { storage.close(); } catch (IOException ioe) { System.out.println("Error closing " + torrent); ioe.printStackTrace(); } if (changed && completeListener != null) completeListener.updateStatus(this); } if (pc != null && _peerCoordinatorSet != null) _peerCoordinatorSet.remove(pc); if (_peerCoordinatorSet == null) _util.disconnect(); }
/** * Bytes still wanted. DOES account for (i.e. does not include) skipped files. FIXME -1 when not * running. * * @return exact value. or -1 if no storage yet or when not running. * @since 0.9.1 */ public long getNeededLength() { PeerCoordinator coord = coordinator; if (coord != null) return coord.getNeededLength(); return -1; }
/** @since 0.8.4 */ public void updatePiecePriorities() { PeerCoordinator coord = coordinator; if (coord != null) coord.updatePiecePriorities(); }
/** Returns the 4-minute-average rate in Bps */ public long getUploadRate() { return PeerCoordinator.getRate(uploaded_old); }
/** @since 0.8.4 */ public long getUploaded() { PeerCoordinator coord = coordinator; if (coord != null) return coord.getUploaded(); return savedUploaded; }
/** @since 0.8.4 */ public long getDownloaded() { PeerCoordinator coord = coordinator; if (coord != null) return coord.getDownloaded(); return 0; }
/** @since 0.8.4 */ public long getUploadRate() { PeerCoordinator coord = coordinator; if (coord != null) return coord.getUploadRate(); return 0; }
public void run() { // XXX - Support other IPs String announce = meta.getAnnounce(); String infoHash = urlencode(meta.getInfoHash()); String peerID = urlencode(coordinator.getID()); long uploaded = coordinator.getUploaded(); long downloaded = coordinator.getDownloaded(); long left = coordinator.getLeft(); boolean completed = (left == 0); try { boolean started = false; while (!started) { try { // Send start. TrackerInfo info = doRequest(announce, infoHash, peerID, uploaded, downloaded, left, STARTED_EVENT); Iterator it = info.getPeers().iterator(); while (it.hasNext()) coordinator.addPeer((Peer) it.next()); 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); } if (!started && !stop) { Snark.debug(" Retrying in one minute...", Snark.DEBUG); try { // Sleep one minutes... Thread.sleep(60 * 1000); } catch (InterruptedException interrupt) { // ignore } } } while (!stop) { try { // Sleep some minutes... Thread.sleep(SLEEP * 60 * 1000); } catch (InterruptedException interrupt) { // ignore } if (stop) break; uploaded = coordinator.getUploaded(); downloaded = coordinator.getDownloaded(); left = coordinator.getLeft(); // First time we got a complete download? String event; if (!completed && left == 0) { completed = true; event = COMPLETED_EVENT; } else event = NO_EVENT; // Only do a request when necessary. if (event == COMPLETED_EVENT || coordinator.needPeers() || System.currentTimeMillis() > lastRequestTime + interval) { try { TrackerInfo info = doRequest(announce, infoHash, peerID, uploaded, downloaded, left, event); Iterator it = info.getPeers().iterator(); while (it.hasNext()) coordinator.addPeer((Peer) it.next()); } 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); } } } } catch (Throwable t) { Snark.debug("TrackerClient: " + t, Snark.ERROR); t.printStackTrace(); } finally { try { TrackerInfo info = doRequest(announce, infoHash, peerID, uploaded, downloaded, left, STOPPED_EVENT); } catch (IOException ioe) { /* ignored */ } } }
/** @since 0.8.4 */ public int getPeerCount() { PeerCoordinator coord = coordinator; if (coord != null) return coord.getPeerCount(); return 0; }
/** Push the total uploaded/downloaded onto a RATE_DEPTH deep stack */ public void setRateHistory(long up, long down) { PeerCoordinator.setRate(up, uploaded_old); PeerCoordinator.setRate(down, downloaded_old); }
/** @since 0.8.4 */ public List<Peer> getPeerList() { PeerCoordinator coord = coordinator; if (coord != null) return coord.peerList(); return Collections.emptyList(); }
public long getDownloadRate() { return PeerCoordinator.getRate(downloaded_old); }
public void setWantedPieces(Storage storage) { coordinator.setWantedPieces(); }