1
0
mirror of https://github.com/Rogiel/torrent4j synced 2025-12-05 23:22:49 +00:00

Fix tracker support and update maven build script

Fixed an issue with the tracker support in which it wansn't doing
requests correctly and not updating the swarm list. Also adds support
for assembling in maven. Now, each compilation will build generate an
zip, tar.gz and tar.bz2 files with dependencies, binary and javadoc
files.
This commit is contained in:
2011-09-14 23:59:50 -03:00
parent 13bba4246f
commit 6821fd3e0f
37 changed files with 907 additions and 178 deletions

View File

@@ -4,8 +4,8 @@
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
/target
/store.bin
/target
/logging.properties

View File

@@ -11,12 +11,13 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>

View File

@@ -1,3 +1,6 @@
#Thu Apr 28 01:49:42 BRT 2011
#Wed Sep 14 13:05:56 BRT 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View File

@@ -0,0 +1,5 @@
#Wed Sep 14 13:04:25 BRT 2011
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

66
pom.xml
View File

@@ -5,7 +5,7 @@
<artifactId>libtorrent</artifactId>
<packaging>jar</packaging>
<name>libtorrent</name>
<version>1.0.0-alpha2</version>
<version>1.0.0-alpha2.1</version>
<description>Java library used for downloading and uploading torrent files</description>
<url>http://code.google.com/p/libtorrent-java</url>
@@ -35,6 +35,11 @@
<version>3.2.4.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.2</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.jboss.netty</groupId> -->
<!-- <artifactId>netty</artifactId> -->
@@ -47,12 +52,18 @@
<artifactId>junit</artifactId>
<version>4.8.2</version>
<type>jar</type>
<scope>compile</scope>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.6.2</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<defaultGoal>package</defaultGoal>
<defaultGoal>assembly</defaultGoal>
<plugins>
<plugin>
@@ -68,6 +79,15 @@
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -97,30 +117,34 @@
</execution>
</executions>
</plugin>
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-clean-plugin</artifactId> -->
<!-- <version>2.4.1</version> -->
<!-- <executions> -->
<!-- <execution> -->
<!-- <id>clean</id> -->
<!-- <phase>package</phase> -->
<!-- <goals> -->
<!-- <goal>clean</goal> -->
<!-- </goals> -->
<!-- </execution> -->
<!-- </executions> -->
<!-- </plugin> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pdf-plugin</artifactId>
<version>1.1</version>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/assembly/distribution-bin.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>pdf</id>
<id>jar</id>
<phase>package</phase>
<goals>
<goal>pdf</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>clean</id>
<phase>package</phase>
<goals>
<goal>clean</goal>
<goal>assembly</goal>
</goals>
</execution>
</executions>

View File

