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