Search in sources :

Example 6 with DHT

use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.

the class I2PSnarkServlet method writeTorrents.

/**
 *  @param canWrite is the data directory writable?
 *  @return true if on first page
 */
private boolean writeTorrents(PrintWriter out, HttpServletRequest req, boolean canWrite) throws IOException {
    /**
     * dl, ul, down rate, up rate, peers, size
     */
    final long[] stats = { 0, 0, 0, 0, 0, 0 };
    String peerParam = req.getParameter("p");
    String stParam = req.getParameter("st");
    List<Snark> snarks = getSortedSnarks(req);
    boolean isForm = _manager.util().connected() || !snarks.isEmpty();
    if (isForm) {
        out.write("<form action=\"_post\" method=\"POST\">\n");
        writeHiddenInputs(out, req, null);
    }
    out.write(TABLE_HEADER);
    // Opera and text-mode browsers: no &thinsp; and no input type=image values submitted
    // Using a unique name fixes Opera, except for the buttons with js confirms, see below
    String ua = req.getHeader("User-Agent");
    boolean isDegraded = ua != null && ServletUtil.isTextBrowser(ua);
    boolean noThinsp = isDegraded || (ua != null && ua.startsWith("Opera"));
    // pages
    int start = 0;
    int total = snarks.size();
    if (stParam != null) {
        try {
            start = Math.max(0, Math.min(total - 1, Integer.parseInt(stParam)));
        } catch (NumberFormatException nfe) {
        }
    }
    int pageSize = Math.max(_manager.getPageSize(), 5);
    String currentSort = req.getParameter("sort");
    boolean showSort = total > 1;
    out.write("<tr><th class=\"snarkGraphicStatus\">");
    String sort = ("2".equals(currentSort)) ? "-2" : "2";
    if (showSort) {
        out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
        out.write("\">");
    }
    String tx = _t("Status");
    out.write(toThemeImg("status", tx, showSort ? _t("Sort by {0}", tx) : tx));
    if (showSort)
        out.write("</a>");
    out.write("</th>\n<th class=\"snarkTorrentStatus\">");
    if (_manager.util().connected() && !snarks.isEmpty()) {
        out.write(" <a href=\"" + _contextPath + '/');
        if (peerParam != null) {
            // disable peer view
            out.write(getQueryString(req, "", null, null));
            out.write("\">");
            tx = _t("Hide Peers");
            out.write(toThemeImg("hidepeers", tx, tx));
        } else {
            // enable peer view
            out.write(getQueryString(req, "1", null, null));
            out.write("\">");
            tx = _t("Show Peers");
            out.write(toThemeImg("showpeers", tx, tx));
        }
        out.write("</a>\n");
    }
    out.write("</th>\n<th colspan=\"2\" align=\"left\">");
    // cycle through sort by name or type
    boolean isTypeSort = false;
    if (showSort) {
        if (currentSort == null || "0".equals(currentSort) || "1".equals(currentSort)) {
            sort = "-1";
        } else if ("-1".equals(currentSort)) {
            sort = "12";
            isTypeSort = true;
        } else if ("12".equals(currentSort)) {
            sort = "-12";
            isTypeSort = true;
        } else {
            sort = "";
        }
        out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
        out.write("\">");
    }
    tx = _t("Torrent");
    out.write(toThemeImg("torrent", tx, showSort ? _t("Sort by {0}", (isTypeSort ? _t("File type") : tx)) : tx));
    if (showSort)
        out.write("</a>");
    out.write("</th>\n<th id=\"pagenav\" align=\"center\">");
    if (total > 0 && (start > 0 || total > pageSize)) {
        writePageNav(out, req, start, pageSize, total, noThinsp);
    }
    out.write("</th>\n<th class=\"snarkTorrentETA\" align=\"right\">");
    if (_manager.util().connected() && !snarks.isEmpty()) {
        if (showSort) {
            sort = ("-4".equals(currentSort)) ? "4" : "-4";
            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
            out.write("\">");
        }
        // Translators: Please keep short or translate as " "
        tx = _t("ETA");
        out.write(toThemeImg("eta", tx, showSort ? _t("Sort by {0}", _t("Estimated time remaining")) : _t("Estimated time remaining")));
        if (showSort)
            out.write("</a>");
    }
    out.write("</th>\n<th class=\"snarkTorrentDownloaded\" align=\"right\">");
    // cycle through sort by size or downloaded
    boolean isDlSort = false;
    if (showSort) {
        if ("-5".equals(currentSort)) {
            sort = "5";
        } else if ("5".equals(currentSort)) {
            sort = "-6";
            isDlSort = true;
        } else if ("-6".equals(currentSort)) {
            sort = "6";
            isDlSort = true;
        } else {
            sort = "-5";
        }
        out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
        out.write("\">");
    }
    // Translators: Please keep short or translate as " "
    tx = _t("RX");
    out.write(toThemeImg("head_rx", tx, showSort ? _t("Sort by {0}", (isDlSort ? _t("Downloaded") : _t("Size"))) : _t("Downloaded")));
    if (showSort)
        out.write("</a>");
    out.write("</th>\n<th class=\"snarkTorrentUploaded\" align=\"right\">");
    boolean isRatSort = false;
    if (!snarks.isEmpty()) {
        // cycle through sort by uploaded or ratio
        boolean nextRatSort = false;
        if (showSort) {
            if ("-7".equals(currentSort)) {
                sort = "7";
            } else if ("7".equals(currentSort)) {
                sort = "-11";
                nextRatSort = true;
            } else if ("-11".equals(currentSort)) {
                sort = "11";
                nextRatSort = true;
                isRatSort = true;
            } else if ("11".equals(currentSort)) {
                sort = "-7";
                isRatSort = true;
            } else {
                sort = "-7";
            }
            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
            out.write("\">");
        }
        // Translators: Please keep short or translate as " "
        tx = _t("TX");
        out.write(toThemeImg("head_tx", tx, showSort ? _t("Sort by {0}", (nextRatSort ? _t("Upload ratio") : _t("Uploaded"))) : _t("Uploaded")));
        if (showSort)
            out.write("</a>");
    }
    out.write("</th>\n<th class=\"snarkTorrentRateDown\" align=\"right\">");
    if (_manager.util().connected() && !snarks.isEmpty()) {
        if (showSort) {
            sort = ("-8".equals(currentSort)) ? "8" : "-8";
            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
            out.write("\">");
        }
        // Translators: Please keep short or translate as " "
        tx = _t("RX Rate");
        out.write(toThemeImg("head_rxspeed", tx, showSort ? _t("Sort by {0}", _t("Down Rate")) : _t("Down Rate")));
        if (showSort)
            out.write("</a>");
    }
    out.write("</th>\n<th class=\"snarkTorrentRateUp\" align=\"right\">");
    if (_manager.util().connected() && !snarks.isEmpty()) {
        if (showSort) {
            sort = ("-9".equals(currentSort)) ? "9" : "-9";
            out.write("<a href=\"" + _contextPath + '/' + getQueryString(req, null, null, sort));
            out.write("\">");
        }
        // Translators: Please keep short or translate as " "
        tx = _t("TX Rate");
        out.write(toThemeImg("head_txspeed", tx, showSort ? _t("Sort by {0}", _t("Up Rate")) : _t("Up Rate")));
        if (showSort)
            out.write("</a>");
    }
    out.write("</th>\n<th class=\"snarkTorrentAction\" align=\"center\">");
    if (_manager.isStopping()) {
        out.write("&nbsp;");
    } else if (_manager.util().connected()) {
        if (isDegraded)
            out.write("<a href=\"" + _contextPath + "/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\"");
        else {
            // http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
            // out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
            out.write("<input type=\"image\" name=\"action_StopAll\" value=\"foo\" title=\"");
        }
        out.write(_t("Stop all torrents and the I2P tunnel"));
        out.write("\" src=\"" + _imgPath + "stop_all.png\" alt=\"");
        out.write(_t("Stop All"));
        out.write("\">");
        if (isDegraded)
            out.write("</a>");
        for (Snark s : snarks) {
            if (s.isStopped()) {
                // show startall too
                if (isDegraded)
                    out.write("<a href=\"" + _contextPath + "/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
                else
                    out.write("<input type=\"image\" name=\"action_StartAll\" value=\"foo\" title=\"");
                out.write(_t("Start all stopped torrents"));
                out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\"");
                out.write(_t("Start All"));
                out.write("\">");
                if (isDegraded)
                    out.write("</a>");
                break;
            }
        }
    } else if ((!_manager.util().isConnecting()) && !snarks.isEmpty()) {
        if (isDegraded)
            out.write("<a href=\"" + _contextPath + "/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
        else
            out.write("<input type=\"image\" name=\"action_StartAll\" value=\"foo\" title=\"");
        out.write(_t("Start all torrents and the I2P tunnel"));
        out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\"");
        out.write(_t("Start All"));
        out.write("\">");
        if (isDegraded)
            out.write("</a>");
    } else {
        out.write("&nbsp;");
    }
    out.write("</th></tr>\n");
    out.write("</thead>\n");
    String uri = _contextPath + '/';
    boolean showDebug = "2".equals(peerParam);
    for (int i = 0; i < total; i++) {
        Snark snark = snarks.get(i);
        boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.getInfoHash()).equals(peerParam);
        boolean hide = i < start || i >= start + pageSize;
        displaySnark(out, req, snark, uri, i, stats, showPeers, isDegraded, noThinsp, showDebug, hide, isRatSort, canWrite);
    }
    if (total == 0) {
        out.write("<tr class=\"snarkTorrentNoneLoaded\">" + "<td colspan=\"11\">");
        synchronized (this) {
            File dd = _resourceBase;
            if (!dd.exists() && !dd.mkdirs()) {
                out.write(_t("Data directory cannot be created") + ": " + DataHelper.escapeHTML(dd.toString()));
            } else if (!dd.isDirectory()) {
                out.write(_t("Not a directory") + ": " + DataHelper.escapeHTML(dd.toString()));
            } else if (!dd.canRead()) {
                out.write(_t("Unreadable") + ": " + DataHelper.escapeHTML(dd.toString()));
            } else if (canWrite) {
                out.write(_t("No write permissions for data directory") + ": " + DataHelper.escapeHTML(dd.toString()));
            } else {
                out.write(_t("No torrents loaded."));
            }
        }
        out.write("</td></tr>\n");
    } else /**
     * if (snarks.size() > 1)
     */
    {
        out.write("<tfoot><tr>\n" + "    <th id=\"snarkTorrentTotals\" align=\"left\" colspan=\"6\">");
        out.write("<span id=\"totals\">");
        out.write(_t("Totals"));
        out.write(":&nbsp;");
        out.write(ngettext("1 torrent", "{0} torrents", total));
        out.write(", ");
        out.write(formatSize(stats[5]));
        if (_manager.util().connected() && total > 0) {
            out.write(", ");
            out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4]));
        }
        DHT dht = _manager.util().getDHT();
        if (dht != null) {
            int dhts = dht.size();
            if (dhts > 0) {
                out.write(", <span>");
                out.write(ngettext("1 DHT peer", "{0} DHT peers", dhts));
                out.write("</span>");
            }
        }
        String IPString = _manager.util().getOurIPString();
        if (!IPString.equals("unknown")) {
            // Only truncate if it's an actual dest
            out.write(";&nbsp;<span id=\"ourDest\">");
            out.write(_t("Dest"));
            out.write(":&nbsp;<tt title=\"");
            out.write(_t("Our destination (identity) for this session"));
            out.write("\">");
            out.write(IPString.substring(0, 4));
            out.write("</tt></span>");
        }
        out.write("</span>");
        out.write("</th>\n");
        if (_manager.util().connected() && total > 0) {
            out.write("    <th class=\"snarkTorrentDownloaded\" align=\"right\">" + formatSize(stats[0]) + "</th>\n" + "    <th class=\"snarkTorrentUploaded\" align=\"right\">" + formatSize(stats[1]) + "</th>\n" + "    <th class=\"snarkTorrentRateDown\" align=\"right\">" + formatSizeDec(stats[2]) + "ps</th>\n" + "    <th class=\"snarkTorrentRateUp\" align=\"right\">" + formatSizeDec(stats[3]) + "ps</th>\n" + "    <th class=\"snarkTorrentAction\"></th>");
        } else {
            out.write("<th colspan=\"5\"></th>");
        }
        // TODO javascript handler to remember checkbox status for debug panel visibility (otherwise resets with ajax/meta refresh)
        if (dht != null) {
            if (showDebug) {
                out.write("</tr>\n<tr class=\"dhtDebug\">");
                out.write("<th colspan=\"11\">");
                out.write("<div id=\"dhtDebugPanel\">");
                out.write("<input class=\"toggle_input\" id=\"toggle_debug\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_debug\">");
                out.write(toThemeImg("debug"));
                out.write(' ');
                out.write(_t("Dht Debug"));
                out.write("</label><div id=\"dhtDebugInner\">");
                out.write(dht.renderStatusHTML());
                out.write("</div></div></th>");
            }
        }
        out.write("</tr></tfoot>\n");
    }
    out.write("</table>");
    if (isForm)
        out.write("</form>\n");
    return start == 0;
}
Also used : DHT(org.klomp.snark.dht.DHT) Snark(org.klomp.snark.Snark) SecureFile(net.i2p.util.SecureFile) File(java.io.File)

