Skip to content

Commit 2e643f4

Browse files
committed
add the ability to set upload/download rate-limits (in kB/sec.) on shared torrents
1 parent c38e0ce commit 2e643f4

File tree

3 files changed

+94
-8
lines changed

3 files changed

+94
-8
lines changed

src/main/java/com/turn/ttorrent/client/Client.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ public Client(InetAddress address, SharedTorrent torrent)
171171
this.connected = new ConcurrentHashMap<String, SharingPeer>();
172172
this.random = new Random(System.currentTimeMillis());
173173
}
174+
175+
public void setMaxDownloadRate(double rate){
176+
this.torrent.setMaxDownloadRate(rate);
177+
}
178+
179+
public void setMaxUploadRate(double rate){
180+
this.torrent.setMaxUploadRate(rate);
181+
}
174182

175183
/**
176184
* Get this client's peer specification.
@@ -991,10 +999,12 @@ private static void usage(PrintStream s) {
991999
s.println("usage: Client [options] <torrent>");
9921000
s.println();
9931001
s.println("Available options:");
994-
s.println(" -h,--help Show this help and exit.");
995-
s.println(" -o,--output DIR Read/write data to directory DIR.");
996-
s.println(" -i,--iface IFACE Bind to interface IFACE.");
997-
s.println(" -s,--seed SECONDS Time to seed after downloading (default: infinitely).");
1002+
s.println(" -h,--help Show this help and exit.");
1003+
s.println(" -o,--output DIR Read/write data to directory DIR.");
1004+
s.println(" -i,--iface IFACE Bind to interface IFACE.");
1005+
s.println(" -s,--seed SECONDS Time to seed after downloading (default: infinitely).");
1006+
s.println(" -d,--max-download KB/SEC Max download rate (default: infinitely).");
1007+
s.println(" -u,--max-upload KB/SEC Max upload rate (default: infinitely).");
9981008
s.println();
9991009
}
10001010

@@ -1052,6 +1062,11 @@ public static void main(String[] args) {
10521062
CmdLineParser.Option output = parser.addStringOption('o', "output");
10531063
CmdLineParser.Option iface = parser.addStringOption('i', "iface");
10541064
CmdLineParser.Option seedTime = parser.addIntegerOption('s', "seed");
1065+
CmdLineParser.Option maxUpload = parser.addDoubleOption('u', "max-upload");
1066+
CmdLineParser.Option maxDownload = parser.addDoubleOption('d', "max-download");
1067+
1068+
logger.debug("Max Download: {}", parser.getOptionValue(maxDownload, 0.0));
1069+
10551070

10561071
try {
10571072
parser.parse(args);
@@ -1071,6 +1086,9 @@ public static void main(String[] args) {
10711086
DEFAULT_OUTPUT_DIRECTORY);
10721087
String ifaceValue = (String)parser.getOptionValue(iface);
10731088
int seedTimeValue = (Integer)parser.getOptionValue(seedTime, -1);
1089+
1090+
double maxDownloadRate = (Double)parser.getOptionValue(maxDownload, 0.0);
1091+
double maxUploadRate = (Double)parser.getOptionValue(maxUpload, 0.0);
10741092

10751093
String[] otherArgs = parser.getRemainingArgs();
10761094
if (otherArgs.length != 1) {
@@ -1084,6 +1102,9 @@ public static void main(String[] args) {
10841102
SharedTorrent.fromFile(
10851103
new File(otherArgs[0]),
10861104
new File(outputValue)));
1105+
1106+
c.setMaxDownloadRate(maxDownloadRate);
1107+
c.setMaxUploadRate(maxUploadRate);
10871108

10881109
// Set a shutdown hook that will stop the sharing/seeding and send
10891110
// a STOPPED announce request.

src/main/java/com/turn/ttorrent/client/SharedTorrent.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.turn.ttorrent.bcodec.InvalidBEncodingException;
1919
import com.turn.ttorrent.common.Torrent;
2020
import com.turn.ttorrent.client.peer.PeerActivityListener;
21+
import com.turn.ttorrent.client.peer.Rate;
2122
import com.turn.ttorrent.client.peer.SharingPeer;
2223
import com.turn.ttorrent.client.storage.TorrentByteStorage;
2324
import com.turn.ttorrent.client.storage.FileStorage;
@@ -99,7 +100,9 @@ public class SharedTorrent extends Torrent implements PeerActivityListener {
99100
private SortedSet<Piece> rarest;
100101
private BitSet completedPieces;
101102
private BitSet requestedPieces;
102-
103+
104+
private double maxUploadRate = 0.0;
105+
private double maxDownloadRate = 0.0;
103106
/**
104107
* Create a new shared torrent from a base Torrent object.
105108
*
@@ -245,6 +248,22 @@ public static SharedTorrent fromFile(File source, File parent)
245248
fis.close();
246249
return new SharedTorrent(data, parent);
247250
}
251+
252+
public double getMaxUploadRate(){
253+
return this.maxUploadRate;
254+
}
255+
256+
public void setMaxUploadRate(double rate){
257+
this.maxUploadRate = rate;
258+
}
259+
260+
public double getMaxDownloadRate(){
261+
return this.maxDownloadRate;
262+
}
263+
264+
public void setMaxDownloadRate(double rate){
265+
this.maxDownloadRate = rate;
266+
}
248267

249268
/**
250269
* Get the number of bytes uploaded for this torrent.

src/main/java/com/turn/ttorrent/client/peer/PeerExchange.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.turn.ttorrent.client.SharedTorrent;
1919
import com.turn.ttorrent.common.protocol.PeerMessage;
20+
import com.turn.ttorrent.common.protocol.PeerMessage.Type;
2021

2122
import java.io.EOFException;
2223
import java.io.IOException;
@@ -200,6 +201,8 @@ public void close() {
200201
* @author mpetazzoni
201202
*/
202203
private class IncomingThread extends Thread {
204+
private Rate rate = new Rate();
205+
private long sleep = 1000;
203206

204207
@Override
205208
public void run() {
@@ -230,8 +233,11 @@ public void run() {
230233
int pstrlen = buffer.getInt(0);
231234
buffer.limit(PeerMessage.MESSAGE_LENGTH_FIELD_SIZE + pstrlen);
232235

236+
long size = 0;
233237
while (!stop && buffer.hasRemaining()) {
234-
if (channel.read(buffer) < 0) {
238+
int read = channel.read(buffer);
239+
size += read;
240+
if (read < 0) {
235241
throw new EOFException(
236242
"Reached end-of-stream while reading message");
237243
}
@@ -242,6 +248,24 @@ public void run() {
242248
try {
243249
PeerMessage message = PeerMessage.parse(buffer, torrent);
244250
logger.trace("Received {} from {}", message, peer);
251+
252+
// throttling
253+
if(message.getType() == Type.PIECE && PeerExchange.this.torrent.getMaxDownloadRate() > 0){
254+
try {
255+
rate.add(size);
256+
if(rate.get() > (PeerExchange.this.torrent.getMaxDownloadRate() * 1024)){
257+
Thread.sleep(this.sleep);
258+
this.sleep += 50;
259+
} else {
260+
this.sleep -= 50;
261+
}
262+
if(this.sleep < 0){
263+
this.sleep = 0;
264+
}
265+
} catch (InterruptedException e) {
266+
// not critical
267+
}
268+
}
245269

246270
for (MessageListener listener : listeners) {
247271
listener.handleMessage(message);
@@ -278,7 +302,9 @@ public void run() {
278302
* @author mpetazzoni
279303
*/
280304
private class OutgoingThread extends Thread {
281-
305+
private Rate rate = new Rate();
306+
private long sleep = 1000;
307+
282308
@Override
283309
public void run() {
284310
try {
@@ -302,12 +328,32 @@ public void run() {
302328
logger.trace("Sending {} to {}", message, peer);
303329

304330
ByteBuffer data = message.getData();
331+
long size = 0;
305332
while (!stop && data.hasRemaining()) {
306-
if (channel.write(data) < 0) {
333+
int written = channel.write(data);
334+
size += written;
335+
if (written < 0) {
307336
throw new EOFException(
308337
"Reached end of stream while writing");
309338
}
310339
}
340+
341+
if(message.getType() == Type.PIECE && PeerExchange.this.torrent.getMaxUploadRate() > 0){
342+
try {
343+
rate.add(size);
344+
if(rate.get() > (PeerExchange.this.torrent.getMaxUploadRate() * 1024)){
345+
Thread.sleep(this.sleep);
346+
this.sleep += 50;
347+
} else {
348+
this.sleep -= 50;
349+
}
350+
if(this.sleep < 0){
351+
this.sleep = 0;
352+
}
353+
} catch (InterruptedException e) {
354+
// not critical
355+
}
356+
}
311357
} catch (InterruptedException ie) {
312358
// Ignore and potentially terminate
313359
}

0 commit comments

Comments
 (0)