diff --git a/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandshake.java b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandshake.java new file mode 100644 index 0000000000000000000000000000000000000000..fb69b044d284a7414f74b3e58a0b5773fd1c8419 --- /dev/null +++ b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandshake.java @@ -0,0 +1,36 @@ +package org.klomp.snark; + +import java.util.HashMap; +import java.util.Map; + +import org.klomp.snark.bencode.BEncoder; +import org.klomp.snark.bencode.BEValue; + +/** + * REF: BEP 10 Extension Protocol + * @since 0.8.2 + */ +class ExtensionHandshake { + + private static final byte[] _payload = buildPayload(); + + /** + * @return bencoded data + */ + static byte[] getPayload() { + return _payload; + } + + /** just a test for now */ + private static byte[] buildPayload() { + Map<String, Object> handshake = new HashMap(); + Map<String, Integer> m = new HashMap(); + m.put("foo", Integer.valueOf(99)); + m.put("bar", Integer.valueOf(101)); + handshake.put("m", m); + handshake.put("p", Integer.valueOf(6881)); + handshake.put("v", "I2PSnark"); + handshake.put("reqq", Integer.valueOf(5)); + return BEncoder.bencode(handshake); + } +} diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java index 257c5ff9a2c7d5fa8ac8f284dbb628b94eb6b3a3..d921f12e82b1f87e190b87e1f5ad0e88f3663be5 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java @@ -66,6 +66,7 @@ public class Peer implements Comparable private long options; /** + * Outgoing connection. * Creates a disconnected peer given a PeerID, your own id and the * relevant MetaInfo. */ @@ -80,6 +81,7 @@ public class Peer implements Comparable } /** + * Incoming connection. * Creates a unconnected peer from the input and output stream got * from the socket. Note that the complete handshake (which can take * some time or block indefinitely) is done in the calling Thread to @@ -201,6 +203,7 @@ public class Peer implements Comparable // Do we need to handshake? if (din == null) { + // Outgoing connection sock = util.connect(peerID); if (_log.shouldLog(Log.DEBUG)) _log.debug("Connected to " + peerID + ": " + sock); @@ -234,6 +237,7 @@ public class Peer implements Comparable + PeerID.idencode(expected_id) + "'"); } } else { + // Incoming connection if (_log.shouldLog(Log.DEBUG)) _log.debug("Already have din [" + sock + "] with " + toString()); } @@ -242,6 +246,12 @@ public class Peer implements Comparable PeerConnectionOut out = new PeerConnectionOut(this, dout); PeerState s = new PeerState(this, listener, metainfo, in, out); + if ((options & OPTION_EXTENSION) != 0) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Peer supports extensions, sending test message"); + out.sendExtension(0, ExtensionHandshake.getPayload()); + } + // Send our bitmap if (bitfield != null) s.out.sendBitfield(bitfield); @@ -331,12 +341,10 @@ public class Peer implements Comparable if (_log.shouldLog(Log.DEBUG)) _log.debug("Read the remote side's hash and peerID fully from " + toString()); -// if ((options & OPTION_EXTENSION) != 0) { if (options != 0) { // send them something if (_log.shouldLog(Log.DEBUG)) - //_log.debug("Peer supports extension message, what should we say? " + toString()); - _log.debug("Peer supports options 0x" + Long.toString(options, 16) + ", what should we say? " + toString()); + _log.debug("Peer supports options 0x" + Long.toString(options, 16) + ": " + toString()); } return bs; diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java index 289822df82495caa73dadad73b87f8fb0c051816..aa9cf2187db0d855dd306199125d939f710ef64d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java @@ -114,8 +114,9 @@ class PeerCheckerTask extends TimerTask // 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.nextBoolean()) || + ((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 2 : 4))) || (coordinator.overUpBWLimit(uploaded))); // If we are at our max uploaders and we have lots of other diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 12e291ea89b1c9d36a6e67cfd871eccf2fadbaa0..0967f24616646563c0f121583728c1c5dcf0a2fd 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -615,13 +615,13 @@ public class PeerCoordinator implements PeerListener // share blocks rather than starting from 0 with each peer. // This is where the flaws of the snark data model are really exposed. // Could also randomize within the duplicate set rather than strict rarest-first - if (_log.shouldLog(Log.DEBUG)) - _log.debug("parallel request (end game?) for " + peer + ": piece = " + piece); + if (_log.shouldLog(Log.INFO)) + _log.info("parallel request (end game?) for " + peer + ": piece = " + piece); } } if (record) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Now requesting: piece " + piece + " priority " + piece.getPriority()); + if (_log.shouldLog(Log.INFO)) + _log.info(peer + " is now requesting: piece " + piece + " priority " + piece.getPriority()); piece.setRequested(true); } return piece.getId(); @@ -945,11 +945,11 @@ public class PeerCoordinator implements PeerListener PartialPiece pp = iter.next(); int savedPiece = pp.getPiece(); if (havePieces.get(savedPiece)) { + iter.remove(); // this is just a double-check, it should be in there for(Piece piece : wantedPieces) { if (piece.getId() == savedPiece) { piece.setRequested(true); - iter.remove(); if (_log.shouldLog(Log.INFO)) { _log.info("Restoring orphaned partial piece " + pp + " Partial list size now: " + partialPieces.size()); @@ -957,8 +957,12 @@ public class PeerCoordinator implements PeerListener return pp; } } + if (_log.shouldLog(Log.WARN)) + _log.warn("Partial piece " + pp + " NOT in wantedPieces??"); } } + if (_log.shouldLog(Log.WARN) && !partialPieces.isEmpty()) + _log.warn("Peer " + peer + " has none of our partials " + partialPieces); } // ...and this section turns this into the general move-requests-around code! // Temporary? So PeerState never calls wantPiece() directly for now... @@ -1004,7 +1008,7 @@ public class PeerCoordinator implements PeerListener } } } - return wantPiece(peer, havePieces, false) > 0; + return wantPiece(peer, havePieces, false) >= 0; } /** diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index d32dc8ae52f171eed7e1960ba467152bf5df9226..38ed62029d88164a2e84d292ee920ea8f002f145 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -609,6 +609,9 @@ class PeerState implements DataLoader */ synchronized void addRequest() { + // no bitfield yet? nothing to request then. + if (bitfield == null) + return; boolean more_pieces = true; while (more_pieces) {