From 38a4f05000b6091cd486012b1f93e87ed2f1338e Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 31 May 2012 15:20:50 +0000 Subject: [PATCH] * i2psnark: - Close connection immediately if bad protocol, this makes blacklist work better too - Stop adding peers when we hit the limit - Lower limit for outbound connections so we give new peers a better chance in large swarms --- .../org/klomp/snark/ConnectionAcceptor.java | 6 ++- .../src/org/klomp/snark/PeerAcceptor.java | 53 +++++++++++++++---- .../src/org/klomp/snark/PeerCoordinator.java | 4 +- .../src/org/klomp/snark/TrackerClient.java | 6 +-- history.txt | 4 ++ .../src/net/i2p/router/RouterVersion.java | 2 +- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/ConnectionAcceptor.java b/apps/i2psnark/java/src/org/klomp/snark/ConnectionAcceptor.java index 0211f6bbda..182d830bfb 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/ConnectionAcceptor.java +++ b/apps/i2psnark/java/src/org/klomp/snark/ConnectionAcceptor.java @@ -198,14 +198,16 @@ public class ConnectionAcceptor implements Runnable // this is for the readahead in PeerAcceptor.connection() in = new BufferedInputStream(in); if (_log.shouldLog(Log.DEBUG)) - _log.debug("Handling socket from " + _socket.getPeerDestination().calculateHash().toBase64()); + _log.debug("Handling socket from " + _socket.getPeerDestination().calculateHash()); peeracceptor.connection(_socket, in, out); } catch (PeerAcceptor.ProtocolException ihe) { _badCounter.increment(_socket.getPeerDestination().calculateHash()); + if (_log.shouldLog(Log.INFO)) + _log.info("Protocol error from " + _socket.getPeerDestination().calculateHash(), ihe); try { _socket.close(); } catch (IOException ignored) { } } catch (IOException ioe) { if (_log.shouldLog(Log.DEBUG)) - _log.debug("Error handling connection from " + _socket.getPeerDestination().calculateHash().toBase64(), ioe); + _log.debug("Error handling connection from " + _socket.getPeerDestination().calculateHash(), ioe); try { _socket.close(); } catch (IOException ignored) { } } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java b/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java index 53b14b1750..e8b1233735 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java @@ -46,6 +46,10 @@ public class PeerAcceptor private final PeerCoordinator coordinator; final PeerCoordinatorSet coordinators; + /** shorten timeout while reading handshake */ + private static final long HASH_READ_TIMEOUT = 45*1000; + + public PeerAcceptor(PeerCoordinator coordinator) { this.coordinator = coordinator; @@ -69,11 +73,20 @@ public class PeerAcceptor // talk about, and we can just look for that in our list of active torrents. byte peerInfoHash[] = null; if (in instanceof BufferedInputStream) { + // multitorrent in.mark(LOOKAHEAD_SIZE); - peerInfoHash = readHash(in); + long timeout = socket.getReadTimeout(); + socket.setReadTimeout(HASH_READ_TIMEOUT); + try { + peerInfoHash = readHash(in); + } catch (IOException ioe) { + // unique exception so ConnectionAcceptor can blame the peer + throw new ProtocolException(ioe.toString()); + } + socket.setReadTimeout(timeout); in.reset(); } else { - // is this working right? + // Single torrent - is this working right? try { peerInfoHash = readHash(in); if (_log.shouldLog(Log.INFO)) @@ -130,23 +143,41 @@ public class PeerAcceptor } } + private static final String PROTO_STR = "BitTorrent protocol"; + private static final int PROTO_STR_LEN = PROTO_STR.length(); + private static final int PROTO_LEN = PROTO_STR_LEN + 1; + private static final int[] PROTO = new int[PROTO_LEN]; + static { + PROTO[0] = PROTO_STR_LEN; + for (int i = 0; i < PROTO_STR_LEN; i++) { + PROTO[i+1] = PROTO_STR.charAt(i); + } + } + /** 48 */ - private static final int LOOKAHEAD_SIZE = 1 + // chr(19) - "BitTorrent protocol".length() + + private static final int LOOKAHEAD_SIZE = PROTO_LEN + 8 + // blank, reserved 20; // infohash /** - * Read ahead to the infohash, throwing an exception if there isn't enough data + * Read ahead to the infohash, throwing an exception if there isn't enough data. + * Also check the first 20 bytes for the correct protocol here and throw IOE if bad, + * so we don't hang waiting for 48 bytes if it's not a bittorrent client. + * The 20 bytes are checked again in Peer.handshake(). */ - private byte[] readHash(InputStream in) throws IOException { - byte buf[] = new byte[LOOKAHEAD_SIZE]; + private static byte[] readHash(InputStream in) throws IOException { + for (int i = 0; i < PROTO_LEN; i++) { + int b = in.read(); + if (b != PROTO[i]) + throw new IOException("Bad protocol 0x" + Integer.toHexString(b) + " at byte " + i); + } + if (in.skip(8) != 8) + throw new IOException("EOF before hash"); + byte buf[] = new byte[20]; int read = DataHelper.read(in, buf); if (read != buf.length) - throw new ProtocolException("Unable to read the hash (read " + read + ")"); - byte rv[] = new byte[20]; - System.arraycopy(buf, buf.length-rv.length, rv, 0, rv.length); - return rv; + throw new IOException("Unable to read the hash (read " + read + ")"); + return buf; } /** diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index abb7d1d7cd..45b6ef82ac 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -371,7 +371,9 @@ class PeerCoordinator implements PeerListener * @since 0.9.1 */ public boolean needOutboundPeers() { - return wantedBytes != 0 && needPeers(); + //return wantedBytes != 0 && needPeers(); + // minus one to make it a little easier for new peers to get in on large swarms + return wantedBytes != 0 && !halted && peers.size() < getMaxConnections() - 1; } /** diff --git a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java index d0e4ca8d9b..fdb6ff7632 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java +++ b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java @@ -298,7 +298,7 @@ public class TrackerClient extends I2PAppThread List ordered = new ArrayList(peers); Collections.shuffle(ordered, r); Iterator it = ordered.iterator(); - while ((!stop) && it.hasNext()) { + while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) { Peer cur = it.next(); // FIXME if id == us || dest == us continue; // only delay if we actually make an attempt to add peer @@ -351,7 +351,7 @@ public class TrackerClient extends I2PAppThread } Collections.shuffle(peers, r); Iterator it = peers.iterator(); - while ((!stop) && it.hasNext()) { + while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) { Peer cur = it.next(); if (coordinator.addPeer(cur) && it.hasNext()) { int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN; @@ -387,7 +387,7 @@ public class TrackerClient extends I2PAppThread } Collections.shuffle(peers, r); Iterator it = peers.iterator(); - while ((!stop) && it.hasNext()) { + while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) { Peer cur = it.next(); if (coordinator.addPeer(cur) && it.hasNext()) { int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN; diff --git a/history.txt b/history.txt index 94d50249f6..4c19f0f8e7 100644 --- a/history.txt +++ b/history.txt @@ -3,6 +3,10 @@ - Add per-hour conn limit - Blacklist peer after two bad handshakes - Reduce connect timeout + - Close connection immediately if bad protocol + - Stop adding peers when we hit the limit + - Lower limit for outbound connections so we give + new peers a better chance in large swarms 2012-05-30 zzz * Graphs: Reduce log EOF error to warn diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a6204817e3..f2522cd4ed 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 8; + public final static long BUILD = 9; /** for example "-test" */ public final static String EXTRA = "";