From b3e6b47cb6ba981fb03b5b70206e2ca61f4987f8 Mon Sep 17 00:00:00 2001 From: Rogiel Sulzbach Date: Sat, 7 Apr 2012 00:44:13 -0300 Subject: [PATCH] Implements peer's client matching using PeerID --- pom.xml | 21 +++++- src/main/java/com/torrent4j/TestMain.java | 4 +- .../java/com/torrent4j/model/TorrentPeer.java | 20 +++++- .../torrent4j/model/TorrentPeerClient.java | 45 +++++++++++++ .../com/torrent4j/model/TorrentPeerID.java | 67 +++++++++++++++++++ .../net/peerwire/PeerWireHandler.java | 47 ++++++++++--- .../net/peerwire/PeerWirePipelineFactory.java | 6 +- .../peerwire/messages/HandshakeMessage.java | 3 +- .../standard/StandardTorrentPeerStrategy.java | 8 ++- src/site/site.xml | 10 +++ 10 files changed, 211 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/torrent4j/model/TorrentPeerClient.java create mode 100644 src/main/java/com/torrent4j/model/TorrentPeerID.java create mode 100755 src/site/site.xml diff --git a/pom.xml b/pom.xml index 5f49efd..466ef02 100644 --- a/pom.xml +++ b/pom.xml @@ -94,6 +94,7 @@ src/main/assembly/distribution-bin.xml + false @@ -130,6 +131,10 @@ org.apache.maven.plugins maven-release-plugin 2.2.2 + + true + deploy site-deploy + @@ -183,7 +188,7 @@ site-maven-plugin 0.4 - Creating site for ${project.version} + Creating ${project.artifactId} site for ${project.version} torrent4j torrent4j.github.com @@ -203,6 +208,9 @@ torrent4j torrent4j + + ${project.build.directory}/${project.artifactId}-${project.version}.zip + @@ -264,6 +272,17 @@ commons-codec 20041127.091804 + + org.slf4j + slf4j-api + 1.6.2 + + + org.slf4j + slf4j-jdk14 + 1.6.2 + runtime + diff --git a/src/main/java/com/torrent4j/TestMain.java b/src/main/java/com/torrent4j/TestMain.java index aed251c..38fb94b 100644 --- a/src/main/java/com/torrent4j/TestMain.java +++ b/src/main/java/com/torrent4j/TestMain.java @@ -21,7 +21,7 @@ public class TestMain { new PeerWireProtocol(), new InMemoryTorrentStorage()); controller.start(1234); - final Torrent torrent = Torrent.load(Paths.get("music.torrent")); + final Torrent torrent = Torrent.load(Paths.get("test.torrent")); System.out.println("Torrent hash is " + torrent.getHash().getString()); // controller.checkExistingData(torrent); @@ -29,7 +29,7 @@ public class TestMain { controller.registerTorrent(torrent); final TorrentPeer peer = new TorrentPeer(torrent); peer.setAddress(new InetSocketAddress(Inet4Address - .getByName("192.168.1.100"), 21958)); + .getByName("127.0.0.1"), 34096)); torrent.getSwarm().addPeer(peer); while(true) { diff --git a/src/main/java/com/torrent4j/model/TorrentPeer.java b/src/main/java/com/torrent4j/model/TorrentPeer.java index 9e1f2c9..b924f82 100644 --- a/src/main/java/com/torrent4j/model/TorrentPeer.java +++ b/src/main/java/com/torrent4j/model/TorrentPeer.java @@ -27,7 +27,7 @@ public class TorrentPeer { /** * The peer ID */ - private String peerID; + private TorrentPeerID peerID; /** * The protocol peer used to communicate with it @@ -67,13 +67,27 @@ public class TorrentPeer { return pieces; } - public String getPeerID() { + public TorrentPeerID getPeerID() { return peerID; } - public void setPeerID(String peerID) { + public void setPeerID(TorrentPeerID peerID) { this.peerID = peerID; } + + public void setPeerID(String peerID) { + this.peerID = new TorrentPeerID(this, peerID); + } + + /** + * Tries to detect the peer's client. If unknown, {@link TorrentPeerClient#UNKNOWN} is + * returned. + * + * @return the peer torrent client + */ + public TorrentPeerClient getClient() { + return peerID.getClient(); + } public TorrentProtocolPeer getProtocolPeer() { return protocolPeer; diff --git a/src/main/java/com/torrent4j/model/TorrentPeerClient.java b/src/main/java/com/torrent4j/model/TorrentPeerClient.java new file mode 100644 index 0000000..ffd5728 --- /dev/null +++ b/src/main/java/com/torrent4j/model/TorrentPeerClient.java @@ -0,0 +1,45 @@ +package com.torrent4j.model; + +/** + * The list of known torrent clients + * + * @author Rogiel + */ +public enum TorrentPeerClient { + /** + * µTorrent for Mac (-UM) + */ + UTORRENT_FOR_MAC("µTorrent for Mac", "-UM"), + /** + * µTorrent (-UT) + */ + UTORRENT("µTorrent", "-UT"), + /** + * Transmission (-TR) + */ + TRANSMISSION("Transmission", "-TR"), + + UNKNOWN("Unknown", ""); + + /** + * An friendly name for the client. Can be used on an UI. + */ + public final String friendlyName; + /** + * The PeerID prefix for the client + */ + public final String prefix; + + /** + * Initializes a new enum value + * + * @param friendlyName + * an friendly name for the client + * @param prefix + * the PeerID prefix + */ + private TorrentPeerClient(String friendlyName, String prefix) { + this.friendlyName = friendlyName; + this.prefix = prefix; + } +} diff --git a/src/main/java/com/torrent4j/model/TorrentPeerID.java b/src/main/java/com/torrent4j/model/TorrentPeerID.java new file mode 100644 index 0000000..838286c --- /dev/null +++ b/src/main/java/com/torrent4j/model/TorrentPeerID.java @@ -0,0 +1,67 @@ +package com.torrent4j.model; + +/** + * This ID represents an PeerID on the BitTorrent network + * + * @author Rogiel + */ +public class TorrentPeerID { + /** + * The torrent peer + */ + private final TorrentPeer peer; + /** + * The underlying peer ID + */ + private final String peerID; + + /** + * Creates a new instance + * + * @param peer + * the peer + * @param peerID + * the peer ID + */ + public TorrentPeerID(TorrentPeer peer, String peerID) { + this.peer = peer; + this.peerID = peerID; + } + + /** + * @return the peerID + */ + public String getPeerID() { + return peerID; + } + + /** + * Tries to detect the peer's client. If unknown, {@link TorrentPeerClient#UNKNOWN} is + * returned. + * + * @return the peer torrent client + */ + public TorrentPeerClient getClient() { + for(TorrentPeerClient client : TorrentPeerClient.values()) { + if(client == TorrentPeerClient.UNKNOWN) + continue; + if(peerID.startsWith(client.prefix)) + return client; + } + return TorrentPeerClient.UNKNOWN; + } + + /** + * @return the peer + */ + public TorrentPeer getPeer() { + return peer; + } + + /** + * @return the torrent + */ + public Torrent getTorrent() { + return peer.getTorrent(); + } +} diff --git a/src/main/java/com/torrent4j/net/peerwire/PeerWireHandler.java b/src/main/java/com/torrent4j/net/peerwire/PeerWireHandler.java index 70a373f..cb1fc3d 100644 --- a/src/main/java/com/torrent4j/net/peerwire/PeerWireHandler.java +++ b/src/main/java/com/torrent4j/net/peerwire/PeerWireHandler.java @@ -71,14 +71,15 @@ public class PeerWireHandler extends SimpleChannelHandler { message.peerID); if (peer == null) { peer = new TorrentPeer(torrent); - peer.setPeerID(message.peerID); peer.setAddress((InetSocketAddress) e.getChannel() .getRemoteAddress()); } + peer.setPeerID(message.peerID); + this.peer = (PeerWireProtocolPeer) peer.getProtocolPeer(); - e.getChannel().getPipeline().get(PeerTrafficShapingHandler.class) - .setPeer(peer); + e.getChannel().getPipeline() + .get(PeerTrafficShapingHandler.class).setPeer(peer); e.getChannel().getPipeline() .get(TorrentTrafficShapingHandler.class) .setTorrent(torrent); @@ -87,6 +88,11 @@ public class PeerWireHandler extends SimpleChannelHandler { this.peer.getStrategy().getPeerStrategy() .peerConnected(torrent, peer); } else if (msg instanceof HaveMessage) { + peer.getTorrentPeer() + .getPieces() + .addPiece( + peer.getTorrent().getPiece( + ((HaveMessage) msg).pieceIndex)); peer.getStrategy() .getPeerStrategy() .havePiece( @@ -127,6 +133,11 @@ public class PeerWireHandler extends SimpleChannelHandler { message.pieceIndex); final TorrentPieceBlock block = piece.getBlock(message.begin, message.length); + + if(peer.getTorrentPeer().getState().hasUploadRequestedBlock()) { + peer.disconnect(); + return; + } peer.getTorrentPeer().getState().setUploadRequestedBlock(block); peer.getTorrentPeer().getState() @@ -233,8 +244,19 @@ public class PeerWireHandler extends SimpleChannelHandler { peer.getTorrentPeer().getState().setLastUploadedBlock(block); peer.getTorrentPeer().getState() .setLastUploadedBlockDate(new Date()); - peer.getTorrentPeer().getState().setUploadRequestedBlock(null); - peer.getTorrentPeer().getState().setUploadRequestedDate(null); + + e.getFuture().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) + throws Exception { + if (!future.isSuccess()) + return; + peer.getTorrentPeer().getState() + .setUploadRequestedBlock(null); + peer.getTorrentPeer().getState() + .setUploadRequestedDate(null); + } + }); } else if (msg instanceof RequestMessage) { final RequestMessage message = (RequestMessage) msg; @@ -248,9 +270,18 @@ public class PeerWireHandler extends SimpleChannelHandler { peer.getTorrentPeer().getState() .setDownloadRequestedDate(new Date()); } else if (msg instanceof CancelMessage) { - peer.getTorrentPeer().getState() - .setDownloadRequestedBlock(null); - peer.getTorrentPeer().getState().setDownloadRequestedDate(null); + e.getFuture().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) + throws Exception { + if (!future.isSuccess()) + return; + peer.getTorrentPeer().getState() + .setDownloadRequestedBlock(null); + peer.getTorrentPeer().getState() + .setDownloadRequestedDate(null); + } + }); } } finally { ctx.sendDownstream(e); diff --git a/src/main/java/com/torrent4j/net/peerwire/PeerWirePipelineFactory.java b/src/main/java/com/torrent4j/net/peerwire/PeerWirePipelineFactory.java index 06daa0e..9a9982e 100644 --- a/src/main/java/com/torrent4j/net/peerwire/PeerWirePipelineFactory.java +++ b/src/main/java/com/torrent4j/net/peerwire/PeerWirePipelineFactory.java @@ -3,6 +3,8 @@ package com.torrent4j.net.peerwire; import static io.netty.channel.Channels.pipeline; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; +import io.netty.handler.logging.LoggingHandler; +import io.netty.logging.InternalLogLevel; import java.util.concurrent.Executor; @@ -11,8 +13,8 @@ import com.torrent4j.net.peerwire.codec.PeerWireFrameDecoder; import com.torrent4j.net.peerwire.codec.PeerWireFrameEncoder; import com.torrent4j.net.peerwire.codec.PeerWireMessageDecoder; import com.torrent4j.net.peerwire.codec.PeerWireMessageEncoder; -import com.torrent4j.net.peerwire.traffic.TorrentTrafficShapingHandler; import com.torrent4j.net.peerwire.traffic.PeerTrafficShapingHandler; +import com.torrent4j.net.peerwire.traffic.TorrentTrafficShapingHandler; public class PeerWirePipelineFactory implements ChannelPipelineFactory { private final TorrentController controller; @@ -37,7 +39,7 @@ public class PeerWirePipelineFactory implements ChannelPipelineFactory { p.addLast("message-decoder", new PeerWireMessageDecoder()); p.addLast("message-encoder", new PeerWireMessageEncoder()); - // p.addLast("logging", new LoggingHandler(InternalLogLevel.WARN)); + p.addLast("logging", new LoggingHandler(InternalLogLevel.WARN)); p.addLast("handler", new PeerWireHandler(controller)); diff --git a/src/main/java/com/torrent4j/net/peerwire/messages/HandshakeMessage.java b/src/main/java/com/torrent4j/net/peerwire/messages/HandshakeMessage.java index 90bc33e..51ae041 100644 --- a/src/main/java/com/torrent4j/net/peerwire/messages/HandshakeMessage.java +++ b/src/main/java/com/torrent4j/net/peerwire/messages/HandshakeMessage.java @@ -2,6 +2,7 @@ package com.torrent4j.net.peerwire.messages; import io.netty.buffer.ChannelBuffer; +import java.nio.charset.Charset; import java.util.Arrays; import com.torrent4j.net.peerwire.PeerWireMessage; @@ -36,7 +37,7 @@ public class HandshakeMessage implements PeerWireMessage { protocolString = buffer.readBytes(protocolStringLength).toString(); reserved = buffer.readLong(); torrentHash = buffer.readBytes(20).array(); - peerID = buffer.readBytes(20).toString(); + peerID = buffer.readBytes(20).toString(Charset.forName("UTF-8")); } /* diff --git a/src/main/java/com/torrent4j/strategy/standard/StandardTorrentPeerStrategy.java b/src/main/java/com/torrent4j/strategy/standard/StandardTorrentPeerStrategy.java index 8ba3b53..ed4c241 100644 --- a/src/main/java/com/torrent4j/strategy/standard/StandardTorrentPeerStrategy.java +++ b/src/main/java/com/torrent4j/strategy/standard/StandardTorrentPeerStrategy.java @@ -42,9 +42,11 @@ public class StandardTorrentPeerStrategy implements TorrentPeerStrategy { return; if (peer.getState().hasDownloadRequestedBlock()) return; - if (peer.getState().isRemotellyChoked()) - return; - peer.requestBlock(piece.getFirstBlock()); + if (peer.getState().isRemotellyChoked()) { + peer.declareInterest(); + } else { + peer.requestBlock(piece.getFirstBlock()); + } } @Override diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100755 index 0000000..e0c6835 --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file