* 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
This commit is contained in:
zzz
2012-05-31 15:20:50 +00:00
parent 041c87a2c9
commit 38a4f05000
6 changed files with 57 additions and 18 deletions

View File

@ -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) { }
}
}

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -298,7 +298,7 @@ public class TrackerClient extends I2PAppThread
List<Peer> ordered = new ArrayList(peers);
Collections.shuffle(ordered, r);
Iterator<Peer> 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<Peer> 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<Peer> 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;

View File

@ -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

View File

@ -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 = "";