From 5c3e408772b61dc6a537ed407fef66c56f1215bc Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Tue, 31 Jul 2018 14:13:33 +0000 Subject: [PATCH] i2psnark: Don't disconnect seeds immediately if comments enabled (ticket #2288) Implement variable timeout Hardcode handshake bytes Log tweaks --- .../java/src/org/klomp/snark/Peer.java | 22 ++++++++++------ .../src/org/klomp/snark/PeerCheckerTask.java | 2 +- .../src/org/klomp/snark/PeerCoordinator.java | 13 ++++++---- .../java/src/org/klomp/snark/PeerState.java | 25 ++++++++++++++++++- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java index 73588d12a9..d1a573e749 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java @@ -79,6 +79,7 @@ public class Peer implements Comparable<Peer> private long uploaded_old[] = {-1,-1,-1}; private long downloaded_old[] = {-1,-1,-1}; + private static final byte[] HANDSHAKE = DataHelper.getASCII("BitTorrent protocol"); // bytes per bt spec: 0011223344556677 private static final long OPTION_EXTENSION = 0x0000000000100000l; private static final long OPTION_FAST = 0x0000000000000004l; @@ -343,8 +344,8 @@ public class Peer implements Comparable<Peer> dout = new DataOutputStream(out); // Handshake write - header - dout.write(19); - dout.write("BitTorrent protocol".getBytes("UTF-8")); + dout.write(HANDSHAKE.length); + dout.write(HANDSHAKE); // Handshake write - options long myOptions = OPTION_EXTENSION; // we can't handle HAVE_ALL or HAVE_NONE if we don't know the number of pieces @@ -365,17 +366,15 @@ public class Peer implements Comparable<Peer> // Handshake read - header byte b = din.readByte(); - if (b != 19) + if (b != HANDSHAKE.length) throw new IOException("Handshake failure, expected 19, got " + (b & 0xff) + " on " + sock); - byte[] bs = new byte[19]; + byte[] bs = new byte[HANDSHAKE.length]; din.readFully(bs); - String bittorrentProtocol = new String(bs, "UTF-8"); - if (!"BitTorrent protocol".equals(bittorrentProtocol)) + if (!Arrays.equals(HANDSHAKE, bs)) throw new IOException("Handshake failure, expected " - + "'BitTorrent protocol', got '" - + bittorrentProtocol + "'"); + + "'BitTorrent protocol'"); // Handshake read - options options = din.readLong(); @@ -684,6 +683,13 @@ public class Peer implements Comparable<Peer> return -1; //"no state"; } } + + /** @since 0.9.36 */ + public long getMaxInactiveTime() { + return isCompleted() && !isInteresting() ? + PeerCoordinator.MAX_SEED_INACTIVE : + PeerCoordinator.MAX_INACTIVE; + } /** * Send keepalive diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java index 6aacfede49..91e21fa6f8 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java @@ -96,7 +96,7 @@ class PeerCheckerTask implements Runnable continue; } - if (peer.getInactiveTime() > PeerCoordinator.MAX_INACTIVE) { + if (peer.getInactiveTime() > peer.getMaxInactiveTime()) { if (_log.shouldLog(Log.WARN)) _log.warn("Disconnecting peer idle " + DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer); diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 285af4d19d..e21891cadf 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -75,6 +75,7 @@ class PeerCoordinator implements PeerListener final static long CHECK_PERIOD = 40*1000; // 40 seconds final static int MAX_UPLOADERS = 8; public static final long MAX_INACTIVE = 8*60*1000; + public static final long MAX_SEED_INACTIVE = 2*60*1000; /** * Approximation of the number of current uploaders (unchoked peers), @@ -496,7 +497,7 @@ class PeerCoordinator implements PeerListener synchronized(peers) { Peer old = peerIDInList(peer.getPeerID(), peers); - if ( (old != null) && (old.getInactiveTime() > MAX_INACTIVE) ) { + if (old != null && old.getInactiveTime() > old.getMaxInactiveTime()) { // idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block) if (_log.shouldLog(Log.WARN)) _log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime()); @@ -592,8 +593,10 @@ class PeerCoordinator implements PeerListener // thus there is an additional check in connected() need_more = (!peer.isConnected()) && peersize < getMaxConnections(); // Check if we already have this peer before we build the connection - Peer old = peerIDInList(peer.getPeerID(), peers); - need_more = need_more && ((old == null) || (old.getInactiveTime() > MAX_INACTIVE)); + if (need_more) { + Peer old = peerIDInList(peer.getPeerID(), peers); + need_more = old == null || old.getInactiveTime() > old.getMaxInactiveTime(); + } } if (need_more) @@ -629,9 +632,9 @@ class PeerCoordinator implements PeerListener } if (_log.shouldLog(Log.DEBUG)) { if (peer.isConnected()) - _log.info("Add peer already connected: " + peer); + _log.debug("Add peer already connected: " + peer); else - _log.info("Connections: " + peersize + "/" + getMaxConnections() + _log.debug("Connections: " + peersize + "/" + getMaxConnections() + " not accepting extra peer: " + peer); } return false; diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index 2e3edf1640..9f6b9a65b1 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -25,12 +25,16 @@ import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import net.i2p.I2PAppContext; import net.i2p.data.ByteArray; import net.i2p.util.Log; +import org.klomp.snark.bencode.BEValue; +import org.klomp.snark.bencode.InvalidBEncodingException; + class PeerState implements DataLoader { private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class); @@ -242,14 +246,33 @@ class PeerState implements DataLoader } // synch boolean interest = listener.gotBitField(peer, bitfield); - setInteresting(interest); if (bitfield.complete() && !interest) { // They are seeding and we are seeding, // why did they contact us? (robert) // Dump them quick before we send our whole bitmap + + // If we both support comments, allow it + if (listener.getUtil().utCommentsEnabled()) { + Map<String, BEValue> handshake = peer.getHandshakeMap(); + if (handshake != null) { + BEValue bev = handshake.get("m"); + if (bev != null) { + try { + if (bev.getMap().get(ExtensionHandler.TYPE_COMMENT) != null) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Allowing seed that connects to seeds for comments: " + peer); + setInteresting(interest); + return; + } + } catch (InvalidBEncodingException ibee) {} + } + } + } if (_log.shouldLog(Log.WARN)) _log.warn("Disconnecting seed that connects to seeds: " + peer); peer.disconnect(true); + } else { + setInteresting(interest); } } -- GitLab