Example 7 with DHT

use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.

the class TrackerClient method getPeersFromTrackers.

/**
 *  @return max peers seen
 */
private int getPeersFromTrackers(List<TCTracker> trckrs) {
    // -1 in magnet mode
    long left = coordinator.getLeft();
    // First time we got a complete download?
    boolean newlyCompleted;
    if (!completed && left == 0) {
        completed = true;
        newlyCompleted = true;
    } else {
        newlyCompleted = false;
    }
    // *** loop once for each tracker
    int maxSeenPeers = 0;
    for (TCTracker tr : trckrs) {
        if ((!stop) && (!tr.stop) && (completed || coordinator.needOutboundPeers() || !tr.started) && (newlyCompleted || System.currentTimeMillis() > tr.lastRequestTime + tr.interval)) {
            try {
                long uploaded = coordinator.getUploaded();
                long downloaded = coordinator.getDownloaded();
                long len = snark.getTotalLength();
                if (len > 0 && downloaded > len)
                    downloaded = len;
                left = coordinator.getLeft();
                String event;
                if (!tr.started) {
                    event = STARTED_EVENT;
                } else if (newlyCompleted) {
                    event = COMPLETED_EVENT;
                } else {
                    event = NO_EVENT;
                }
                TrackerInfo info = doRequest(tr, infoHash, peerID, uploaded, downloaded, left, event);
                snark.setTrackerProblems(null);
                tr.trackerProblems = null;
                tr.registerFails = 0;
                tr.consecutiveFails = 0;
                if (tr.isPrimary)
                    consecutiveFails = 0;
                runStarted = true;
                tr.started = true;
                tr.seenPeers = info.getPeerCount();
                if (// update rising number quickly
                snark.getTrackerSeenPeers() < tr.seenPeers)
                    snark.setTrackerSeenPeers(tr.seenPeers);
                // just for update torrent
                if (completed && tr.isPrimary && snark.isAutoStoppable() && !snark.isChecking() && info.getSeedCount() > 100 && coordinator.getPeerCount() <= 0 && _util.getContext().clock().now() > _startedOn + 30 * 60 * 1000 && snark.getTotalLength() > 0 && uploaded >= snark.getTotalLength() / 2) {
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("Auto stopping " + snark.getBaseName());
                    snark.setAutoStoppable(false);
                    snark.stopTorrent();
                    return tr.seenPeers;
                }
                Set<Peer> peers = info.getPeers();
                // pass everybody over to our tracker
                DHT dht = _util.getDHT();
                if (dht != null) {
                    for (Peer peer : peers) {
                        dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash(), // TODO actual seed/leech status
                        false);
                    }
                }
                if (coordinator.needOutboundPeers()) {
                    // we only want to talk to new people if we need things
                    // from them (duh)
                    List<Peer> ordered = new ArrayList<Peer>(peers);
                    Random r = _util.getContext().random();
                    Collections.shuffle(ordered, r);
                    Iterator<Peer> it = ordered.iterator();
                    while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
                        Peer cur = it.next();
                        // only delay if we actually make an attempt to add peer
                        if (coordinator.addPeer(cur) && it.hasNext()) {
                            int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
                            try {
                                Thread.sleep(delay);
                            } catch (InterruptedException ie) {
                            }
                        }
                    }
                }
            } catch (IOException ioe) {
                // Probably not fatal (if it doesn't last to long...)
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Could not contact tracker at '" + tr.announce + "': " + ioe);
                tr.trackerProblems = ioe.getMessage();
                // ... and only if we don't have any peers at all. Otherwise, PEX/DHT will save us.
                if (tr.isPrimary && coordinator.getPeers() <= 0 && (!completed || _util.getDHT() == null || _util.getDHT().size() <= 0))
                    snark.setTrackerProblems(tr.trackerProblems);
                String tplc = tr.trackerProblems.toLowerCase(Locale.US);
                if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2) || tplc.startsWith(NOT_REGISTERED_3) || tplc.startsWith(ERROR_GOT_HTML)) {
                    // } else { // hopefully each on the opentrackers list is really open
                    if (tr.registerFails++ > MAX_REGISTER_FAILS || // no use retrying if we aren't seeding
                    !completed || // fake msg from doRequest()
                    tplc.startsWith(ERROR_GOT_HTML) || (!tr.isPrimary && tr.registerFails > MAX_REGISTER_FAILS / 2))
                        if (_log.shouldLog(Log.WARN))
                            _log.warn("Not longer announcing to " + tr.announce + " : " + tr.trackerProblems + " after " + tr.registerFails + " failures");
                    tr.stop = true;
                // 
                }
                if (++tr.consecutiveFails == MAX_CONSEC_FAILS) {
                    tr.seenPeers = 0;
                    if (tr.interval < LONG_SLEEP)
                        // slow down
                        tr.interval = LONG_SLEEP;
                }
            }
        } else {
            if (_log.shouldLog(Log.INFO))
                _log.info("Not announcing to " + tr.announce + " last announce was " + new Date(tr.lastRequestTime) + " interval is " + DataHelper.formatDuration(tr.interval));
        }
        if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
            maxSeenPeers = tr.seenPeers;
    }
    return maxSeenPeers;
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) Date(java.util.Date) DHT(org.klomp.snark.dht.DHT) Random(java.util.Random)

