i2psnark: Don't disconnect seeds immediately if comments enabled (ticket #2288)

Implement variable timeout
Hardcode handshake bytes
Log tweaks
This commit is contained in:
zzz
2018-07-31 14:13:33 +00:00
parent a51d260a78
commit 5c3e408772
4 changed files with 47 additions and 15 deletions

View File

@ -79,6 +79,7 @@ public class Peer implements Comparable<Peer>
private long uploaded_old[] = {-1,-1,-1}; private long uploaded_old[] = {-1,-1,-1};
private long downloaded_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 // bytes per bt spec: 0011223344556677
private static final long OPTION_EXTENSION = 0x0000000000100000l; private static final long OPTION_EXTENSION = 0x0000000000100000l;
private static final long OPTION_FAST = 0x0000000000000004l; private static final long OPTION_FAST = 0x0000000000000004l;
@ -343,8 +344,8 @@ public class Peer implements Comparable<Peer>
dout = new DataOutputStream(out); dout = new DataOutputStream(out);
// Handshake write - header // Handshake write - header
dout.write(19); dout.write(HANDSHAKE.length);
dout.write("BitTorrent protocol".getBytes("UTF-8")); dout.write(HANDSHAKE);
// Handshake write - options // Handshake write - options
long myOptions = OPTION_EXTENSION; long myOptions = OPTION_EXTENSION;
// we can't handle HAVE_ALL or HAVE_NONE if we don't know the number of pieces // 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 // Handshake read - header
byte b = din.readByte(); byte b = din.readByte();
if (b != 19) if (b != HANDSHAKE.length)
throw new IOException("Handshake failure, expected 19, got " throw new IOException("Handshake failure, expected 19, got "
+ (b & 0xff) + " on " + sock); + (b & 0xff) + " on " + sock);
byte[] bs = new byte[19]; byte[] bs = new byte[HANDSHAKE.length];
din.readFully(bs); din.readFully(bs);
String bittorrentProtocol = new String(bs, "UTF-8"); if (!Arrays.equals(HANDSHAKE, bs))
if (!"BitTorrent protocol".equals(bittorrentProtocol))
throw new IOException("Handshake failure, expected " throw new IOException("Handshake failure, expected "
+ "'BitTorrent protocol', got '" + "'BitTorrent protocol'");
+ bittorrentProtocol + "'");
// Handshake read - options // Handshake read - options
options = din.readLong(); options = din.readLong();
@ -684,6 +683,13 @@ public class Peer implements Comparable<Peer>
return -1; //"no state"; return -1; //"no state";
} }
} }
/** @since 0.9.36 */
public long getMaxInactiveTime() {
return isCompleted() && !isInteresting() ?
PeerCoordinator.MAX_SEED_INACTIVE :
PeerCoordinator.MAX_INACTIVE;
}
/** /**
* Send keepalive * Send keepalive

View File

@ -96,7 +96,7 @@ class PeerCheckerTask implements Runnable
continue; continue;
} }
if (peer.getInactiveTime() > PeerCoordinator.MAX_INACTIVE) { if (peer.getInactiveTime() > peer.getMaxInactiveTime()) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Disconnecting peer idle " + _log.warn("Disconnecting peer idle " +
DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer); DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer);

View File

@ -75,6 +75,7 @@ class PeerCoordinator implements PeerListener
final static long CHECK_PERIOD = 40*1000; // 40 seconds final static long CHECK_PERIOD = 40*1000; // 40 seconds
final static int MAX_UPLOADERS = 8; final static int MAX_UPLOADERS = 8;
public static final long MAX_INACTIVE = 8*60*1000; 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), * Approximation of the number of current uploaders (unchoked peers),
@ -496,7 +497,7 @@ class PeerCoordinator implements PeerListener
synchronized(peers) synchronized(peers)
{ {
Peer old = peerIDInList(peer.getPeerID(), 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) // idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block)
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime()); _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() // thus there is an additional check in connected()
need_more = (!peer.isConnected()) && peersize < getMaxConnections(); need_more = (!peer.isConnected()) && peersize < getMaxConnections();
// Check if we already have this peer before we build the connection // Check if we already have this peer before we build the connection
Peer old = peerIDInList(peer.getPeerID(), peers); if (need_more) {
need_more = need_more && ((old == null) || (old.getInactiveTime() > MAX_INACTIVE)); Peer old = peerIDInList(peer.getPeerID(), peers);
need_more = old == null || old.getInactiveTime() > old.getMaxInactiveTime();
}
} }
if (need_more) if (need_more)
@ -629,9 +632,9 @@ class PeerCoordinator implements PeerListener
} }
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
if (peer.isConnected()) if (peer.isConnected())
_log.info("Add peer already connected: " + peer); _log.debug("Add peer already connected: " + peer);
else else
_log.info("Connections: " + peersize + "/" + getMaxConnections() _log.debug("Connections: " + peersize + "/" + getMaxConnections()
+ " not accepting extra peer: " + peer); + " not accepting extra peer: " + peer);
} }
return false; return false;

View File

@ -25,12 +25,16 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray; import net.i2p.data.ByteArray;
import net.i2p.util.Log; import net.i2p.util.Log;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
class PeerState implements DataLoader class PeerState implements DataLoader
{ {
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class); private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
@ -242,14 +246,33 @@ class PeerState implements DataLoader
} // synch } // synch
boolean interest = listener.gotBitField(peer, bitfield); boolean interest = listener.gotBitField(peer, bitfield);
setInteresting(interest);
if (bitfield.complete() && !interest) { if (bitfield.complete() && !interest) {
// They are seeding and we are seeding, // They are seeding and we are seeding,
// why did they contact us? (robert) // why did they contact us? (robert)
// Dump them quick before we send our whole bitmap // 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)) if (_log.shouldLog(Log.WARN))
_log.warn("Disconnecting seed that connects to seeds: " + peer); _log.warn("Disconnecting seed that connects to seeds: " + peer);
peer.disconnect(true); peer.disconnect(true);
} else {
setInteresting(interest);
} }
} }