@@ -0,0 +1,33 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<formats>
<format>tar.gz</format>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<baseDirectory></baseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
<include>${project.artifactId}-${project.version}-javadoc.jar</include>
</includes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/libs</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>false</unpack>
<scope>runtime</scope>
<excludes>
<exclude>net.bittorrent:libtorrent</exclude>
</excludes>
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -15,16 +15,24 @@
*/
package net.torrent;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.util.Timer;
import java.util.TimerTask;
import net.torrent.protocol.algorithm.TorrentAlgorithm;
import net.torrent.protocol.peerwire.PeerWireManager;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.protocol.tracker.HttpTorrentTrackerAnnouncer;
import net.torrent.torrent.context.TorrentContext;
import net.torrent.torrent.context.TorrentPeer;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is the main class used to controll your torrent transfer. It is not
* recommended to directly instantiate this class, instead use
@@ -33,6 +41,11 @@ import net.torrent.torrent.context.TorrentPeer;
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class BitTorrentClient implements Runnable {
/**
* The logger instance
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* Configuration of an BitTorrentClient.
*/
@@ -100,8 +113,21 @@ public class BitTorrentClient implements Runnable {
if (config.getListenPort() > 0)
peerWire.listen(config.getListenPort());
final HttpTorrentTrackerAnnouncer announcer = new HttpTorrentTrackerAnnouncer(
context.getSwarm());
try {
announcer.announce(context.getTorrent().getTrackers().iterator()
.next());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// run every 10 seconds - only 1 connection per turn
connectorTimer.schedule(new ConnectorTimerTask(), 0, 10 * 1000);
connectorTimer.schedule(new ConnectorTimerTask(), 0 * 1000, 2 * 1000);
if (addrs != null)
for (final InetSocketAddress addr : addrs) {
@@ -121,8 +147,17 @@ public class BitTorrentClient implements Runnable {
public void run() {
TorrentPeer peer = null;
while ((peer = algorithm.getPeerAlgorithm().connect()) != null) {
peerWire.connect(peer.getSocketAddress());
log.debug("Connecting to {}", peer);
try {
if (!peerWire.connect(peer.getSocketAddress()).await()
.isSuccess()) {
peer.setAccessible(false);
}
} catch (InterruptedException e) {
}
return;
}
log.debug("No new peers to connect");
}
}

View File

@@ -36,11 +36,18 @@ public class TorrentStdAlgorithm implements TorrentAlgorithm {
public TorrentStdAlgorithm(final TorrentManager manager,
final PieceSelector selector) {
peerAlgorithm = new TorrentStdPeerAlgorithm(manager);
interestAlgorithm = new TorrentStdInterestAlgorithm(manager, selector);
downloadAlgorithm = new TorrentStdPieceDownloadAlgorithm(manager,
final TorrentStdAlgorithmContext ctx = new TorrentStdAlgorithmContext();
peerAlgorithm = new TorrentStdPeerAlgorithm(manager, ctx);
interestAlgorithm = new TorrentStdInterestAlgorithm(manager, ctx, selector);
downloadAlgorithm = new TorrentStdPieceDownloadAlgorithm(manager, ctx,
selector);
uploadAlgorithm = new TorrentStdPieceUploadAlgorithm(manager);
uploadAlgorithm = new TorrentStdPieceUploadAlgorithm(manager, ctx);
}
protected class TorrentStdAlgorithmContext {
public int downloadingPieces = 0;
public int activeConnections = 0;
}
@Override

View File

@@ -16,23 +16,36 @@
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentInterestAlgorithm;
import net.torrent.protocol.algorithm.impl.TorrentStdAlgorithm.TorrentStdAlgorithmContext;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeer.ChokingState;
import net.torrent.torrent.context.TorrentPeer.InterestState;
import net.torrent.torrent.piece.PieceSelector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Standard torrent interest algorithm
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentStdInterestAlgorithm implements TorrentInterestAlgorithm {
/**
* The logger instance
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* The torrent manager
*/
@SuppressWarnings("unused")
private final TorrentManager manager;
/**
* The algorithm context
*/
private final TorrentStdAlgorithmContext context;
/**
* This selector is used to find the next piece to be downloaded. Parts are
@@ -49,21 +62,32 @@ public class TorrentStdInterestAlgorithm implements TorrentInterestAlgorithm {
* the piece selector
*/
public TorrentStdInterestAlgorithm(TorrentManager manager,
PieceSelector selector) {
TorrentStdAlgorithmContext context, PieceSelector selector) {
this.manager = manager;
this.context = context;
this.selector = selector;
}
@Override
public InterestState interested(TorrentPeer peer) {
log.debug("Checking interest in peer {}", peer);
if (context.downloadingPieces >= 10) {
log.debug("Already downloading 10 or more pieces, no interest in {}", peer);
return InterestState.UNINTERESTED;
}
int pieces = selector.countPieces(peer);
if (pieces >= 5)
if (pieces >= 5) {
log.debug("Peer {} has {} interesting pieces", peer, pieces);
return InterestState.INTERESTED;
}
log.debug("Peer {} does not have 5 or more pieces we dont have", peer);
return InterestState.INTERESTED;
}
@Override
public ChokingState choke(TorrentPeer peer) {
log.debug("Never choke peer {}", peer);
return ChokingState.UNCHOKED;
}
}

View File

@@ -16,6 +16,7 @@
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentPeerAlgorithm;
import net.torrent.protocol.algorithm.impl.TorrentStdAlgorithm.TorrentStdAlgorithmContext;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeer.ChokingState;
@@ -27,16 +28,23 @@ import net.torrent.torrent.context.TorrentPeer.InterestState;
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentStdPeerAlgorithm implements TorrentPeerAlgorithm {
@SuppressWarnings("unused")
private final TorrentManager manager;
/**
* The algorithm context
*/
private final TorrentStdAlgorithmContext context;
public TorrentStdPeerAlgorithm(TorrentManager manager) {
public TorrentStdPeerAlgorithm(TorrentManager manager,
TorrentStdAlgorithmContext context) {
this.manager = manager;
this.context = context;
}
@Override
public TorrentPeer connect() {
return null;
if (context.activeConnections >= 30)
return null;
return manager.getContext().getSwarm().getRandomPeer();
}
@Override

View File

@@ -19,6 +19,7 @@ import java.util.HashSet;
import java.util.Set;
import net.torrent.protocol.algorithm.TorrentPieceDownloadAlgorithm;
import net.torrent.protocol.algorithm.impl.TorrentStdAlgorithm.TorrentStdAlgorithmContext;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.TorrentPart;
import net.torrent.torrent.TorrentPiece;
@@ -39,6 +40,10 @@ public class TorrentStdPieceDownloadAlgorithm implements
* The torrent manager
*/
private final TorrentManager manager;
/**
* The algorithm context
*/
private final TorrentStdAlgorithmContext context;
/**
* This selector is used to find the next piece to be downloaded. Parts are
@@ -64,9 +69,10 @@ public class TorrentStdPieceDownloadAlgorithm implements
* @param selector
* the piece selector
*/
public TorrentStdPieceDownloadAlgorithm(TorrentManager manager,
public TorrentStdPieceDownloadAlgorithm(TorrentManager manager,TorrentStdAlgorithmContext context,
PieceSelector selector) {
this.manager = manager;
this.context = context;
this.selector = selector;
}

View File

@@ -16,6 +16,7 @@
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentPieceUploadAlgorithm;
import net.torrent.protocol.algorithm.impl.TorrentStdAlgorithm.TorrentStdAlgorithmContext;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.TorrentPart;
import net.torrent.torrent.context.TorrentPeer;
@@ -29,9 +30,15 @@ public class TorrentStdPieceUploadAlgorithm implements
TorrentPieceUploadAlgorithm {
@SuppressWarnings("unused")
private final TorrentManager manager;
/**
* The algorithm context
*/
private final TorrentStdAlgorithmContext context;
public TorrentStdPieceUploadAlgorithm(TorrentManager manager) {
public TorrentStdPieceUploadAlgorithm(TorrentManager manager,
TorrentStdAlgorithmContext context) {
this.manager = manager;
this.context = context;
}
@Override

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentAlgorithm;
import net.torrent.protocol.algorithm.TorrentInterestAlgorithm;
import net.torrent.protocol.algorithm.TorrentPeerAlgorithm;
import net.torrent.protocol.algorithm.TorrentPieceDownloadAlgorithm;
import net.torrent.protocol.algorithm.TorrentPieceUploadAlgorithm;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.piece.PieceSelector;
/**
* Standard torrent algorithm
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentTestAlgorithm implements TorrentAlgorithm {
private final TorrentPeerAlgorithm peerAlgorithm;
private final TorrentInterestAlgorithm interestAlgorithm;
private final TorrentPieceDownloadAlgorithm downloadAlgorithm;
private final TorrentPieceUploadAlgorithm uploadAlgorithm;
public TorrentTestAlgorithm(final TorrentManager manager,
final PieceSelector selector) {
peerAlgorithm = new TorrentTestPeerAlgorithm(manager);
interestAlgorithm = new TorrentTestInterestAlgorithm(manager, selector);
downloadAlgorithm = new TorrentTestPieceDownloadAlgorithm(manager,
selector);
uploadAlgorithm = new TorrentTestPieceUploadAlgorithm(manager);
}
@Override
public TorrentPeerAlgorithm getPeerAlgorithm() {
return peerAlgorithm;
}
@Override
public TorrentInterestAlgorithm getInterestAlgorithm() {
return interestAlgorithm;
}
@Override
public TorrentPieceDownloadAlgorithm getDownloadAlgorithm() {
return downloadAlgorithm;
}
@Override
public TorrentPieceUploadAlgorithm getUploadAlgorithm() {
return uploadAlgorithm;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentInterestAlgorithm;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeer.ChokingState;
import net.torrent.torrent.context.TorrentPeer.InterestState;
import net.torrent.torrent.piece.PieceSelector;
/**
* Standard torrent interest algorithm
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentTestInterestAlgorithm implements TorrentInterestAlgorithm {
/**
* The torrent manager
*/
@SuppressWarnings("unused")
private final TorrentManager manager;
/**
* This selector is used to find the next piece to be downloaded. Parts are
* managed inside this algorithm.
*/
private final PieceSelector selector;
/**
* Creates a new instance
*
* @param manager
* the manager
* @param selector
* the piece selector
*/
public TorrentTestInterestAlgorithm(TorrentManager manager,
PieceSelector selector) {
this.manager = manager;
this.selector = selector;
}
@Override
public InterestState interested(TorrentPeer peer) {
int pieces = selector.countPieces(peer);
if (pieces >= 5)
return InterestState.INTERESTED;
return InterestState.INTERESTED;
}
@Override
public ChokingState choke(TorrentPeer peer) {
return ChokingState.UNCHOKED;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentPeerAlgorithm;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeer.ChokingState;
import net.torrent.torrent.context.TorrentPeer.InterestState;
/**
* Standard torrent peer algorithm
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentTestPeerAlgorithm implements TorrentPeerAlgorithm {
@SuppressWarnings("unused")
private final TorrentManager manager;
public TorrentTestPeerAlgorithm(TorrentManager manager) {
this.manager = manager;
}
@Override
public TorrentPeer connect() {
return null;
}
@Override
public PeerDiscoveredAction discovered(TorrentPeer peer) {
return PeerDiscoveredAction.CONNECT;
}
@Override
public KeepAliveAction keepAlive(TorrentPeer peer) {
return KeepAliveAction.KEEP_ALIVE;
}
@Override
public ChokingState interested(TorrentPeer peer, InterestState interest) {
switch (interest) {
case INTERESTED:
return ChokingState.UNCHOKED;
case UNINTERESTED:
return ChokingState.CHOKED;
}
return null;
}
@Override
public PeerChokedAction choked(TorrentPeer peer, ChokingState state) {
switch (state) {
case CHOKED:
return PeerChokedAction.NONE;
case UNCHOKED:
return PeerChokedAction.DOWNLOAD;
}
return null;
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.torrent.protocol.algorithm.impl;
import java.util.HashSet;
import java.util.Set;
import net.torrent.protocol.algorithm.TorrentPieceDownloadAlgorithm;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.TorrentPart;
import net.torrent.torrent.TorrentPiece;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.piece.PieceSelector;
/**
* This standard implementation of {@link TorrentPieceDownloadAlgorithm} chooses
* a random missing piece and tries to download all the parts from the same
* peer, following the standard behavior of most of torrent clients.
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
// TODO separate standard algorithm from extension ones
public class TorrentTestPieceDownloadAlgorithm implements
TorrentPieceDownloadAlgorithm {
/**
* The torrent manager
*/
private final TorrentManager manager;
/**
* This selector is used to find the next piece to be downloaded. Parts are
* managed inside this algorithm.
*/
private final PieceSelector selector;
/**
* Maps all unchecked completed pieces. The piece is removed from the list
* once
* {@link TorrentPieceDownloadAlgorithm#isComplete(TorrentPeer, TorrentPiece)}
* is called.
*/
private Set<TorrentPiece> completedPieces = new HashSet<TorrentPiece>();
/**
* Creates a new instance of this algorithm.
*
* @param manager
* the torrent manager instance. With this object is possible to
* retrieve current downloads/uploads and connections.
* @param pieceSelector
* the piece selector
* @param selector
* the piece selector
*/
public TorrentTestPieceDownloadAlgorithm(TorrentManager manager,
PieceSelector selector) {
this.manager = manager;
this.selector = selector;
}
@Override
public TorrentPart getNextPart(TorrentPeer peer, TorrentPart part) {
if (part != null) {
if (part.isLast()) {
completedPieces.add(part.getPiece());
} else {
return part.getNextPart();
}
}
TorrentPiece piece = selector.select(peer);
if (piece == null)
// no piece, return null. The default handler will check, again, the
// interest on this peer.
return null;
return piece.getFirstPart();
}
@Override
public TorrentPart sugested(TorrentPeer peer, TorrentPiece piece) {
return piece.getFirstPart();
}
@Override
public TorrentPart allowedFast(TorrentPeer peer, TorrentPiece piece) {
return piece.getFirstPart();
}
@Override
public RejectAction rejected(TorrentPeer peer, TorrentPart part) {
return RejectAction.TRY_ANOTHER_PIECE;
}
@Override
public boolean isComplete(TorrentPeer peer, TorrentPiece piece) {
if (manager.getContext().getBitfield().hasPiece(piece))
return true;
// minimum overhead possible, will return true if was on list
return completedPieces.remove(piece);
}
@Override
public CorruptedAction corrupted(TorrentPeer peer, TorrentPiece piece) {
// TODO ban peer sending many corrupted pieces
return CorruptedAction.CANCEL;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.torrent.protocol.algorithm.impl;
import net.torrent.protocol.algorithm.TorrentPieceUploadAlgorithm;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.torrent.TorrentPart;
import net.torrent.torrent.context.TorrentPeer;
/**
* Standard torrent upload algorithm
*
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class TorrentTestPieceUploadAlgorithm implements
TorrentPieceUploadAlgorithm {
@SuppressWarnings("unused")
private final TorrentManager manager;
public TorrentTestPieceUploadAlgorithm(TorrentManager manager) {
this.manager = manager;
}
@Override
public RequestAction request(TorrentPeer peer, TorrentPart part) {
return RequestAction.NONE;
}
@Override
public boolean cancel(TorrentPeer peer, TorrentPart part) {
// TODO Auto-generated method stub
return false;
}
}

View File

@@ -44,6 +44,8 @@ import net.torrent.torrent.context.TorrentPeerCapabilities.TorrentPeerCapability
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An PeerWire Peer manages the {@link Channel channel} (the current peer
@@ -54,6 +56,11 @@ import org.jboss.netty.channel.ChannelFutureListener;
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class PeerWirePeer {
/**
* The logger instance
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* The active {@link Channel}
*/
@@ -109,11 +116,14 @@ public class PeerWirePeer {
public void choke() {
if (peer.getChokingState() == ChokingState.CHOKED)
return;
log.debug("Chocking peer {}", this);
write(new ChokeMessage()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
if (future.isSuccess()) {
log.debug("Chocked peer {}", this);
peer.setChokingState(ChokingState.CHOKED);
}
}
@@ -126,11 +136,14 @@ public class PeerWirePeer {
public void unchoke() {
if (peer.getChokingState() == ChokingState.UNCHOKED)
return;
log.debug("Unchocking peer {}", this);
write(new UnchokeMessage()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
if (future.isSuccess()) {
log.debug("Unchocked peer {}", this);
peer.setChokingState(ChokingState.UNCHOKED);
}
}
@@ -143,11 +156,14 @@ public class PeerWirePeer {
public void interested() {
if (peer.getInterestState() == InterestState.INTERESTED)
return;
log.debug("Informing interest in peer {}", this);
write(new InterestedMessage()).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
if (future.isSuccess()) {
log.debug("Interest informed to peer {}", this);
peer.setInterestState(InterestState.INTERESTED);
}
}
@@ -160,12 +176,15 @@ public class PeerWirePeer {
public void uninterested() {
if (peer.getInterestState() == InterestState.UNINTERESTED)
return;
log.debug("Informing no interest to peer {}", this);
write(new NotInterestedMessage()).addListener(
new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
if (future.isSuccess()) {
log.debug("No interest informed to peer {}", this);
peer.setInterestState(InterestState.UNINTERESTED);
}
}
@@ -184,6 +203,8 @@ public class PeerWirePeer {
* @return the {@link ChannelFuture} for this message
*/
public ChannelFuture request(int index, int start, int length) {
log.debug("Requesting piece {} part {} with {} length to peer {}",
new Object[] { index, start, length, peer });
return write(new RequestMessage(index, start, length));
}
@@ -201,6 +222,8 @@ public class PeerWirePeer {
*/
public void upload(int index, int start, int length, ByteBuffer data) {
this.unchoke();
log.debug("Sending piece {} part {} with {} length to {}, buffer: {}",
new Object[] { index, start, length, this, data });
write(new PieceMessage(index, start, length, data));
}
@@ -211,6 +234,7 @@ public class PeerWirePeer {
* the piece index
*/
public void have(int index) {
log.debug("Notifying have piece {} to peer {}", index, this);
write(new HaveMessage(index));
}
@@ -225,6 +249,9 @@ public class PeerWirePeer {
* the length
*/
public void cancel(int index, int start, int length) {
log.debug(
"Cancelling piece {} reuquest, part {} with {} length from peer {}",
new Object[] { index, start, length, this });
write(new CancelMessage(index, start, length));
}
@@ -232,6 +259,7 @@ public class PeerWirePeer {
* Send an keep alive message
*/
public void keepAlive() {
log.debug("Keeping alive peer {}", this);
write(new KeepAliveMessage());
}
@@ -246,6 +274,7 @@ public class PeerWirePeer {
* the port number
*/
public void port(short port) {
log.debug("Sending DHT port {} to peer {}", port, this);
write(new PortMessage(port));
}
@@ -256,6 +285,7 @@ public class PeerWirePeer {
* Send an have none message.
*/
public void haveNone() {
log.debug("Sendind NO-PIECES message to peer {}", this);
write(new HaveNoneMessage());
}
@@ -266,6 +296,7 @@ public class PeerWirePeer {
* Send an have all message.
*/
public void haveAll() {
log.debug("Sending HAVE-ALL message to peer {}", this);
write(new HaveAllMessage());
}
@@ -284,6 +315,9 @@ public class PeerWirePeer {
*/
public void reject(int index, int start, int length) {
this.choke();
log.debug(
"Rejecting part {}, starting at {} with {] length from peer {}",
new Object[] { index, start, length, this });
write(new RejectMessage(index, start, length));
}
@@ -297,6 +331,7 @@ public class PeerWirePeer {
* the piece index
*/
public void suggest(int index) {
log.debug("Suggesting piece {} to peer {}", index, this);
write(new SuggestPieceMessage(index));
}
@@ -311,6 +346,7 @@ public class PeerWirePeer {
* the piece indexes
*/
public void allowedFast(int... indexes) {
log.debug("Allowing {} fast pieces to peer {}", indexes.length, this);
write(new AllowedFastMessage(indexes));
}
@@ -355,6 +391,16 @@ public class PeerWirePeer {
return channel;
}
/**
* @return
* @see org.jboss.netty.channel.Channel#isOpen()
*/
public boolean isConnected() {
if (channel == null)
return false;
return channel.isOpen();
}
/**
* Get the active {@link TorrentPeer}
*

View File

@@ -55,6 +55,8 @@ import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Standard handler responsible for forwarding calls to {@link TorrentAlgorithm}
@@ -69,6 +71,11 @@ import org.jboss.netty.handler.timeout.IdleStateEvent;
*/
// TODO separate extensions handler from algorithm handler
public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
/**
* The logger instance
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* The torrent manager
*/
@@ -223,9 +230,11 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
private void testInterest(PeerWirePeer peer) {
switch (interestAlgorithm.interested(peer.getTorrentPeer())) {
case INTERESTED:
log.debug("Algorithm is interested in peer {}", peer);
peer.interested();
return;
case UNINTERESTED:
log.debug("Algorithm is not interested in peer {}", peer);
peer.uninterested();
return;
}
@@ -240,9 +249,11 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
private void testChoke(PeerWirePeer peer) {
switch (interestAlgorithm.choke(peer.getTorrentPeer())) {
case CHOKED:
log.debug("Algorithm wants to choke peer {}", peer);
peer.choke();
return;
case UNCHOKED:
log.debug("Algorithm wants to unchoke peer {}", peer);
peer.unchoke();
return;
}
@@ -257,12 +268,14 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
* the new interest state
*/
private void peerIntrestUpdate(PeerWirePeer peer, InterestState state) {
log.debug("Peer {} has updated interest state to {}", peer, state);
switch (peerAlgorithm.interested(peer.getTorrentPeer(), state)) {
case CHOKED:
log.debug("Algorithm wants to choke peer {}", peer);
peer.choke();
return;
case UNCHOKED:
log.debug("Algorithm wants to unchoke peer {}", peer);
peer.unchoke();
return;
}
@@ -277,17 +290,22 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
* the choke state
*/
private void peerChokeUpdate(PeerWirePeer peer, ChokingState state) {
log.debug("Peer {} has updated choke state to {}", peer, state);
switch (peerAlgorithm.choked(peer.getTorrentPeer(), state)) {
case DISCONNECT:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
break;
case CONNECT_NEW_PEER:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
log.debug("Algorithm wants connect to a new peer");
connect(peerAlgorithm.connect());
return;
case DOWNLOAD:
log.debug("Algorithm wants to download a piece from peer {}", peer);
download(peer,
downloadAlgorithm.getNextPart(peer.getTorrentPeer(), null));
return;
@@ -305,25 +323,34 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
*/
private void processRequest(PeerWirePeer peer, TorrentPart part)
throws IOException {
log.debug("Peer {} has requested {}", peer, part);
switch (uploadAlgorithm.request(peer.getTorrentPeer(), part)) {
case DISCONNECT:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
break;
case REJECT:
log.debug("Algorithm wants to reject part {} from peer {}", part, peer);
if (!peer.getTorrentPeer().getCapabilities()
.supports(TorrentPeerCapability.FAST_PEERS))
.supports(TorrentPeerCapability.FAST_PEERS)) {
log.debug("Peer {} do not support rejecting part {}, ignoring request", peer, part);
return;
}
peer.reject(part.getPiece().getIndex(), part.getStart(),
part.getLength());
break;
case CONNECT_NEW_PEER:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
log.debug("Algorithm wants connect to a new peer");
connect(peerAlgorithm.connect());
break;
case CHOKE:
log.debug("Algorithm wants to choke peer {}", peer);
peer.choke();
break;
case UPLOAD:
log.debug("Algorithm wants to upload part {} to peer {}", part, peer);
upload(peer, part);
break;
}
@@ -342,8 +369,11 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
*/
private void processDownload(final PeerWirePeer peer,
final TorrentPart part, ByteBuffer data) throws IOException {
log.debug("Received part {} from peer {}", part, peer);
final TorrentPart nextPart = downloadAlgorithm.getNextPart(
peer.getTorrentPeer(), part);
log.debug("Next part from peer {} is {}", peer, nextPart);
boolean complete = downloadAlgorithm.isComplete(peer.getTorrentPeer(),
part.getPiece());
final ChannelFuture future = download(peer, nextPart);
@@ -353,36 +383,47 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
return;
if (!complete)
return;
log.debug("Piece {} is complete, calculating check sum", part.getPiece());
if (datastore.checksum(part.getPiece())) {
manager.getContext().getBitfield().setPiece(part.getPiece(), true);
manager.getPeerManager().executeActive(new PeerWirePeerCallback() {
@Override
public void callback(PeerWirePeer peer) {
log.debug("Broadcasting HAVE {} message to all peers", part.getPiece());
peer.have(part.getPiece().getIndex());
}
});
} else {
System.exit(0);
log.debug("Checksum for piece {} is not valid", part.getPiece());
manager.getContext().getBitfield().setPiece(part.getPiece(), false);
switch (downloadAlgorithm.corrupted(peer.getTorrentPeer(),
part.getPiece())) {
case CHOKE:
if (future != null && !future.cancel())
log.debug("Algorithm wants to choke peer {}", peer);
if (future != null && !future.cancel()) {
log.debug("Canceling part {} request from peer {}", nextPart, peer);
peer.cancel(nextPart.getPiece().getIndex(),
nextPart.getStart(), nextPart.getLength());
}
peer.choke();
break;
case DISCONNECT:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
break;
case CONNECT_NEW_PEER:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
log.debug("Algorithm wants connect to a new peer");
connect(peerAlgorithm.connect());
break;
return;
case CONTINUE:
log.debug("Algorithm wants to continue downloads from peer {}", peer);
break;
case CANCEL:
log.debug("Algorithms wants to cancel part {} request from peer {}", nextPart, peer);
if (future != null && !future.cancel())
peer.cancel(nextPart.getPiece().getIndex(),
nextPart.getStart(), nextPart.getLength());
@@ -398,15 +439,21 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
* the peer
*/
private void keepAlive(PeerWirePeer peer) {
log.debug("Peer {} is keeping alive", peer);
switch (peerAlgorithm.keepAlive(peer.getTorrentPeer())) {
case DISCONNECT:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
break;
case CONNECT_NEW_PEER:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
log.debug("Algorithm wants connect to a new peer");
connect(peerAlgorithm.connect());
break;
return;
case KEEP_ALIVE:
log.debug("Algorithm wants to keep alive peer {}", peer);
peer.keepAlive();
break;
}
@@ -493,23 +540,31 @@ public class PeerWireAlgorithmHandler extends IdleStateAwareChannelHandler {
}
private void rejected(PeerWirePeer peer, TorrentPart part) {
log.debug("Peer {} rejected part request {}", peer, part);
switch (downloadAlgorithm.rejected(peer.getTorrentPeer(), part)) {
case DISCONNECT:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
break;
case CONNECT_NEW_PEER:
log.debug("Algorithm wants to diconnect peer {}", peer);
peer.disconnect();
log.debug("Algorithm wants connect to a new peer");
connect(peerAlgorithm.connect());
break;
return;
case NOT_INTERESTED:
log.debug("Algorithm has no interest in peer {}", peer);
peer.uninterested();
break;
case RETRY:
log.debug("Algorithm wants to retry request for part {} from peer {}", part, peer);
download(peer, part);
break;
case TRY_ANOTHER_PIECE:
final TorrentPart nextPart = downloadAlgorithm.getNextPart(
peer.getTorrentPeer(), part);
log.debug("Algorithm wants to try another part request {} from peer {}", nextPart, peer);
download(peer, nextPart);
break;
}

View File

@@ -21,7 +21,6 @@ import net.torrent.protocol.peerwire.PeerWirePeer;
import net.torrent.protocol.peerwire.manager.TorrentManager;
import net.torrent.protocol.peerwire.message.HandshakeMessage;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeerCapabilities.TorrentPeerCapability;
import net.torrent.torrent.context.TorrentPeerID;
import org.jboss.netty.channel.Channel;
@@ -29,6 +28,8 @@ import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handles pre-algoritihm handler stuff.
@@ -38,6 +39,11 @@ import org.jboss.netty.channel.SimpleChannelHandler;
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class PeerWireManagerHeadHandler extends SimpleChannelHandler {
/**
* The logger instance
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* The torrent manager
*/
@@ -88,14 +94,16 @@ public class PeerWireManagerHeadHandler extends SimpleChannelHandler {
peer.setSocketAddress((InetSocketAddress) channel
.getRemoteAddress());
peer.getCapabilities().setCapabilities(handshake.getReserved());
log.debug("Handshaked with peer {}", pwpeer);
// TODO send bitfield
if (peer.getCapabilities().supports(
TorrentPeerCapability.FAST_PEERS)) {
pwpeer.haveAll();
} else {
// pwpeer.bitfield(manager.getContext().getBitfield().getBits());
}
// if (peer.getCapabilities().supports(
// TorrentPeerCapability.FAST_PEERS)) {
// //pwpeer.haveAll();
// } else {
pwpeer.bitfield(manager.getContext().getBitfield().getBits());
// }
}
super.messageReceived(ctx, e);
}

View File

@@ -30,6 +30,8 @@ import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handles post-algorithm handler stuff.
@@ -39,6 +41,11 @@ import org.jboss.netty.channel.SimpleChannelHandler;
* @author <a href="http://www.rogiel.com/">Rogiel Josias Sulzbach</a>
*/
public class PeerWireManagerTailHandler extends SimpleChannelHandler {
/**
* The logger instance
*/
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* The torrent manager
*/
@@ -64,12 +71,18 @@ public class PeerWireManagerTailHandler extends SimpleChannelHandler {
final Torrent torrent = manager.getTorrent();
final TorrentPart part = torrent.getPart(pieceMsg.getIndex(),
pieceMsg.getStart(), pieceMsg.getLength());
log.debug("Removing {} from download queue", part);
manager.getDownloadManager().remove(part);
} else if (msg instanceof RejectMessage) {
final RejectMessage reject = (RejectMessage) msg;
final Torrent torrent = manager.getTorrent();
final TorrentPart part = torrent.getPart(reject.getIndex(),
reject.getStart(), reject.getLength());
log.debug("Removing {} from download queue", part);
manager.getDownloadManager().remove(part);
}
super.messageReceived(ctx, e);
@@ -87,11 +100,15 @@ public class PeerWireManagerTailHandler extends SimpleChannelHandler {
final Torrent torrent = manager.getContext().getTorrent();
final TorrentPart part = torrent.getPart(message.getIndex(),
message.getStart(), message.getLength());
log.debug("Adding {} to upload queue", part);
manager.getUploadManager().add(part, peer.getTorrentPeer());
e.getFuture().addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
log.debug("Removing {} from upload queue", part);
manager.getUploadManager().remove(part);
}
});
@@ -100,6 +117,9 @@ public class PeerWireManagerTailHandler extends SimpleChannelHandler {
final Torrent torrent = manager.getContext().getTorrent();
final TorrentPart part = torrent.getPart(message.getIndex(),
message.getStart(), message.getLength());
log.debug("Adding {} to download queue", part);
manager.getDownloadManager().add(part, peer.getTorrentPeer());
} else if (msg instanceof CancelMessage) {
final CancelMessage message = (CancelMessage) msg;
@@ -110,6 +130,7 @@ public class PeerWireManagerTailHandler extends SimpleChannelHandler {
@Override
public void operationComplete(ChannelFuture future)
throws Exception {
log.debug("Removing {} from download queue", part);
manager.getDownloadManager().remove(part);
}
});
@@ -124,7 +145,9 @@ public class PeerWireManagerTailHandler extends SimpleChannelHandler {
final PeerWirePeer peer = manager.getPeerManager().update(
e.getChannel());
if (peer.getTorrentPeer() != null) {
log.debug("Removing all peer {} pieces from download queue", peer);
manager.getDownloadManager().remove(peer.getTorrentPeer());
log.debug("Removing all peer {} pieces from upload queue", peer);
manager.getUploadManager().remove(peer.getTorrentPeer());
}
super.channelDisconnected(ctx, e);
@@ -137,7 +160,9 @@ public class PeerWireManagerTailHandler extends SimpleChannelHandler {
final PeerWirePeer peer = manager.getPeerManager().remove(
e.getChannel());
if (peer.getTorrentPeer() != null) {
log.debug("Removing all peer {} pieces from download queue", peer);
manager.getDownloadManager().remove(peer.getTorrentPeer());
log.debug("Removing all peer {} pieces from upload queue", peer);
manager.getUploadManager().remove(peer.getTorrentPeer());
}
super.channelClosed(ctx, e);

View File

@@ -65,19 +65,15 @@ public class BitfieldMessage implements PeerWireWritableMessage,
@Override
public void read(ChannelBuffer buffer) throws IOException {
buffer.readerIndex(buffer.readerIndex() - 5);
int len = buffer.readInt() - 2;
buffer.readByte(); // unk
bitfield = new BitSet(len * 8);
bitfield = new BitSet(8);
int i = 0;
int read = 0;
while (read <= len) {
while (buffer.readable()) {
byte b = buffer.readByte();
for (int j = 128; j > 0; j >>= 1) {
bitfield.set(i++, (b & j) != 0);
}
read++;
}
}

View File

@@ -25,6 +25,7 @@ import net.torrent.protocol.tracker.message.AnnounceMessage;
import net.torrent.protocol.tracker.message.AnnounceMessage.Event;
import net.torrent.torrent.Torrent;
import net.torrent.torrent.TorrentTracker;
import net.torrent.torrent.context.TorrentSwarm;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFuture;
@@ -35,16 +36,21 @@ public class HttpTorrentTrackerAnnouncer {
new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
public HttpTorrentTrackerAnnouncer() {
client.setPipelineFactory(new HttpTorrentTrackerPipelineFactory());
private final TorrentSwarm swarm;
private final Torrent torrent;
public HttpTorrentTrackerAnnouncer(TorrentSwarm swarm) {
this.swarm = swarm;
this.torrent = swarm.getContext().getTorrent();
client.setPipelineFactory(new HttpTorrentTrackerPipelineFactory(swarm));
}
public boolean announce(Torrent torrent, TorrentTracker tracker)
public boolean announce(TorrentTracker tracker)
throws UnsupportedEncodingException, MalformedURLException {
final AnnounceMessage announceMessage = new AnnounceMessage(tracker
.getURL().toString(), torrent.getInfoHash().toByteArray(),
torrent.getInfoHash().toByteArray(), 10, 0, 0, 0, true, false,
Event.STARTED);
torrent.getInfoHash().toByteArray(), 10254, 0, 0, 0, true,
false, Event.STARTED);
int port = (tracker.getURL().getPort() > 0 ? tracker.getURL().getPort()
: tracker.getURL().getDefaultPort());
final ChannelFuture chFuture = client.connect(new InetSocketAddress(

View File

@@ -16,38 +16,49 @@
package net.torrent.protocol.tracker;
import static org.jboss.netty.channel.Channels.pipeline;
import net.torrent.protocol.tracker.codec.ISO8859HttpRequestEncoder;
import net.torrent.protocol.tracker.codec.TorrentTrackerBDecoder;
import net.torrent.protocol.tracker.codec.TorrentTrackerDecoder;
import net.torrent.protocol.tracker.codec.TorrentTrackerEncoder;
import net.torrent.torrent.context.TorrentSwarm;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpRequestEncoder;
import org.jboss.netty.handler.codec.http.HttpResponseDecoder;
import org.jboss.netty.handler.logging.LoggingHandler;
import org.jboss.netty.logging.InternalLogLevel;
public class HttpTorrentTrackerPipelineFactory implements
ChannelPipelineFactory {
private final TorrentSwarm swarm;
/**
* @param torrent
*/
public HttpTorrentTrackerPipelineFactory(TorrentSwarm swarm) {
this.swarm = swarm;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
final ChannelPipeline pipeline = pipeline();
// log binary data input and object output
// pipeline.addFirst("logging", new LoggingHandler());
pipeline.addFirst("logging-start", new LoggingHandler(
InternalLogLevel.INFO));
pipeline.addLast("tracker.encoder", new TorrentTrackerEncoder());
pipeline.addLast("encoder", new ISO8859HttpRequestEncoder());
pipeline.addLast("http.encoder", new HttpRequestEncoder());
pipeline.addLast("interceptor", new Interceptor());
pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("http.decoder", new HttpResponseDecoder());
pipeline.addLast("bdecoder", new TorrentTrackerBDecoder());
pipeline.addLast("tracker.decoder", new TorrentTrackerDecoder());
pipeline.addLast("handler", new TrackerHandler());
pipeline.addLast("handler", new TrackerHandler(swarm));
pipeline.addLast("logging", new LoggingHandler(InternalLogLevel.WARN));
pipeline.addLast("logging", new LoggingHandler(InternalLogLevel.INFO));
return pipeline;
}

View File

@@ -15,15 +15,43 @@
*/
package net.torrent.protocol.tracker;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import net.torrent.protocol.tracker.message.PeerListMessage;
import net.torrent.protocol.tracker.message.PeerListMessage.PeerInfo;
import net.torrent.torrent.context.TorrentPeer;
import net.torrent.torrent.context.TorrentPeerID;
import net.torrent.torrent.context.TorrentSwarm;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.SimpleChannelHandler;
public class TrackerHandler extends SimpleChannelHandler {
private final TorrentSwarm swarm;
/**
* @param torrent
*/
public TrackerHandler(TorrentSwarm swarm) {
this.swarm = swarm;
}
public class TrackerHandler extends SimpleChannelUpstreamHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
System.out.println(e.getMessage());
if (e.getMessage() instanceof PeerListMessage) {
final PeerListMessage message = (PeerListMessage) e.getMessage();
for (final PeerInfo peerInfo : message.getPeerList()) {
final TorrentPeer peer = new TorrentPeer(swarm.getContext(),
TorrentPeerID.create(peerInfo.getPeerId()),
new InetSocketAddress(Inet4Address.getByName(peerInfo
.getIp()), peerInfo.getPort()));
swarm.add(peer);
}
}
super.messageReceived(ctx, e);
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.torrent.protocol.tracker.codec;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.handler.codec.http.HttpMessage;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpRequestEncoder;
public class ISO8859HttpRequestEncoder extends HttpRequestEncoder {
static final byte SP = 32;
static final byte CR = 13;
static final byte LF = 10;
@Override
protected void encodeInitialLine(ChannelBuffer buf, HttpMessage message)
throws Exception {
HttpRequest request = (HttpRequest) message;
buf.writeBytes(request.getMethod().toString().getBytes());
buf.writeByte(SP);
buf.writeBytes(request.getUri().getBytes());
buf.writeByte(SP);
buf.writeBytes(request.getProtocolVersion().toString().getBytes());
buf.writeByte(CR);
buf.writeByte(LF);
}
}

View File

@@ -22,18 +22,17 @@ import net.torrent.util.bencoding.BMap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.http.HttpChunk;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
public class TorrentTrackerBDecoder extends OneToOneDecoder {
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel,
Object msg) throws Exception {
if (!(msg instanceof HttpChunk))
if (!(msg instanceof DefaultHttpResponse))
return msg;
final HttpChunk message = (HttpChunk) msg;
final DefaultHttpResponse message = (DefaultHttpResponse) msg;
System.out.println(new String(message.getContent().array()));
if (message.getContent().readableBytes() <= 0)
return null;

View File

@@ -57,7 +57,7 @@ public class AnnounceMessage implements TorrentTrackerRequestMessage {
}
private String ip;
private Integer numWant = 10;
private Integer numWant = 100;
private String key = "avtbyit8";
private String trackerId;
@@ -114,19 +114,20 @@ public class AnnounceMessage implements TorrentTrackerRequestMessage {
add(builder, "downloaded", Long.toString(downloaded));
add(builder, "left", Long.toString(left));
add(builder, "compact", compact);
add(builder, "no_peer_id", noPeerId);
//add(builder, "compact", compact);
//add(builder, "no_peer_id", noPeerId);
if (event != Event.UPDATE)
add(builder, "event", event.urlArg());
add(builder, "ip", ip);
add(builder, "numwant", numWant);
add(builder, "key", key);
add(builder, "trackerid", trackerId);
//add(builder, "key", key);
//add(builder, "trackerid", trackerId);
builder.setLength(builder.length() - 1);// trim last character it is an
// unnecessary &.
final URL url = new URL(builder.toString());
System.out.println(builder.toString());
return new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
url.getPath() + "?" + url.getQuery());
@@ -136,25 +137,21 @@ public class AnnounceMessage implements TorrentTrackerRequestMessage {
throws UnsupportedEncodingException {
if (value == null)
return;
builder.append(key + "=" + value).append("&");
builder.append(key + "=" + URLEncoder.encode(value, "ISO-8859-1").replace("*", "%2a")).append("&");
}
private void add(StringBuilder builder, String key, byte[] value)
throws UnsupportedEncodingException {
if (value == null)
return;
add(builder, key, URLEncoder.encode(new String(value), "ISO-8859-1")
.replaceAll("\\+", "%20"));
add(builder, key, new String(value, "ISO-8859-1"));
}
private void addLowerCase(StringBuilder builder, String key, byte[] value)
throws UnsupportedEncodingException {
if (value == null)
return;
add(builder, key,
URLEncoder
.encode(new String(value, "ISO-8859-1"), "ISO-8859-1")
.replaceAll("\\+", "%20").toLowerCase());
add(builder, key, new String(value, "ISO-8859-1"));
}
private void add(StringBuilder builder, String key, Number value)

View File

@@ -159,7 +159,7 @@ public class PeerListMessage implements TorrentTrackerResponseMessage {
public static PeerInfo fromBMap(BMap map) throws BTypeException {
return new PeerInfo((byte[]) map.get("peer id"),
map.getString("peer ip"), map.getInteger("port"));
map.getString("ip"), map.getInteger("port"));
}
public static PeerInfo fromRawIP(byte[] list, int i, int j) {

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.Collections;
@@ -340,8 +341,12 @@ public class Torrent {
if (in == null)
throw new InvalidParameterException("InputStream cannot be null");
final BMap map = (BMap) new BEncodedInputStream(in).readElement();
return new Torrent(map);
try {
final BMap map = (BMap) new BEncodedInputStream(in).readElement();
return new Torrent(map);
} finally {
in.close();
}
}
/**
@@ -359,4 +364,19 @@ public class Torrent {
throw new InvalidParameterException("File cannot be null");
return load(new FileInputStream(file));
}
/**
* Load an torrent from an {@link File}
*
* @param url
* the {@link URL}
* @return the loaded {@link Torrent} instance
* @throws IOException
* @throws URISyntaxException
*/
public static Torrent load(URL url) throws IOException, URISyntaxException {
if (url == null)
throw new InvalidParameterException("File cannot be null");
return load(url.openStream());
}
}

View File

@@ -18,6 +18,8 @@ package net.torrent.torrent.context;
import java.net.InetSocketAddress;
import java.util.Date;
import net.torrent.protocol.peerwire.PeerWirePeer;
/**
* Object representing a peer in the swarm.
*
@@ -118,6 +120,8 @@ public class TorrentPeer {
*/
private boolean accessible = true;
private PeerWirePeer peerWirePeer;
/**
* Creates a new peer
*
@@ -313,6 +317,28 @@ public class TorrentPeer {
this.accessible = accessible;
}
/**
* @return the peerWirePeer
*/
public PeerWirePeer getPeerWirePeer() {
return peerWirePeer;
}
/**
* @param peerWirePeer the peerWirePeer to set
*/
public void setPeerWirePeer(PeerWirePeer peerWirePeer) {
this.peerWirePeer = peerWirePeer;
}
public boolean isConnected() {
if(this.peerWirePeer == null)
return false;
return true;
}
/**
* Get the torrent context
*

View File

@@ -61,6 +61,17 @@ public class TorrentSwarm implements Iterable<TorrentPeer> {
return this.peers.add(peer);
}
/**
* Add an given peers to the swarm
*
* @param peers
* the peers
* @return true if was not present in swarm
*/
public boolean add(List<TorrentPeer> peers) {
return this.peers.addAll(peers);
}
/**
* Removes an given peer from the swarm
*
@@ -131,6 +142,44 @@ public class TorrentSwarm implements Iterable<TorrentPeer> {
return null;
}
/**
* Get an peer by its address
*
* @return an random peer
*/
public TorrentPeer getRandomPeer() {
if (peers.size() == 0)
return null;
return peers.get((int) (Math.random() * (peers.size() - 1)));
}
/**
* Get an peer by its address
*
* @return an random peer
*/
public TorrentPeer getRandomOfflinePeer() {
List<TorrentPeer> accessiblePeers = new ArrayList<TorrentPeer>();
List<TorrentPeer> nonAccessiblePeers = new ArrayList<TorrentPeer>();
for (final TorrentPeer peer : peers) {
if (peer.isConnected()) {
if (peer.isAccessible()) {
accessiblePeers.add(peer);
} else {
nonAccessiblePeers.add(peer);
}
}
}
List<TorrentPeer> peerList = accessiblePeers;
if (peerList.size() == 0)
peerList = nonAccessiblePeers;
if (peerList.size() == 0)
return null;
return peerList.get((int) (Math.random() * (peerList.size() - 1)));
}
/**
* Lookup for a peer first by its id, then by address, if still not found,
* creates a new entry.

View File

@@ -65,7 +65,6 @@ public class ScoredPieceSelector extends SortedListPieceSelector {
protected void sort(List<TorrentPiece> pieces) {
if (comparator != null)
Collections.sort(pieces, comparator);
System.out.println(pieces);
}
@Override

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2011 Rogiel Josias Sulzbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.bittorrent.protocol.tracker;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import net.torrent.protocol.tracker.HttpTorrentTrackerAnnouncer;
import net.torrent.torrent.Torrent;
import org.junit.Test;
public class HttpTorrentTrackerAnnouncerTest {
@Test
public void testAnnounce() throws IOException, URISyntaxException,
InterruptedException {
final Torrent torrent = Torrent
.load(new File(
"src/test/resources/Tim Besamusca - Running Away EP Urban Sickness Audio USA1008.torrent"));
final HttpTorrentTrackerAnnouncer announcer = new HttpTorrentTrackerAnnouncer();
System.out.println(announcer.announce(torrent, torrent.getTrackers()
.iterator().next()));
//Thread.sleep(10 * 60 * 1000);
}
}

View File

@@ -15,27 +15,42 @@
*/
package net.torrent.protocol.peerwire;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.LogManager;
import net.torrent.BitTorrentClient;
import net.torrent.BitTorrentClientFactory;
import net.torrent.torrent.Torrent;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.logging.JdkLoggerFactory;
import org.junit.Test;
public class PeerWireManagerTest {
// @Test
//@Test
public void testPeerWire() throws IOException, InterruptedException,
URISyntaxException {
final Torrent torrent = Torrent.load(new File(
"src/test/resources/oth.s01e13.avi.torrent"));
LogManager.getLogManager().readConfiguration(
this.getClass().getResourceAsStream("/logging.properties"));
InternalLoggerFactory.setDefaultFactory(new JdkLoggerFactory());
//GET /announce?info_hash=9uKh%e8%2a%81%a47%5b%95%24%d7%84kD-%af%a7%93&peer_id=-TR2130-0kr8c2gx1d39&port=51413&uploaded=0&downloaded=0&left=124928000&numwant=0&key=c3gvpc8w&compact=1&supportcrypto=1&event=stopped HTTP/1.1\r\n
//GET /announce?info_hash=9uKh%E8%2a%81%A47%5B%95%24%D7%84kD-%AF%A7%93&peer_id=-TR2130-g4mvcv2iyehf&port=10254&uploaded=0&downloaded=0&left=0&compact=1&event=started HTTP/1.1
final Torrent torrent = Torrent
.load(new URL(
"http://build.eclipse.org/technology/phoenix/torrents/indigo/eclipse-java-indigo-linux-gtk-x86_64.tar.gz.torrent"));
System.out.println(torrent.getInfoHash());
final BitTorrentClient client = new BitTorrentClientFactory(torrent)
.newBitTorrentClient();
client.start(new InetSocketAddress("192.168.1.100", 25944));
// client.start(new InetSocketAddress("192.168.1.100", 25944));
// client.start(new InetSocketAddress("192.168.1.110", 51413));
client.start();
Thread.sleep(60 * 1000 * 30);
}

View File

@@ -0,0 +1,3 @@
handlers = java.util.logging.ConsoleHandler
.level=FINE
java.util.logging.ConsoleHandler.level = FINE