Example 8 with DHT

use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.

the class PeerCoordinator method sendDHT.

/**
 *  Send a DHT message to the peer, if we both support DHT.
 *  @since DHT
 */
void sendDHT(Peer peer) {
    DHT dht = _util.getDHT();
    if (dht == null)
        return;
    Map<String, BEValue> handshake = peer.getHandshakeMap();
    if (handshake == null)
        return;
    BEValue bev = handshake.get("m");
    if (bev == null)
        return;
    try {
        if (bev.getMap().get(ExtensionHandler.TYPE_DHT) != null)
            ExtensionHandler.sendDHT(peer, dht.getPort(), dht.getRPort());
    } catch (InvalidBEncodingException ibee) {
    }
}
Also used : DHT(org.klomp.snark.dht.DHT) InvalidBEncodingException(org.klomp.snark.bencode.InvalidBEncodingException) BEValue(org.klomp.snark.bencode.BEValue)

Example 9 with DHT

use of org.klomp.snark.dht.DHT in project i2p.i2p by i2p.

the class PeerCheckerTask method run.

public void run() {
    _runCount++;
    List<Peer> peerList = coordinator.peerList();
    if (peerList.isEmpty() || coordinator.halted()) {
        coordinator.setRateHistory(0, 0);
        return;
    }
    // Calculate total uploading and worst downloader.
    long worstdownload = Long.MAX_VALUE;
    Peer worstDownloader = null;
    int uploaders = 0;
    int interestedUploaders = 0;
    int removedCount = 0;
    long uploaded = 0;
    long downloaded = 0;
    // Keep track of peers we remove now,
    // we will add them back to the end of the list.
    List<Peer> removed = new ArrayList<Peer>();
    int uploadLimit = coordinator.allowedUploaders();
    boolean overBWLimit = coordinator.overUpBWLimit();
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("START peers: " + peerList.size() + " uploaders: " + coordinator.getUploaders() + " interested: " + coordinator.getInterestedUploaders() + " limit: " + uploadLimit + " overBW? " + overBWLimit);
    DHT dht = _util.getDHT();
    boolean fetchComments = _util.utCommentsEnabled();
    int i = 0;
    for (Peer peer : peerList) {
        i++;
        // Remove dying peers
        if (!peer.isConnected()) {
            // coordinator.peerCount = coordinator.peers.size();
            continue;
        }
        if (peer.getInactiveTime() > PeerCoordinator.MAX_INACTIVE) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Disconnecting peer idle " + DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer);
            peer.disconnect();
            continue;
        }
        // from some other torrent
        if (peer.isInterested() && !peer.isChoking())
            uploaders++;
        long upload = peer.getUploaded();
        uploaded += upload;
        long download = peer.getDownloaded();
        downloaded += download;
        peer.setRateHistory(upload, download);
        peer.resetCounters();
        if (_log.shouldLog(Log.DEBUG)) {
            _log.debug(peer + ":" + " ul: " + upload * 1024 / KILOPERSECOND + " dl: " + download * 1024 / KILOPERSECOND + " i: " + peer.isInterested() + " I: " + peer.isInteresting() + " c: " + peer.isChoking() + " C: " + peer.isChoked());
        }
        // Choke a percentage of them rather than all so it isn't so drastic...
        // unless this torrent is over the limit all by itself.
        // choke 5/8 of the time when seeding and 3/8 when leeching
        boolean overBWLimitChoke = upload > 0 && ((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 2 : 4))) || (coordinator.overUpBWLimit(uploaded)));
        // If we are at our max uploaders and we have lots of other
        // interested peers try to make some room.
        // (Note use of coordinator.uploaders)
        int cup = coordinator.getUploaders();
        if (((cup == uploadLimit && coordinator.getInterestedAndChoking() > 0) || cup > uploadLimit || overBWLimitChoke) && !peer.isChoking()) {
            // Check if it still wants pieces from us.
            if (!peer.isInterested()) {
                // so a peer may remain unchoked even if uninterested.
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("Choke uninterested peer: " + peer);
                peer.setChoking(true);
                uploaders--;
                coordinator.decrementUploaders(false);
                // Put it at the back of the list
                removed.add(peer);
            } else if (overBWLimitChoke) {
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer);
                peer.setChoking(true);
                uploaders--;
                interestedUploaders--;
                coordinator.decrementUploaders(true);
                removedCount++;
                // Put it at the back of the list for fairness, even though we won't be unchoking this time
                removed.add(peer);
            } else if (peer.isInteresting() && peer.isChoked()) {
                // If they are choking us make someone else a downloader
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("Choke choking peer: " + peer);
                peer.setChoking(true);
                uploaders--;
                interestedUploaders--;
                coordinator.decrementUploaders(true);
                removedCount++;
                // Put it at the back of the list
                removed.add(peer);
            } else if (!peer.isInteresting() && !coordinator.completed()) {
                // If they aren't interesting make someone else a downloader
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("Choke uninteresting peer: " + peer);
                peer.setChoking(true);
                uploaders--;
                interestedUploaders--;
                coordinator.decrementUploaders(true);
                removedCount++;
                // Put it at the back of the list
                removed.add(peer);
            } else if (peer.isInteresting() && !peer.isChoked() && download == 0) {
                // We are downloading but didn't receive anything...
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug("Choke downloader that doesn't deliver: " + peer);
                peer.setChoking(true);
                uploaders--;
                interestedUploaders--;
                coordinator.decrementUploaders(true);
                removedCount++;
                // Put it at the back of the list
                removed.add(peer);
            } else if (peer.isInteresting() && !peer.isChoked() && download < worstdownload) {
                // Make sure download is good if we are uploading
                worstdownload = download;
                worstDownloader = peer;
            } else if (upload < worstdownload && coordinator.completed()) {
                // Make sure upload is good if we are seeding
                worstdownload = upload;
                worstDownloader = peer;
            }
        }
        peer.retransmitRequests();
        // send PEX, about every 12 minutes
        if (((_runCount + i) % 17) == 0 && !peer.isCompleted())
            coordinator.sendPeers(peer);
        // send Comment Request, about every 30 minutes
        if (fetchComments && ((_runCount + i) % 47) == 0)
            coordinator.sendCommentReq(peer);
        // the inactive checker (above) will eventually disconnect it
        if (coordinator.getNeededLength() > 0 || !peer.isCompleted())
            peer.keepAlive();
        // announce them to local tracker (TrackerClient does this too)
        if (dht != null && (_runCount % 5) == 0) {
            dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash(), peer.isCompleted());
        }
    }
    // for peer
    // Resync actual uploaders value
    // (can shift a bit by disconnecting peers)
    coordinator.setUploaders(uploaders, interestedUploaders);
    // Remove the worst downloader if needed. (uploader if seeding)
    if (((uploaders == uploadLimit && coordinator.getInterestedAndChoking() > 0) || uploaders > uploadLimit) && worstDownloader != null) {
        if (_log.shouldLog(Log.DEBUG))
            _log.debug("Choke worst downloader: " + worstDownloader);
        worstDownloader.setChoking(true);
        coordinator.decrementUploaders(worstDownloader.isInterested());
        removedCount++;
        // Put it at the back of the list
        removed.add(worstDownloader);
    }
    boolean coordOver = coordinator.overUpBWLimit(uploaded);
    synchronized (coordinator.peers) {
        if ((!overBWLimit) && !coordOver) {
            // Optimistically unchoke a peer
            // must be called inside synch
            coordinator.unchokePeer();
        }
        // Put peers back at the end of the list that we removed earlier.
        for (Peer peer : removed) {
            if (coordinator.peers.remove(peer))
                coordinator.peers.add(peer);
        }
    }
    coordinator.addInterestedAndChoking(removedCount);
    // store the rates
    coordinator.setRateHistory(uploaded, downloaded);
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("END peers: " + peerList.size() + " uploaders: " + uploaders + " interested: " + interestedUploaders);
    // close out unused files, but we don't need to do it every time
    Storage storage = coordinator.getStorage();
    if (storage != null) {
        // The more files a torrent has, the more often we call the cleaner,
        // to keep from running out of FDs
        int files = storage.getFileCount();
        int skip;
        if (files == 1)
            skip = 6;
        else if (files <= 4)
            skip = 4;
        else if (files <= 20)
            skip = 3;
        else if (files <= 50)
            skip = 2;
        else
            skip = 1;
        if ((_runCount % skip) == 0)
            storage.cleanRAFs();
    }
    // announce ourselves to local tracker (TrackerClient does this too)
    if (dht != null && (_runCount % 16) == 0) {
        dht.announce(coordinator.getInfoHash(), coordinator.completed());
    }
}
Also used : DHT(org.klomp.snark.dht.DHT) ArrayList(java.util.ArrayList)

Aggregations

DHT (org.klomp.snark.dht.DHT)9 ArrayList (java.util.ArrayList)3 Random (java.util.Random)3 InvalidBEncodingException (org.klomp.snark.bencode.InvalidBEncodingException)2 File (java.io.File)1 IOException (java.io.IOException)1 Date (java.util.Date)1 Hash (net.i2p.data.Hash)1 ConvertToHash (net.i2p.util.ConvertToHash)1 I2PAppThread (net.i2p.util.I2PAppThread)1 SecureFile (net.i2p.util.SecureFile)1 Snark (org.klomp.snark.Snark)1 BEValue (org.klomp.snark.bencode.BEValue)1 CommentSet (org.klomp.snark.comments.CommentSet)1