diff --git a/apps/i2psnark/java/src/org/klomp/snark/Message.java b/apps/i2psnark/java/src/org/klomp/snark/Message.java index a9d1e23f2..57fecf43d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Message.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Message.java @@ -53,6 +53,7 @@ class Message // Used for HAVE, REQUEST, PIECE and CANCEL messages. // low byte used for EXTENSION message + // low two bytes used for PORT message int piece; // Used for REQUEST, PIECE and CANCEL messages. @@ -107,6 +108,9 @@ class Message if (type == EXTENSION) datalen += 1; + if (type == PORT) + datalen += 2; + // add length of data for piece or bitfield array. if (type == BITFIELD || type == PIECE || type == EXTENSION) datalen += len; @@ -130,6 +134,9 @@ class Message if (type == EXTENSION) dos.writeByte((byte) piece & 0xff); + if (type == PORT) + dos.writeShort(piece & 0xffff); + // Send actual data if (type == BITFIELD || type == PIECE || type == EXTENSION) dos.write(data, off, len); diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java index ae053b8c8..f42adddef 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java @@ -72,7 +72,6 @@ public class Peer implements Comparable * relevant MetaInfo. */ public Peer(PeerID peerID, byte[] my_id, MetaInfo metainfo) - throws IOException { this.peerID = peerID; this.my_id = my_id; @@ -253,6 +252,13 @@ public class Peer implements Comparable out.sendExtension(0, ExtensionHandshake.getPayload()); } + if ((options & OPTION_DHT) != 0 && util.getDHT() != null) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Peer supports DHT, sending PORT message"); + int port = util.getDHT().getPort(); + out.sendPort(port); + } + // Send our bitmap if (bitfield != null) s.out.sendBitfield(bitfield); @@ -303,7 +309,8 @@ public class Peer implements Comparable dout.write(19); dout.write("BitTorrent protocol".getBytes("UTF-8")); // Handshake write - options - dout.writeLong(OPTION_EXTENSION); + // FIXME not if DHT disabled + dout.writeLong(OPTION_EXTENSION | OPTION_DHT); // Handshake write - metainfo hash byte[] shared_hash = metainfo.getInfoHash(); dout.write(shared_hash); @@ -343,7 +350,7 @@ public class Peer implements Comparable _log.debug("Read the remote side's hash and peerID fully from " + toString()); if (options != 0) { - // send them something + // send them something in runConnection() above if (_log.shouldLog(Log.DEBUG)) _log.debug("Peer supports options 0x" + Long.toString(options, 16) + ": " + toString()); } @@ -351,6 +358,11 @@ public class Peer implements Comparable return bs; } + /** @since 0.8.4 */ + public long getOptions() { + return options; + } + public boolean isConnected() { return state != null; diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java index 43bb9a712..90755a937 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java @@ -171,6 +171,11 @@ class PeerConnectionIn implements Runnable if (_log.shouldLog(Log.DEBUG)) _log.debug("Received cancel(" + piece + "," + begin + ") from " + peer + " on " + peer.metainfo.getName()); break; + case 9: // PORT message + int port = din.readUnsignedShort(); + ps.portMessage(port); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Received port message from " + peer + " on " + peer.metainfo.getName()); case 20: // Extension message int id = din.readUnsignedByte(); byte[] payload = new byte[i-2]; diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java index 38cb29e3b..19614bc52 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java @@ -547,4 +547,12 @@ class PeerConnectionOut implements Runnable m.len = bytes.length; addMessage(m); } + + /** @since 0.8.4 */ + void sendPort(int port) { + Message m = new Message(); + m.type = Message.PORT; + m.piece = port; + addMessage(m); + } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 034f74ae7..c9cdf6141 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -1086,6 +1086,12 @@ public class PeerCoordinator implements PeerListener } } + /** @since 0.8.4 */ + public void gotExtension(Peer peer, int id, byte[] bs) {} + + /** @since 0.8.4 */ + public void gotPort(Peer peer, int port) {} + /** Return number of allowed uploaders for this torrent. ** Check with Snark to see if we are over the total upload limit. */ diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerListener.java b/apps/i2psnark/java/src/org/klomp/snark/PeerListener.java index 975c12c10..6d9e681cb 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerListener.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerListener.java @@ -179,4 +179,23 @@ interface PeerListener * @since 0.8.2 */ PartialPiece getPartialPiece(Peer peer, BitField havePieces); + + /** + * Called when an extension message is received. + * + * @param peer the Peer that got the message. + * @param id the message ID + * @param bs the message payload + * @since 0.8.4 + */ + void gotExtension(Peer peer, int id, byte[] bs); + + /** + * Called when an extension message is received. + * + * @param peer the Peer that got the message. + * @param port the port + * @since 0.8.4 + */ + void gotPort(Peer peer, int port); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index 0c3c9eee8..ad70df9dc 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -32,9 +32,6 @@ import java.util.Set; import net.i2p.I2PAppContext; import net.i2p.util.Log; -import org.klomp.snark.bencode.BDecoder; -import org.klomp.snark.bencode.BEValue; - class PeerState implements DataLoader { private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class); @@ -485,22 +482,13 @@ class PeerState implements DataLoader /** @since 0.8.2 */ void extensionMessage(int id, byte[] bs) { - if (id == 0) { - InputStream is = new ByteArrayInputStream(bs); - try { - BDecoder dec = new BDecoder(is); - BEValue bev = dec.bdecodeMap(); - Map map = bev.getMap(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Got extension handshake message " + bev.toString()); - } catch (Exception e) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Failed extension decode", e); - } - } else { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Got extended message type: " + id + " length: " + bs.length); - } + listener.gotExtension(peer, id, bs); + } + + /** @since 0.8.4 */ + void portMessage(int port) + { + listener.gotPort(peer, port); } void unknownMessage(int type, byte[] bs)