فهرست منبع

2006-04-29 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To add --select-file command-line option:
	
	* src/Util.cc
	(unfoldRange): New function.
	(getNum): New function.
	(unfoldSubRange): New function
	* src/main.cc
	(showUsage): Added help message.
	(main): Added --select-file command-line option.
	
2006-04-28  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>

	To deploy upload rate based choking algorithm:
	
	* src/PeerInteractionCommand.cc
	(PeerInteractionCommand): Add peer to TorrentMan::activePeers to 
track
	peer currently used.
	(decideChoking): Deleted the choke/unchoke decision algorithm 
when
	download completes. Simplified.
	(receiveMessage): Updated.
	* src/TorrentMan.h
	(activePeers): New variable.
	(addActivePeer): New function.
	(getActivePeers): New function.
	(deleteActivePeer): New function.
	* src/TorrentMan.cc
	(addPeer): deleteOldErrorPeers is moved to the begining of the 
function
	* src/PeerAbstractCommand.cc
	(onAbort): Use peer->resetStatus().
	* src/main.cc
	(PeerChokeCommand.h): Included.
	(main): Added the instance of ChokingCommand to the command 
queue.
	* src/Peer.h
	(amChoking): Renamed from amChocking
	(chokingRequired): New variable.
	(optUnchoking): New variable.
	(deltaUpload): New variable.
	(deltaDownload): New variable.
	(addDeltaUpload): New function.
	(resetDeltaUpload): New function.
	(addDeltaDownload): New function.
	(resetDeltaDownload): New function.
	(addPeerUpload): Added a call to addDeltaUpload.
	(addPeerDownload): Added a call to addDeltaDownload.
	* src/Peer.cc
	(shouldBeChoking): Renamed from shouldChoke.
	(resetStatus): New function.
	* src/PeerChokeCommand.h: New class.
	* src/PeerChokeCommand.cc: New class.
	
	To add lazy upload speed limiter:

	* src/TorrentConsoleDownloadEngine.h: Moved the variables for
	statistics calculation to TorrentDownloadEngine.
	* src/TorrentConsoleDownloadEngine.cc
	(sendStatistics): Renamed from printStatistics.
	(initStatistics): Removed. Moved to TorrentDownloadEngine.
	(calculateSpeed): Removed. Moved to TorrentDownloadEngine.
	(calculateStatistics): Removed. Moved to TorrentDownloadEngine.
	* src/TorrentDownloadEngine.h: Added the variables for 
statistics
	calculation.
	(sendStatistics): New function as pure virtual function.
	(getUploadSpeed): New function.
	* src/TorrentDownloadEngine.cc
	(initStatistics): New function.
	(calculateSpeed): New function.
	(calculateStatistics): New function.
	* src/SendMessageQueue.h
	(uploadLength): New variable.
	(send): Added an argument.
	(setUploadLimit): New function.
	(getUploadLimit): New function.
	* src/SendMessageQueue.cc
	(send): Added upload speed limiter.
	* src/prefs.h
	(PREF_UPLOAD_LIMIT): New definition.
	* src/PeerInteractionCommand.cc
	(PeerInteractionCommand): Set upload speed limit to 
sendMessageQueue.
	* src/main.cc
	(main): Added --upload-limit option

	For bug fixes:
	
	* src/main.cc
	(showUsage): Corrected --listen-port help

	Other changes:
	
	* src/TorrentMan.cc
	(getPeer): Return nullPeer if connection is grather than
	MAX_PEER_UPDATE(15) in order to leave space for incoming peers.
Tatsuhiro Tsujikawa 19 سال پیش
والد
کامیت
df2364b1db

+ 94 - 0
ChangeLog

@@ -1,3 +1,97 @@
+2006-04-29  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To add --select-file command-line option:
+	
+	* src/Util.cc
+	(unfoldRange): New function.
+	(getNum): New function.
+	(unfoldSubRange): New function
+	* src/main.cc
+	(showUsage): Added help message.
+	(main): Added --select-file command-line option.
+	
+2006-04-28  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To deploy upload rate based choking algorithm:
+	
+	* src/PeerInteractionCommand.cc
+	(PeerInteractionCommand): Add peer to TorrentMan::activePeers to track
+	peer currently used.
+	(decideChoking): Deleted the choke/unchoke decision algorithm when
+	download completes. Simplified.
+	(receiveMessage): Updated.
+	* src/TorrentMan.h
+	(activePeers): New variable.
+	(addActivePeer): New function.
+	(getActivePeers): New function.
+	(deleteActivePeer): New function.
+	* src/TorrentMan.cc
+	(addPeer): deleteOldErrorPeers is moved to the begining of the function
+	* src/PeerAbstractCommand.cc
+	(onAbort): Use peer->resetStatus().
+	* src/main.cc
+	(PeerChokeCommand.h): Included.
+	(main): Added the instance of ChokingCommand to the command queue.
+	* src/Peer.h
+	(amChoking): Renamed from amChocking
+	(chokingRequired): New variable.
+	(optUnchoking): New variable.
+	(deltaUpload): New variable.
+	(deltaDownload): New variable.
+	(addDeltaUpload): New function.
+	(resetDeltaUpload): New function.
+	(addDeltaDownload): New function.
+	(resetDeltaDownload): New function.
+	(addPeerUpload): Added a call to addDeltaUpload.
+	(addPeerDownload): Added a call to addDeltaDownload.
+	* src/Peer.cc
+	(shouldBeChoking): Renamed from shouldChoke.
+	(resetStatus): New function.
+	* src/PeerChokeCommand.h: New class.
+	* src/PeerChokeCommand.cc: New class.
+	
+	To add lazy upload speed limiter:
+
+	* src/TorrentConsoleDownloadEngine.h: Moved the variables for
+	statistics calculation to TorrentDownloadEngine.
+	* src/TorrentConsoleDownloadEngine.cc
+	(sendStatistics): Renamed from printStatistics.
+	(initStatistics): Removed. Moved to TorrentDownloadEngine.
+	(calculateSpeed): Removed. Moved to TorrentDownloadEngine.
+	(calculateStatistics): Removed. Moved to TorrentDownloadEngine.
+	* src/TorrentDownloadEngine.h: Added the variables for statistics
+	calculation.
+	(sendStatistics): New function as pure virtual function.
+	(getUploadSpeed): New function.
+	* src/TorrentDownloadEngine.cc
+	(initStatistics): New function.
+	(calculateSpeed): New function.
+	(calculateStatistics): New function.
+	* src/SendMessageQueue.h
+	(uploadLength): New variable.
+	(send): Added an argument.
+	(setUploadLimit): New function.
+	(getUploadLimit): New function.
+	* src/SendMessageQueue.cc
+	(send): Added upload speed limiter.
+	* src/prefs.h
+	(PREF_UPLOAD_LIMIT): New definition.
+	* src/PeerInteractionCommand.cc
+	(PeerInteractionCommand): Set upload speed limit to sendMessageQueue.
+	* src/main.cc
+	(main): Added --upload-limit option
+
+	For bug fixes:
+	
+	* src/main.cc
+	(showUsage): Corrected --listen-port help
+
+	Other changes:
+	
+	* src/TorrentMan.cc
+	(getPeer): Return nullPeer if connection is grather than
+	MAX_PEER_UPDATE(15) in order to leave space for incoming peers.
+
 2006-04-21  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	To add some useful information to the exception message:

+ 98 - 70
po/aria2c.pot

@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
-"POT-Creation-Date: 2006-04-21 21:41+0900\n"
+"POT-Creation-Date: 2006-04-29 00:50+0900\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -329,39 +329,39 @@ msgstr ""
 msgid "Failed to peek data, cause: %s"
 msgstr ""
 
-#: src/main.cc:64
+#: src/main.cc:65
 #, c-format
 msgid ""
 "\n"
 "The download was complete. <%s>\n"
 msgstr ""
 
-#: src/main.cc:72
+#: src/main.cc:73
 msgid ""
 "\n"
 "The download was not complete because of errors. Check the log.\n"
 msgstr ""
 
-#: src/main.cc:91 src/main.cc:100
+#: src/main.cc:92 src/main.cc:101
 msgid ""
 "\n"
 "stopping application...\n"
 msgstr ""
 
-#: src/main.cc:95 src/main.cc:110
+#: src/main.cc:96 src/main.cc:111
 msgid "done\n"
 msgstr ""
 
-#: src/main.cc:121
+#: src/main.cc:122
 #, c-format
 msgid "Unrecognized URL or unsupported protocol: %s\n"
 msgstr ""
 
-#: src/main.cc:127
+#: src/main.cc:128
 msgid " version "
 msgstr ""
 
-#: src/main.cc:131
+#: src/main.cc:132
 msgid ""
 "This program is free software; you can redistribute it and/or modify\n"
 "it under the terms of the GNU General Public License as published by\n"
@@ -378,45 +378,45 @@ msgid ""
 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
 msgstr ""
 
-#: src/main.cc:145
+#: src/main.cc:146
 #, c-format
 msgid "Contact Info: %s\n"
 msgstr ""
 
-#: src/main.cc:151
+#: src/main.cc:152
 #, c-format
 msgid "Usage: %s [options] URL ...\n"
 msgstr ""
 
-#: src/main.cc:153
+#: src/main.cc:154
 #, c-format
 msgid "       %s [options] -T TORRENT_FILE FILE ...\n"
 msgstr ""
 
-#: src/main.cc:156
+#: src/main.cc:157
 msgid "Options:"
 msgstr ""
 
-#: src/main.cc:157
+#: src/main.cc:158
 msgid " -d, --dir=DIR                The directory to store downloaded file."
 msgstr ""
 
-#: src/main.cc:158
+#: src/main.cc:159
 msgid " -o, --out=FILE               The file name for downloaded file."
 msgstr ""
 
-#: src/main.cc:159
+#: src/main.cc:160
 msgid ""
 " -l, --log=LOG                The file path to store log. If '-' is "
 "specified,\n"
 "                              log is written to stdout."
 msgstr ""
 
-#: src/main.cc:161
+#: src/main.cc:162
 msgid " -D, --daemon                 Run as daemon."
 msgstr ""
 
-#: src/main.cc:162
+#: src/main.cc:163
 msgid ""
 " -s, --split=N                Download a file using N connections. N must "
 "be\n"
@@ -426,24 +426,24 @@ msgid ""
 "                              N connections."
 msgstr ""
 
-#: src/main.cc:166
+#: src/main.cc:167
 msgid ""
 " --retry-wait=SEC             Set amount of time in second between requests\n"
 "                              for errors. Specify a value between 0 and 60.\n"
 "                              Default: 5"
 msgstr ""
 
-#: src/main.cc:169
+#: src/main.cc:170
 msgid " -t, --timeout=SEC            Set timeout in second. Default: 60"
 msgstr ""
 
-#: src/main.cc:170
+#: src/main.cc:171
 msgid ""
 " -m, --max-tries=N            Set number of tries. 0 means unlimited.\n"
 "                              Default: 5"
 msgstr ""
 
-#: src/main.cc:172
+#: src/main.cc:173
 msgid ""
 " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
 "                              K or M(1K = 1024, 1M = 1024K). This\n"
@@ -451,40 +451,40 @@ msgid ""
 "                              1024."
 msgstr ""
 
-#: src/main.cc:176
+#: src/main.cc:177
 msgid ""
 " --http-proxy=HOST:PORT       Use HTTP proxy server. This affects to all\n"
 "                              URLs."
 msgstr ""
 
-#: src/main.cc:178
+#: src/main.cc:179
 msgid " --http-user=USER             Set HTTP user. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:179
+#: src/main.cc:180
 msgid ""
 " --http-passwd=PASSWD         Set HTTP password. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:180
+#: src/main.cc:181
 msgid ""
 " --http-proxy-user=USER       Set HTTP proxy user. This affects to all URLs"
 msgstr ""
 
-#: src/main.cc:181
+#: src/main.cc:182
 msgid ""
 " --http-proxy-passwd=PASSWD   Set HTTP proxy password. This affects to all "
 "URLs."
 msgstr ""
 
-#: src/main.cc:182
+#: src/main.cc:183
 msgid ""
 " --http-proxy-method=METHOD   Set the method to use in proxy request.\n"
 "                              METHOD is either 'get' or 'tunnel'.\n"
 "                              Default: tunnel"
 msgstr ""
 
-#: src/main.cc:185
+#: src/main.cc:186
 msgid ""
 " --http-auth-scheme=SCHEME    Set HTTP authentication scheme. Currently, "
 "basic\n"
@@ -492,23 +492,23 @@ msgid ""
 "                              Default: basic"
 msgstr ""
 
-#: src/main.cc:188
+#: src/main.cc:189
 msgid " --referer=REFERER            Set Referer. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:189
+#: src/main.cc:190
 msgid ""
 " --ftp-user=USER              Set FTP user. This affects to all URLs.\n"
 "                              Default: anonymous"
 msgstr ""
 
-#: src/main.cc:191
+#: src/main.cc:192
 msgid ""
 " --ftp-passwd=PASSWD          Set FTP password. This affects to all URLs.\n"
 "                              Default: ARIA2USER@"
 msgstr ""
 
-#: src/main.cc:193
+#: src/main.cc:194
 msgid ""
 " --ftp-type=TYPE              Set FTP transfer type. TYPE is either "
 "'binary'\n"
@@ -516,11 +516,11 @@ msgid ""
 "                              Default: binary"
 msgstr ""
 
-#: src/main.cc:196
+#: src/main.cc:197
 msgid " -p, --ftp-pasv               Use passive mode in FTP."
 msgstr ""
 
-#: src/main.cc:197
+#: src/main.cc:198
 msgid ""
 " --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' "
 "or\n"
@@ -528,11 +528,11 @@ msgid ""
 "                              Default: tunnel"
 msgstr ""
 
-#: src/main.cc:201
+#: src/main.cc:202
 msgid " -T, --torrent-file=TORRENT_FILE  The file path to .torrent file."
 msgstr ""
 
-#: src/main.cc:202
+#: src/main.cc:203
 msgid ""
 " --follow-torrent=true|false  Setting this option to false prevents aria2 "
 "to\n"
@@ -541,145 +541,173 @@ msgid ""
 "                              Default: true"
 msgstr ""
 
-#: src/main.cc:206
+#: src/main.cc:207
 msgid ""
 " -S, --show-files             Print file listing of .torrent file and exit."
 msgstr ""
 
-#: src/main.cc:207
+#: src/main.cc:208
 msgid ""
 " --direct-file-mapping=true|false Directly read from and write to each file\n"
 "                              mentioned in .torrent file.\n"
 "                              Default: true"
 msgstr ""
 
-#: src/main.cc:210
+#: src/main.cc:211
 msgid ""
-" --listen-port                Set port number to listen to for peer "
+" --listen-port=PORT           Set port number to listen to for peer "
 "connection."
 msgstr ""
 
 #: src/main.cc:212
+msgid ""
+" --upload-limit=SPEED         Set upload speed limit in KB/sec. aria2 tries "
+"to\n"
+"                              keep upload speed under SPEED. 0 means "
+"unlimited."
+msgstr ""
+
+#: src/main.cc:214
+msgid ""
+" --select-file=INDEX...       Set file to download by specifing its index.\n"
+"                              You can know file index through --show-files\n"
+"                              option. Multiple indexes can be specified by "
+"using\n"
+"                              ',' like \"3,6\".\n"
+"                              You can also use '-' to specify rangelike \"1-5"
+"\".\n"
+"                              ',' and '-' can be used together.\n"
+msgstr ""
+
+#: src/main.cc:221
 msgid " -v, --version                Print the version number and exit."
 msgstr ""
 
-#: src/main.cc:213
+#: src/main.cc:222
 msgid " -h, --help                   Print this message and exit."
 msgstr ""
 
-#: src/main.cc:216
+#: src/main.cc:225
 msgid ""
 " You can specify multiple URLs. All URLs must point to the same file\n"
 " or downloading fails."
 msgstr ""
 
-#: src/main.cc:221
+#: src/main.cc:230
 msgid ""
 " Specify files in multi-file torrent to download. Use conjunction with\n"
-" -T option."
+" -T option. This arguments are ignored if you specify --select-file option."
 msgstr ""
 
-#: src/main.cc:225
+#: src/main.cc:234
 msgid "Examples:"
 msgstr ""
 
-#: src/main.cc:226
+#: src/main.cc:235
 msgid " Download a file by 1 connection:"
 msgstr ""
 
-#: src/main.cc:228
+#: src/main.cc:237
 msgid " Download a file by 2 connections:"
 msgstr ""
 
-#: src/main.cc:230
+#: src/main.cc:239
 msgid " Download a file by 2 connections, each connects to a different server:"
 msgstr ""
 
-#: src/main.cc:232
+#: src/main.cc:241
 msgid " You can mix up different protocols:"
 msgstr ""
 
-#: src/main.cc:235
+#: src/main.cc:244
 msgid " Download a torrent:"
 msgstr ""
 
-#: src/main.cc:237
+#: src/main.cc:246
 msgid " Download a torrent using local .torrent file:"
 msgstr ""
 
-#: src/main.cc:239
+#: src/main.cc:248
 msgid " Download only selected files:"
 msgstr ""
 
-#: src/main.cc:241
+#: src/main.cc:250
 msgid " Print file listing of .torrent file:"
 msgstr ""
 
-#: src/main.cc:245
+#: src/main.cc:254
 #, c-format
 msgid "Report bugs to %s"
 msgstr ""
 
-#: src/main.cc:339
+#: src/main.cc:350
 msgid "unrecognized proxy format"
 msgstr ""
 
-#: src/main.cc:366
+#: src/main.cc:377
 msgid "Currently, supported authentication scheme is basic."
 msgstr ""
 
-#: src/main.cc:375
+#: src/main.cc:386
 msgid "retry-wait must be between 0 and 60."
 msgstr ""
 
-#: src/main.cc:392
+#: src/main.cc:403
 msgid "ftp-type must be either 'binary' or 'ascii'."
 msgstr ""
 
-#: src/main.cc:401
+#: src/main.cc:412
 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'."
 msgstr ""
 
-#: src/main.cc:419
+#: src/main.cc:430
 msgid "min-segment-size invalid"
 msgstr ""
 
-#: src/main.cc:430
+#: src/main.cc:441
 msgid "http-proxy-method must be either 'get' or 'tunnel'."
 msgstr ""
 
-#: src/main.cc:438
+#: src/main.cc:449
 msgid "listen-port must be between 1024 and 65535."
 msgstr ""
 
-#: src/main.cc:449
+#: src/main.cc:460
 msgid "follow-torrent must be either 'true' or 'false'."
 msgstr ""
 
-#: src/main.cc:489
+#: src/main.cc:474
+msgid "direct-file-mapping must be either 'true' or 'false'."
+msgstr ""
+
+#: src/main.cc:482
+msgid "upload-limit must be grater than or equal to 0."
+msgstr ""
+
+#: src/main.cc:514
 msgid "split must be between 1 and 5."
 msgstr ""
 
-#: src/main.cc:499
+#: src/main.cc:524
 msgid "timeout must be between 1 and 600"
 msgstr ""
 
-#: src/main.cc:508
+#: src/main.cc:533
 msgid "max-tries invalid"
 msgstr ""
 
-#: src/main.cc:537
+#: src/main.cc:562
 msgid "specify at least one URL"
 msgstr ""
 
-#: src/main.cc:544
+#: src/main.cc:569
 msgid "daemon failed"
 msgstr ""
 
-#: src/main.cc:648
+#: src/main.cc:671
 msgid "Files:"
 msgstr ""
 
-#: src/main.cc:671
+#: src/main.cc:702
 msgid "Errors occurred while binding port.\n"
 msgstr ""

BIN
po/ja.gmo


+ 112 - 73
po/ja.po

@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: aria2c 0.2.1\n"
 "Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
-"POT-Creation-Date: 2006-04-21 21:41+0900\n"
-"PO-Revision-Date: 2006-04-21 01:08+0900\n"
+"POT-Creation-Date: 2006-04-29 00:50+0900\n"
+"PO-Revision-Date: 2006-04-29 00:54+0900\n"
 "Last-Translator: Tatsuhiro Tsujikawa <tujikawa@rednoah.com>\n"
 "Language-Team: Japanese <ja@li.org>\n"
 "MIME-Version: 1.0\n"
@@ -341,7 +341,7 @@ msgstr "
 msgid "Failed to peek data, cause: %s"
 msgstr "データの peek に失敗しました. 原因: %s"
 
-#: src/main.cc:64
+#: src/main.cc:65
 #, c-format
 msgid ""
 "\n"
@@ -350,7 +350,7 @@ msgstr ""
 "\n"
 "<%s> のダウンロードが完了しました.\n"
 
-#: src/main.cc:72
+#: src/main.cc:73
 msgid ""
 "\n"
 "The download was not complete because of errors. Check the log.\n"
@@ -358,7 +358,7 @@ msgstr ""
 "\n"
 "ダウンロードはエラーのため完了していません. ログを確認してください.\n"
 
-#: src/main.cc:91 src/main.cc:100
+#: src/main.cc:92 src/main.cc:101
 msgid ""
 "\n"
 "stopping application...\n"
@@ -366,22 +366,22 @@ msgstr ""
 "\n"
 "アプリケーションを終了しています...\n"
 
-#: src/main.cc:95 src/main.cc:110
+#: src/main.cc:96 src/main.cc:111
 msgid "done\n"
 msgstr "完了\n"
 
-#: src/main.cc:121
+#: src/main.cc:122
 #, c-format
 msgid "Unrecognized URL or unsupported protocol: %s\n"
 msgstr ""
 "%s は, 理解できない URL フォーマット, または, サポートされないプロトコルで"
 "す.\n"
 
-#: src/main.cc:127
+#: src/main.cc:128
 msgid " version "
 msgstr " バージョン "
 
-#: src/main.cc:131
+#: src/main.cc:132
 msgid ""
 "This program is free software; you can redistribute it and/or modify\n"
 "it under the terms of the GNU General Public License as published by\n"
@@ -412,36 +412,36 @@ msgstr ""
 "Temple Place, Suite 330, Boston, MA 02111-1307 USA)。\n"
 "(訳: http://www.opensource.jp/gpl/gpl.ja.html.euc-jp)\n"
 
-#: src/main.cc:145
+#: src/main.cc:146
 #, c-format
 msgid "Contact Info: %s\n"
 msgstr "連絡先: %s\n"
 
-#: src/main.cc:151
+#: src/main.cc:152
 #, c-format
 msgid "Usage: %s [options] URL ...\n"
 msgstr "使い方: %s [オプション] URL ...\n"
 
-#: src/main.cc:153
+#: src/main.cc:154
 #, c-format
 msgid "       %s [options] -T TORRENT_FILE FILE ...\n"
 msgstr "        %s [オプション] -T TORRENT_FILE FILE ...\n"
 
-#: src/main.cc:156
+#: src/main.cc:157
 msgid "Options:"
 msgstr "オプション:"
 
-#: src/main.cc:157
+#: src/main.cc:158
 msgid " -d, --dir=DIR                The directory to store downloaded file."
 msgstr ""
 " -d, --dir=DIR                ダウンロードしたファイルを保存するディレクトリ."
 
-#: src/main.cc:158
+#: src/main.cc:159
 msgid " -o, --out=FILE               The file name for downloaded file."
 msgstr ""
 " -o, --out=FILE               ダウンロードしたファイルの保存先ファイル名."
 
-#: src/main.cc:159
+#: src/main.cc:160
 msgid ""
 " -l, --log=LOG                The file path to store log. If '-' is "
 "specified,\n"
@@ -451,11 +451,11 @@ msgstr ""
 "力\n"
 "                              に出力します."
 
-#: src/main.cc:161
+#: src/main.cc:162
 msgid " -D, --daemon                 Run as daemon."
 msgstr " -D, --daemon                 デーモンとして起動します."
 
-#: src/main.cc:162
+#: src/main.cc:163
 msgid ""
 " -s, --split=N                Download a file using N connections. N must "
 "be\n"
@@ -474,7 +474,7 @@ msgstr ""
 "ショ\n"
 "                              ンを確立します."
 
-#: src/main.cc:166
+#: src/main.cc:167
 msgid ""
 " --retry-wait=SEC             Set amount of time in second between requests\n"
 "                              for errors. Specify a value between 0 and 60.\n"
@@ -485,13 +485,13 @@ msgstr ""
 "                              す. 0 - 60 の値を指定してください.\n"
 "                              デフォルト値: 5"
 
-#: src/main.cc:169
+#: src/main.cc:170
 msgid " -t, --timeout=SEC            Set timeout in second. Default: 60"
 msgstr ""
 " -t, --timeout=SEC            タイムアウトとなる時間を秒で指定します.\n"
 "                              デフォルト値: 60"
 
-#: src/main.cc:170
+#: src/main.cc:171
 msgid ""
 " -m, --max-tries=N            Set number of tries. 0 means unlimited.\n"
 "                              Default: 5"
@@ -500,7 +500,7 @@ msgstr ""
 "行\n"
 "                              します. デフォルト値: 5"
 
-#: src/main.cc:172
+#: src/main.cc:173
 msgid ""
 " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
 "                              K or M(1K = 1024, 1M = 1024K). This\n"
@@ -513,7 +513,7 @@ msgstr ""
 "1024K).\n"
 "                              1024 以上の値を指定してください."
 
-#: src/main.cc:176
+#: src/main.cc:177
 msgid ""
 " --http-proxy=HOST:PORT       Use HTTP proxy server. This affects to all\n"
 "                              URLs."
@@ -522,14 +522,14 @@ msgstr ""
 "シ\n"
 "                              ョンはすべての URL に影響します."
 
-#: src/main.cc:178
+#: src/main.cc:179
 msgid " --http-user=USER             Set HTTP user. This affects to all URLs."
 msgstr ""
 " --http-user=USER             HTTP での認証ユーザーを指定します. このオプショ"
 "ン\n"
 "                              はすべての URL に影響します."
 
-#: src/main.cc:179
+#: src/main.cc:180
 msgid ""
 " --http-passwd=PASSWD         Set HTTP password. This affects to all URLs."
 msgstr ""
@@ -537,7 +537,7 @@ msgstr ""
 "ショ\n"
 "                              ンはすべての URL に影響します."
 
-#: src/main.cc:180
+#: src/main.cc:181
 msgid ""
 " --http-proxy-user=USER       Set HTTP proxy user. This affects to all URLs"
 msgstr ""
@@ -547,7 +547,7 @@ msgstr ""
 "ま\n"
 "                              す."
 
-#: src/main.cc:181
+#: src/main.cc:182
 msgid ""
 " --http-proxy-passwd=PASSWD   Set HTTP proxy password. This affects to all "
 "URLs."
@@ -558,7 +558,7 @@ msgstr ""
 "し\n"
 "                              ます."
 
-#: src/main.cc:182
+#: src/main.cc:183
 msgid ""
 " --http-proxy-method=METHOD   Set the method to use in proxy request.\n"
 "                              METHOD is either 'get' or 'tunnel'.\n"
@@ -569,7 +569,7 @@ msgstr ""
 "                              す. 'get' または 'tunnel' を指定してください.\n"
 "                              デフォルト値: tunnel"
 
-#: src/main.cc:185
+#: src/main.cc:186
 msgid ""
 " --http-auth-scheme=SCHEME    Set HTTP authentication scheme. Currently, "
 "basic\n"
@@ -581,14 +581,14 @@ msgstr ""
 "                              いるのは basic です. \n"
 "                              デフォルト値: basic"
 
-#: src/main.cc:188
+#: src/main.cc:189
 msgid " --referer=REFERER            Set Referer. This affects to all URLs."
 msgstr ""
 " --referer=REFERER            リファラーを指定します. このオプションはすべて"
 "の\n"
 "                               URL に影響します."
 
-#: src/main.cc:189
+#: src/main.cc:190
 msgid ""
 " --ftp-user=USER              Set FTP user. This affects to all URLs.\n"
 "                              Default: anonymous"
@@ -598,7 +598,7 @@ msgstr ""
 "                              はすべての URL に影響します.\n"
 "                              デフォルト値: anonymous"
 
-#: src/main.cc:191
+#: src/main.cc:192
 msgid ""
 " --ftp-passwd=PASSWD          Set FTP password. This affects to all URLs.\n"
 "                              Default: ARIA2USER@"
@@ -608,7 +608,7 @@ msgstr ""
 "                              ンはすべての URL に影響します.\n"
 "                              デフォルト値: ARIA2USER@"
 
-#: src/main.cc:193
+#: src/main.cc:194
 msgid ""
 " --ftp-type=TYPE              Set FTP transfer type. TYPE is either "
 "'binary'\n"
@@ -619,11 +619,11 @@ msgstr ""
 "                              'ascii' を指定してください. デフォルト値: "
 "binary"
 
-#: src/main.cc:196
+#: src/main.cc:197
 msgid " -p, --ftp-pasv               Use passive mode in FTP."
 msgstr " -p, --ftp-pasv               FTP で passive モードを使用します."
 
-#: src/main.cc:197
+#: src/main.cc:198
 msgid ""
 " --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' "
 "or\n"
@@ -636,11 +636,11 @@ msgstr ""
 "く\n"
 "                              ださい. デフォルト値: tunnel"
 
-#: src/main.cc:201
+#: src/main.cc:202
 msgid " -T, --torrent-file=TORRENT_FILE  The file path to .torrent file."
 msgstr " -T, --torrent-file=TORRENT_FILE  .torrent ファイルのパスを指定."
 
-#: src/main.cc:202
+#: src/main.cc:203
 msgid ""
 " --follow-torrent=true|false  Setting this option to false prevents aria2 "
 "to\n"
@@ -655,7 +655,7 @@ msgstr ""
 "                              は, BitTorrent モードに入りません.\n"
 "                              デフォルト値: true"
 
-#: src/main.cc:206
+#: src/main.cc:207
 msgid ""
 " -S, --show-files             Print file listing of .torrent file and exit."
 msgstr ""
@@ -663,7 +663,7 @@ msgstr ""
 "し\n"
 "                              終了します."
 
-#: src/main.cc:207
+#: src/main.cc:208
 msgid ""
 " --direct-file-mapping=true|false Directly read from and write to each file\n"
 "                              mentioned in .torrent file.\n"
@@ -674,23 +674,54 @@ msgstr ""
 "                              します.\n"
 "                              デフォルト値: true"
 
-#: src/main.cc:210
+#: src/main.cc:211
 msgid ""
-" --listen-port                Set port number to listen to for peer "
+" --listen-port=PORT           Set port number to listen to for peer "
 "connection."
 msgstr ""
-" --listen-port                ピアからの接続を受け付けるポート番号を指定."
+" --listen-port=PORT           ピアからの接続を受け付けるポート番号を指定."
 
 #: src/main.cc:212
+msgid ""
+" --upload-limit=SPEED         Set upload speed limit in KB/sec. aria2 tries "
+"to\n"
+"                              keep upload speed under SPEED. 0 means "
+"unlimited."
+msgstr ""
+"\" --upload-limit=SPEED         アップロード制限速度を KB/秒 で設定. aria2 は"
+"この\n"
+"                               設定値をアップロード速度が上回らないように努力"
+"し\n"
+"                               ます. 0 は速度無制限を意味します."
+
+#: src/main.cc:214
+msgid ""
+" --select-file=INDEX...       Set file to download by specifing its index.\n"
+"                              You can know file index through --show-files\n"
+"                              option. Multiple indexes can be specified by "
+"using\n"
+"                              ',' like \"3,6\".\n"
+"                              You can also use '-' to specify rangelike \"1-5"
+"\".\n"
+"                              ',' and '-' can be used together.\n"
+msgstr ""
+" --select-file=INDEX...       インデックスでダウンロード対象ファイルを指定しま\n"
+"                              す. インデックスは --show-files オプションで知る\n"
+"                              ことができます. 複数のインデックスを ',' で区切っ\n"
+"                              て指定できます: \"3,6\"\n"
+"                              また, '-' を使って範囲指定もできます: \"1-5\"\n"
+"                              ',' と '-' は組み合わせて使うことができます.\n"
+
+#: src/main.cc:221
 msgid " -v, --version                Print the version number and exit."
 msgstr " -v, --version                バージョン番号を表示し, 終了します."
 
-#: src/main.cc:213
+#: src/main.cc:222
 msgid " -h, --help                   Print this message and exit."
 msgstr ""
 " -h, --help                   このヘルプメッセージを表示し, 終了します."
 
-#: src/main.cc:216
+#: src/main.cc:225
 msgid ""
 " You can specify multiple URLs. All URLs must point to the same file\n"
 " or downloading fails."
@@ -699,116 +730,124 @@ msgstr ""
 "れ\n"
 " ばなりません. さもなくばダウンロードは失敗します."
 
-#: src/main.cc:221
+#: src/main.cc:230
 msgid ""
 " Specify files in multi-file torrent to download. Use conjunction with\n"
-" -T option."
+" -T option. This arguments are ignored if you specify --select-file option."
 msgstr ""
 " multi-file torrent のとき, ダウンロードするファイルを指定します. -T オプショ"
 "ン\n"
-" と共に使用します."
+" と共に使用します. --select-file オプションと併用はできません."
 
-#: src/main.cc:225
+#: src/main.cc:234
 msgid "Examples:"
 msgstr "例:"
 
-#: src/main.cc:226
+#: src/main.cc:235
 msgid " Download a file by 1 connection:"
 msgstr " 1 コネクションでのダウンロード:"
 
-#: src/main.cc:228
+#: src/main.cc:237
 msgid " Download a file by 2 connections:"
 msgstr " 2 コネクションでのダウンロード:"
 
-#: src/main.cc:230
+#: src/main.cc:239
 msgid " Download a file by 2 connections, each connects to a different server:"
 msgstr " 二つの異なるサーバーに接続してダウンロード:"
 
-#: src/main.cc:232
+#: src/main.cc:241
 msgid " You can mix up different protocols:"
 msgstr " 異なるプロトコルを混合させてダウンロード:"
 
-#: src/main.cc:235
+#: src/main.cc:244
 msgid " Download a torrent:"
 msgstr "torrent をダウンロード:"
 
-#: src/main.cc:237
+#: src/main.cc:246
 msgid " Download a torrent using local .torrent file:"
 msgstr " ローカル .torrent ファイルを使ってダウンロード:"
 
-#: src/main.cc:239
+#: src/main.cc:248
 msgid " Download only selected files:"
 msgstr " ファイルを指定してダウンロード:"
 
-#: src/main.cc:241
+#: src/main.cc:250
 msgid " Print file listing of .torrent file:"
 msgstr " この .torrent ファイルに含まれるファイルリストを表示:"
 
-#: src/main.cc:245
+#: src/main.cc:254
 #, c-format
 msgid "Report bugs to %s"
 msgstr "バグレポートはこちらへ: %s"
 
-#: src/main.cc:339
+#: src/main.cc:350
 msgid "unrecognized proxy format"
 msgstr "理解できないProxyフォーマットです."
 
-#: src/main.cc:366
+#: src/main.cc:377
 msgid "Currently, supported authentication scheme is basic."
 msgstr "現在サポートされている認証方法は basic です."
 
-#: src/main.cc:375
+#: src/main.cc:386
 msgid "retry-wait must be between 0 and 60."
 msgstr "retry-wait は 0 から 60 の間で指定してください."
 
-#: src/main.cc:392
+#: src/main.cc:403
 msgid "ftp-type must be either 'binary' or 'ascii'."
 msgstr "ftp-type は 'binary' または 'ascii' を指定してください."
 
-#: src/main.cc:401
+#: src/main.cc:412
 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'."
 msgstr "ftp-via-http-proxy は 'get' または 'tunnel' を指定してください."
 
-#: src/main.cc:419
+#: src/main.cc:430
 msgid "min-segment-size invalid"
 msgstr "min-segment-size が不正です."
 
-#: src/main.cc:430
+#: src/main.cc:441
 msgid "http-proxy-method must be either 'get' or 'tunnel'."
 msgstr "http-proxy-method は 'get' または 'tunnel' を指定してください."
 
-#: src/main.cc:438
+#: src/main.cc:449
 msgid "listen-port must be between 1024 and 65535."
 msgstr "listen-port は 1024 - 65535 の値を指定してください."
 
-#: src/main.cc:449
+#: src/main.cc:460
 msgid "follow-torrent must be either 'true' or 'false'."
 msgstr "follow-torrent は 'true' または 'false を指定してください."
 
-#: src/main.cc:489
+#: src/main.cc:474
+msgid "direct-file-mapping must be either 'true' or 'false'."
+msgstr "direct-file-mapping は 'true' または 'false を指定してください."
+
+#: src/main.cc:482
+msgid "upload-limit must be grater than or equal to 0."
+msgstr "upload-limit は 0 以上の数を指定してください."
+
+#: src/main.cc:514
 msgid "split must be between 1 and 5."
 msgstr "split は 1 - 5 の値を指定してください."
 
-#: src/main.cc:499
+#: src/main.cc:524
 msgid "timeout must be between 1 and 600"
 msgstr "timeout は 1 - 600 の値を指定してください."
 
-#: src/main.cc:508
+#: src/main.cc:533
 msgid "max-tries invalid"
 msgstr "max-tries が不正です."
 
-#: src/main.cc:537
+#: src/main.cc:562
 msgid "specify at least one URL"
 msgstr "一個以上の URL を指定してください."
 
-#: src/main.cc:544
+#: src/main.cc:569
 msgid "daemon failed"
 msgstr "デーモン起動に失敗"
 
-#: src/main.cc:648
+#: src/main.cc:671
 msgid "Files:"
 msgstr "ファイル:"
 
-#: src/main.cc:671
+#: src/main.cc:702
 msgid "Errors occurred while binding port.\n"
 msgstr "ポートをバインド中にエラーが発生しました.\n"

+ 2 - 0
src/DiskAdaptor.h

@@ -54,6 +54,8 @@ public:
     this->fileEntries = fileEntries;
   }
   FileEntry getFileEntryFromPath(const string& fileEntryPath) const;
+  const FileEntries& getFileEntries() const { return fileEntries; }
+
   bool addDownloadEntry(const string& fileEntryPath);
   bool addDownloadEntry(int index);
   void addAllDownloadEntry();

+ 2 - 1
src/Makefile.am

@@ -84,7 +84,8 @@ SRCS =  Socket.cc Socket.h\
 	FileEntry.h\
 	LogFactory.cc LogFactory.h\
 	TrackerUpdateCommand.cc TrackerUpdateCommand.h\
-	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h
+	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\
+	PeerChokeCommand.cc PeerChokeCommand.h
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\

+ 4 - 2
src/Makefile.in

@@ -100,7 +100,7 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
 	DiskAdaptor.$(OBJEXT) CopyDiskAdaptor.$(OBJEXT) \
 	DirectDiskAdaptor.$(OBJEXT) MultiDiskAdaptor.$(OBJEXT) \
 	LogFactory.$(OBJEXT) TrackerUpdateCommand.$(OBJEXT) \
-	ByteArrayDiskWriter.$(OBJEXT)
+	ByteArrayDiskWriter.$(OBJEXT) PeerChokeCommand.$(OBJEXT)
 am_libaria2c_a_OBJECTS = $(am__objects_1)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -334,7 +334,8 @@ SRCS = Socket.cc Socket.h\
 	FileEntry.h\
 	LogFactory.cc LogFactory.h\
 	TrackerUpdateCommand.cc TrackerUpdateCommand.h\
-	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h
+	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\
+	PeerChokeCommand.cc PeerChokeCommand.h
 
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
@@ -461,6 +462,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Option.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Peer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerAbstractCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerChokeCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerConnection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerInitiateConnectionCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerInteractionCommand.Po@am__quote@

+ 16 - 11
src/Peer.cc

@@ -33,19 +33,11 @@ void Peer::updateBitfield(int index, int operation) {
 
 #define THRESHOLD 1024*1024*2
 
-bool Peer::shouldChoke() const {
-  if(bitfield->countBlock()*0.95 < bitfield->countMissingBlock()) {
+bool Peer::shouldBeChoking() const {
+  if(optUnchoking) {
     return false;
   }
-  // we are always optimistic.
-  if(amInterested && peerInterested) {
-    return false;
-  }
-  if(amChocking) {
-    return !(peerDownload+pieceLength*5 < peerUpload);
-  } else {
-    return peerDownload >= peerUpload+pieceLength*5;
-  }
+  return chokingRequired;
 }
 
 bool Peer::hasPiece(int index) const {
@@ -55,3 +47,16 @@ bool Peer::hasPiece(int index) const {
 bool Peer::isSeeder() const {
   return bitfield->isAllBitSet();
 }
+
+void Peer::resetStatus() {
+  tryCount = 0;
+  cuid = 0;
+  amChoking = true;
+  amInterested = false;
+  peerChoking = true;
+  peerInterested = false;
+  resetDeltaUpload();
+  resetDeltaDownload();
+  chokingRequired = true;
+  optUnchoking = false;
+}

+ 32 - 6
src/Peer.h

@@ -36,13 +36,15 @@ public:
   int entryId;
   string ipaddr;
   int port;
-  bool amChocking;
+  bool amChoking;
   bool amInterested;
   bool peerChoking;
   bool peerInterested;
   int tryCount;
   int error;
   int cuid;
+  bool chokingRequired;
+  bool optUnchoking;
 private:
   char peerId[PEER_ID_LENGTH];
   BitfieldMan* bitfield;
@@ -50,15 +52,19 @@ private:
   long long int peerDownload;
   int pieceLength;
   long long int totalLength;
+  int deltaUpload;
+  int deltaDownload;
 public:
   Peer(string ipaddr, int port, int pieceLength, long long int totalLength):
     entryId(0), ipaddr(ipaddr), port(port),
-    amChocking(true), amInterested(false),
+    amChoking(true), amInterested(false),
     peerChoking(true), peerInterested(false),
     tryCount(0), error(0), cuid(0),
+    chokingRequired(true), optUnchoking(false),
     bitfield(NULL),
     peerUpload(0), peerDownload(0),
-    pieceLength(pieceLength), totalLength(totalLength) {
+    pieceLength(pieceLength), totalLength(totalLength),
+    deltaUpload(0), deltaDownload(0) {
     this->bitfield = new BitfieldMan(pieceLength, totalLength);
   }
 
@@ -68,6 +74,20 @@ public:
     }
   }
 
+  void resetStatus();
+
+  void addDeltaUpload(int length) {
+    this->deltaUpload += length;
+  }
+  void resetDeltaUpload() { this->deltaUpload = 0; }
+  int getDeltaUpload() const { return this->deltaUpload; }
+
+  void addDeltaDownload(int length) {
+    this->deltaDownload += length;
+  }
+  void resetDeltaDownload() { this->deltaDownload = 0; }
+  int getDeltaDownload() const { return this->deltaDownload; }
+
   void setPeerId(const char* peerId) {
     memcpy(this->peerId, peerId, PEER_ID_LENGTH);
   }
@@ -85,15 +105,21 @@ public:
    */
   void updateBitfield(int index, int operation);
 
-  void addPeerUpload(int size) { peerUpload += size; }
+  void addPeerUpload(int size) {
+    peerUpload += size;
+    addDeltaUpload(size);
+  }
   void setPeerUpload(long long int size) { peerUpload = size; }
   long long int getPeerUpload() const { return peerUpload; }
 
-  void addPeerDownload(int size) { peerDownload += size; }
+  void addPeerDownload(int size) {
+    peerDownload += size;
+    addDeltaDownload(size);
+  }
   void setPeerDownload(long long int size) { peerDownload = size; }
   long long int getPeerDownload() const { return peerDownload; }
 
-  bool shouldChoke() const;
+  bool shouldBeChoking() const;
 
   bool hasPiece(int index) const;
 

+ 1 - 6
src/PeerAbstractCommand.cc

@@ -130,12 +130,7 @@ void PeerAbstractCommand::onAbort(Exception* ex) {
   } else {
     peer->error += MAX_PEER_ERROR;
   }
-  peer->tryCount = 0;
-  peer->cuid = 0;
-  peer->amChocking = true;
-  peer->amInterested = false;
-  peer->peerChoking = true;
-  peer->peerInterested = false;
+  peer->resetStatus();
   logger->debug("CUID#%d - peer %s:%d banned.", cuid, peer->ipaddr.c_str(), peer->port);
 }
 

+ 149 - 0
src/PeerChokeCommand.cc

@@ -0,0 +1,149 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#include "PeerChokeCommand.h"
+#include "SleepCommand.h"
+#include "Util.h"
+
+PeerChokeCommand::PeerChokeCommand(int cuid, int interval, TorrentDownloadEngine* e):Command(cuid), interval(interval), e(e), rotate(0) {}
+
+PeerChokeCommand::~PeerChokeCommand() {}
+
+void PeerChokeCommand::setAllPeerChoked(Peers& peers) const {
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    Peer* peer = *itr;
+    peer->chokingRequired = true;
+  }
+}
+
+void PeerChokeCommand::optUnchokingPeer(Peers& peers) const {
+  if(peers.empty()) {
+    return;
+  }
+  random_shuffle(peers.begin(), peers.end());
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    (*itr)->optUnchoking = false;
+  }
+  Peer* peer = peers.front();
+  peer->optUnchoking = true;
+  /*
+  Peers::iterator itr = peers.begin();
+  for(;itr != peers.end(); itr++) {
+    if((*itr)->optUnchoking) {
+      break;
+    }
+  }
+  if(itr != peers.end()) {
+    (*itr)->optUnchoking = false;
+    itr++;
+  }
+  if(itr == peers.end()) {
+    itr = peers.begin();
+  }
+  (*itr)->optUnchoking = true;
+  */
+  logger->debug("opt, unchoking %s, delta=%d",
+		peer->ipaddr.c_str(), peer->getDeltaUpload());
+}
+
+void PeerChokeCommand::setAllPeerResetDeltaUpload(Peers& peers) const {
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    Peer* peer = *itr;
+    peer->resetDeltaUpload();
+  }
+}
+
+void PeerChokeCommand::setAllPeerResetDeltaDownload(Peers& peers) const {
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    Peer* peer = *itr;
+    peer->resetDeltaDownload();
+  }
+}
+
+class UploadFaster {
+public:
+  bool operator() (const Peer* left, const Peer* right) const {
+    return left->getDeltaUpload() > right->getDeltaUpload();
+  }
+};
+
+void PeerChokeCommand::orderByUploadRate(Peers& peers) const {
+  sort(peers.begin(), peers.end(), UploadFaster());
+}
+
+class DownloadFaster {
+public:
+  bool operator() (const Peer* left, const Peer* right) const {
+    return left->getDeltaDownload() > right->getDeltaDownload();
+  }
+};
+
+void PeerChokeCommand::orderByDownloadRate(Peers& peers) const {
+  sort(peers.begin(), peers.end(), UploadFaster());
+}
+
+bool PeerChokeCommand::execute() {
+  Peers peers = e->torrentMan->getActivePeers();
+  setAllPeerChoked(peers);
+  if(e->torrentMan->downloadComplete()) {
+    orderByDownloadRate(peers);
+  } else {
+    orderByUploadRate(peers);
+  }
+  int unchokingCount = peers.size() >= 4 ? 4 : peers.size();
+  for(Peers::iterator itr = peers.begin(); unchokingCount > 0 && itr != peers.end(); ) {
+    Peer* peer = *itr;
+    if(peer->peerInterested) {
+      peer->chokingRequired = false;
+      itr = peers.erase(itr);
+      unchokingCount--;
+      logger->debug("cat01, unchoking %s, delta=%d", peer->ipaddr.c_str(), peer->getDeltaUpload());
+    } else {
+      itr++;
+    }
+  }
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); ) {
+    Peer* peer = *itr;
+    if(!peer->peerInterested) {
+      peer->chokingRequired = false;
+      itr = peers.erase(itr);
+      logger->debug("cat02, unchoking %s, delta=%d", peer->ipaddr.c_str(), peer->getDeltaUpload());
+      break;
+    } else {
+      itr++;
+    }
+  }
+  if(rotate%3 == 0) {
+    optUnchokingPeer(peers);
+    rotate = 0;
+  }
+  rotate++;
+  if(e->torrentMan->downloadComplete()) {
+    setAllPeerResetDeltaDownload(e->torrentMan->getActivePeers());
+  } else {
+    setAllPeerResetDeltaUpload(e->torrentMan->getActivePeers());
+  }
+
+  SleepCommand* command = new SleepCommand(cuid, e, this, interval);
+  e->commands.push(command);
+
+  return false;
+}

+ 48 - 0
src/PeerChokeCommand.h

@@ -0,0 +1,48 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#ifndef _D_PEER_CHOKE_COMMAND_H_
+#define _D_PEER_CHOKE_COMMAND_H_
+
+#include "Command.h"
+#include "TorrentDownloadEngine.h"
+
+class PeerChokeCommand : public Command {
+private:
+  int interval;
+  TorrentDownloadEngine* e;
+  int rotate;
+
+  void orderByUploadRate(Peers& peers) const;
+  void orderByDownloadRate(Peers& peers) const;
+  void setAllPeerChoked(Peers& peers) const;
+  void setAllPeerResetDeltaUpload(Peers& peers) const;
+  void setAllPeerResetDeltaDownload(Peers& peers) const;
+  void optUnchokingPeer(Peers& peers) const;
+
+public:
+  PeerChokeCommand(int cuid, int interval, TorrentDownloadEngine* e);
+  virtual ~PeerChokeCommand();
+
+  bool execute();
+};
+
+#endif // _D_PEER_CHOKE_COMMAND_H_

+ 10 - 15
src/PeerInteractionCommand.cc

@@ -39,6 +39,7 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, Peer* peer,
   }
   peerConnection = new PeerConnection(cuid, socket, e->option, peer, e->torrentMan);
   sendMessageQueue = new SendMessageQueue(cuid, peerConnection, e->torrentMan);
+  sendMessageQueue->setUploadLimit(e->option->getAsInt(PREF_UPLOAD_LIMIT));
   piece = Piece::nullPiece;
   keepAliveCheckPoint.tv_sec = 0;
   keepAliveCheckPoint.tv_usec = 0;
@@ -49,12 +50,14 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, Peer* peer,
   chokeUnchokeCount = 0;
   haveCount = 0;
   keepAliveCount = 0;
+  e->torrentMan->addActivePeer(this->peer);
 }
 
 PeerInteractionCommand::~PeerInteractionCommand() {
   delete peerConnection;
   delete sendMessageQueue;
   e->torrentMan->unadvertisePiece(cuid);
+  e->torrentMan->deleteActivePeer(this->peer);
 }
 
 bool PeerInteractionCommand::executeInternal() {
@@ -189,24 +192,16 @@ void PeerInteractionCommand::syncPiece() {
 }
 
 void PeerInteractionCommand::decideChoking() {
-  if(e->torrentMan->downloadComplete()) {
-    if(peer->amChocking && peer->peerInterested) {
-      PendingMessage pendingMessage(PeerMessage::UNCHOKE, peerConnection);
+  if(peer->shouldBeChoking()) {
+    if(!peer->amChoking) {
+      PendingMessage pendingMessage(PeerMessage::CHOKE, peerConnection);
       sendMessageQueue->addPendingMessage(pendingMessage);
     }
-    return;
-  }
-  if(peer->shouldChoke()) {
-    if(!peer->amChocking) {
-      PendingMessage pendingMessage(PeerMessage::CHOKE, peerConnection);
+  } else {
+    if(peer->amChoking) {
+      PendingMessage pendingMessage(PeerMessage::UNCHOKE, peerConnection);
       sendMessageQueue->addPendingMessage(pendingMessage);
     }
-  } else if(peer->amChocking && peer->peerInterested) {
-    PendingMessage pendingMessage(PeerMessage::UNCHOKE, peerConnection);
-    sendMessageQueue->addPendingMessage(pendingMessage);
-  } else if(!peer->peerInterested) {
-    PendingMessage pendingMessage(PeerMessage::CHOKE, peerConnection);
-    sendMessageQueue->addPendingMessage(pendingMessage);
   }
 }
 
@@ -389,7 +384,7 @@ void PeerInteractionCommand::sendMessages() {
     }
   }
 
-  sendMessageQueue->send();
+  sendMessageQueue->send(e->getUploadSpeed());
 }
 
 void PeerInteractionCommand::onAbort(Exception* ex) {

+ 5 - 5
src/PendingMessage.cc

@@ -33,15 +33,15 @@ bool PendingMessage::processMessage() {
     peerConnection->sendBitfield();
     break;
   case PeerMessage::UNCHOKE:
-    if(peerConnection->getPeer()->amChocking) {
+    if(peerConnection->getPeer()->amChoking) {
       peerConnection->sendUnchoke();
-      peerConnection->getPeer()->amChocking = false;
+      peerConnection->getPeer()->amChoking = false;
     }
     break;
   case PeerMessage::CHOKE:
-    if(!peerConnection->getPeer()->amChocking) {
+    if(!peerConnection->getPeer()->amChoking) {
       peerConnection->sendChoke();
-      peerConnection->getPeer()->amChocking = true;
+      peerConnection->getPeer()->amChoking = true;
     }
     break;
   case PeerMessage::NOT_INTERESTED:
@@ -57,7 +57,7 @@ bool PendingMessage::processMessage() {
     }
     break;
   case PeerMessage::PIECE:
-    if((!peerConnection->getPeer()->amChocking &&
+    if((!peerConnection->getPeer()->amChoking &&
 	peerConnection->getPeer()->peerInterested) || inProgress) {
       if(!inProgress) {
 	peerConnection->sendPieceHeader(index, begin, length);

+ 16 - 7
src/SendMessageQueue.cc

@@ -24,7 +24,7 @@
 
 SendMessageQueue::SendMessageQueue(int cuid, PeerConnection* peerConnection,
 				   TorrentMan* torrentMan)
-  :cuid(cuid) {
+  :cuid(cuid), uploadLimit(0) {
   requestSlotMan = new RequestSlotMan(cuid, &pendingMessages, peerConnection,
 				      torrentMan);
   logger = LogFactory::getInstance();
@@ -34,15 +34,24 @@ SendMessageQueue::~SendMessageQueue() {
   delete requestSlotMan;
 }
 
-void SendMessageQueue::send() {
-  for(PendingMessages::iterator itr = pendingMessages.begin();
-      itr != pendingMessages.end();) {
-    if(itr->processMessage()) {
-      itr = pendingMessages.erase(itr);
+void SendMessageQueue::send(int uploadSpeed) {
+  //logger->debug("SendMessageQueue:send start");
+  int size = pendingMessages.size();
+  for(int i = 0; i < size; i++) {
+    PendingMessage msg = pendingMessages.front();
+    pendingMessages.pop_front();
+    if(uploadLimit != 0 && uploadSpeed >= uploadLimit*1024 &&
+       msg.getPeerMessageId() == PeerMessage::PIECE && !msg.isInProgress()) {
+      //logger->debug("upload speed limiter enabled, uploadSpeed=%d", uploadSpeed);
+      pendingMessages.push_back(msg);
     } else {
-      break;
+      if(!msg.processMessage()) {
+	pendingMessages.push_front(msg);
+	break;
+      }
     }
   }
+  //logger->debug("SendMessageQueue:send end");
 }
 
 void SendMessageQueue::addPendingMessage(const PendingMessage& pendingMessage) {

+ 6 - 1
src/SendMessageQueue.h

@@ -31,12 +31,14 @@ private:
   RequestSlotMan* requestSlotMan;
   PendingMessages pendingMessages;
   const Logger* logger;
+  // upload speed limit(byte/sec)
+  int uploadLimit;
 public:
   SendMessageQueue(int cuid, PeerConnection* peerConnection,
 		   TorrentMan* torrentMan);
   ~SendMessageQueue();
 
-  void send();
+  void send(int uploadSpeed);
 
   void addPendingMessage(const PendingMessage& pendingMessage);
   void deletePendingPieceMessage(const PeerMessage* cancelMessage);
@@ -52,6 +54,9 @@ public:
 
   int countPendingMessage() const;
   int countRequestSlot() const;
+
+  void setUploadLimit(int uploadLimit) { this->uploadLimit = uploadLimit; }
+  int getUploadLimit() const { return this->uploadLimit; }
 };
 
 #endif // _D_SEND_MESSAGE_QUEUE_H_

+ 1 - 78
src/TorrentConsoleDownloadEngine.cc

@@ -31,7 +31,7 @@ void TorrentConsoleDownloadEngine::onSelectiveDownloadingCompletes() {
   fflush(stdout);
 }
 
-void TorrentConsoleDownloadEngine::printStatistics() {
+void TorrentConsoleDownloadEngine::sendStatistics() {
   printf("\r                                                                             ");
   printf("\r");
   if(torrentMan->downloadComplete()) {
@@ -51,80 +51,3 @@ void TorrentConsoleDownloadEngine::printStatistics() {
 	 torrentMan->connections);
   fflush(stdout);	 
 }
-
-void TorrentConsoleDownloadEngine::initStatistics() {
-  downloadSpeed = 0;
-  uploadSpeed = 0;
-  lastElapsed = 0;
-  gettimeofday(&cp[0], NULL);
-  gettimeofday(&cp[1], NULL);
-  gettimeofday(&startup, NULL);
-  sessionDownloadLengthArray[0] = 0;
-  sessionDownloadLengthArray[1] = 0;
-  sessionUploadLengthArray[0] = 0;
-  sessionUploadLengthArray[1] = 0;
-  currentCp = 0;
-  eta = 0;
-  avgSpeed = 0;
-  sessionDownloadLength = 0;
-  downloadLength = 0;
-  totalLength = 0;
-  if(torrentMan->isSelectiveDownloadingMode()) {
-    selectedDownloadLengthDiff = torrentMan->getDownloadLength()-torrentMan->getCompletedLength();
-    selectedTotalLength = torrentMan->getSelectedTotalLength();
-  }
-}
-
-int TorrentConsoleDownloadEngine::calculateSpeed(long long int sessionLength, int elapsed) {
-  int nowSpeed = (int)(sessionLength/elapsed);
-  return nowSpeed;
-}
-
-void TorrentConsoleDownloadEngine::calculateStatistics() {
-  struct timeval now;
-  gettimeofday(&now, NULL);
-  int elapsed = Util::difftvsec(now, cp[currentCp]);
-
-  sessionDownloadLengthArray[0] += torrentMan->getDeltaDownloadLength();
-  sessionUploadLengthArray[0] += torrentMan->getDeltaUploadLength();
-  sessionDownloadLengthArray[1] += torrentMan->getDeltaDownloadLength();
-  sessionUploadLengthArray[1] += torrentMan->getDeltaUploadLength();
-
-  sessionDownloadLength += torrentMan->getDeltaDownloadLength();
-
-
-  torrentMan->resetDeltaDownloadLength();
-  torrentMan->resetDeltaUploadLength();
-
-  if(torrentMan->isSelectiveDownloadingMode()) {
-    downloadLength = torrentMan->getDownloadLength()-selectedDownloadLengthDiff;
-    totalLength = selectedTotalLength;
-  } else {
-    downloadLength = torrentMan->getDownloadLength();
-    totalLength = torrentMan->getTotalLength();
-  }
-  
-
-  if(elapsed-lastElapsed >= 1) {
-    downloadSpeed = calculateSpeed(sessionDownloadLengthArray[currentCp], elapsed);
-    uploadSpeed = calculateSpeed(sessionUploadLengthArray[currentCp], elapsed);
-    avgSpeed = calculateSpeed(sessionDownloadLength,
-			      Util::difftvsec(now, startup));
-    if(avgSpeed < 0) {
-      avgSpeed = 0;
-    } else if(avgSpeed != 0) {
-      eta = (totalLength-downloadLength)/avgSpeed;
-    }
-
-    printStatistics();
-    lastElapsed = elapsed;
-  }
-
-  if(elapsed > 15) {
-    sessionDownloadLengthArray[currentCp] = 0;
-    sessionUploadLengthArray[currentCp] = 0;
-    cp[currentCp] = now;
-    lastElapsed = 0;
-    currentCp = currentCp ? 0 : 1;
-  }
-}

+ 1 - 26
src/TorrentConsoleDownloadEngine.h

@@ -25,33 +25,8 @@
 #include "TorrentDownloadEngine.h"
 
 class TorrentConsoleDownloadEngine : public TorrentDownloadEngine {
-private:
-  struct timeval cp[2];
-  long long int sessionDownloadLengthArray[2];
-  long long int sessionUploadLengthArray[2];
-  int currentCp;
-
-  int downloadSpeed;
-  int uploadSpeed;
-  int lastElapsed;
-  long long int selectedDownloadLengthDiff;
-  long long int selectedTotalLength;
-  // The time when startup
-  struct timeval startup;
-  // The number of bytes downloaded since startup
-  long long int sessionDownloadLength;
-  // The average speed(bytes per second) since startup
-  int avgSpeed;
-  // The estimated remaining time to complete the download.
-  int eta;
-  long long int downloadLength;
-  long long int totalLength;
-
-  void printStatistics();
-  int calculateSpeed(long long int sessionLength, int elapsed);
 protected:
-  void initStatistics();
-  void calculateStatistics();
+  virtual void sendStatistics();
   void onSelectiveDownloadingCompletes();
 public:
   TorrentConsoleDownloadEngine();

+ 78 - 0
src/TorrentDownloadEngine.cc

@@ -20,6 +20,7 @@
  */
 /* copyright --> */
 #include "TorrentDownloadEngine.h"
+#include "Util.h"
 
 void TorrentDownloadEngine::onEndOfRun() {
   torrentMan->diskAdaptor->closeFile();
@@ -42,3 +43,80 @@ void TorrentDownloadEngine::afterEachIteration() {
     }
   }
 }
+
+void TorrentDownloadEngine::initStatistics() {
+  downloadSpeed = 0;
+  uploadSpeed = 0;
+  lastElapsed = 0;
+  gettimeofday(&cp[0], NULL);
+  gettimeofday(&cp[1], NULL);
+  gettimeofday(&startup, NULL);
+  sessionDownloadLengthArray[0] = 0;
+  sessionDownloadLengthArray[1] = 0;
+  sessionUploadLengthArray[0] = 0;
+  sessionUploadLengthArray[1] = 0;
+  currentCp = 0;
+  eta = 0;
+  avgSpeed = 0;
+  sessionDownloadLength = 0;
+  downloadLength = 0;
+  totalLength = 0;
+  if(torrentMan->isSelectiveDownloadingMode()) {
+    selectedDownloadLengthDiff = torrentMan->getDownloadLength()-torrentMan->getCompletedLength();
+    selectedTotalLength = torrentMan->getSelectedTotalLength();
+  }
+}
+
+int TorrentDownloadEngine::calculateSpeed(long long int sessionLength, int elapsed) {
+  int nowSpeed = (int)(sessionLength/elapsed);
+  return nowSpeed;
+}
+
+void TorrentDownloadEngine::calculateStatistics() {
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  int elapsed = Util::difftvsec(now, cp[currentCp]);
+
+  sessionDownloadLengthArray[0] += torrentMan->getDeltaDownloadLength();
+  sessionUploadLengthArray[0] += torrentMan->getDeltaUploadLength();
+  sessionDownloadLengthArray[1] += torrentMan->getDeltaDownloadLength();
+  sessionUploadLengthArray[1] += torrentMan->getDeltaUploadLength();
+
+  sessionDownloadLength += torrentMan->getDeltaDownloadLength();
+
+
+  torrentMan->resetDeltaDownloadLength();
+  torrentMan->resetDeltaUploadLength();
+
+  if(torrentMan->isSelectiveDownloadingMode()) {
+    downloadLength = torrentMan->getDownloadLength()-selectedDownloadLengthDiff;
+    totalLength = selectedTotalLength;
+  } else {
+    downloadLength = torrentMan->getDownloadLength();
+    totalLength = torrentMan->getTotalLength();
+  }
+  
+
+  if(elapsed-lastElapsed >= 1) {
+    downloadSpeed = calculateSpeed(sessionDownloadLengthArray[currentCp], elapsed);
+    uploadSpeed = calculateSpeed(sessionUploadLengthArray[currentCp], elapsed);
+    avgSpeed = calculateSpeed(sessionDownloadLength,
+			      Util::difftvsec(now, startup));
+    if(avgSpeed < 0) {
+      avgSpeed = 0;
+    } else if(avgSpeed != 0) {
+      eta = (totalLength-downloadLength)/avgSpeed;
+    }
+
+    sendStatistics();
+    lastElapsed = elapsed;
+  }
+
+  if(elapsed > 15) {
+    sessionDownloadLengthArray[currentCp] = 0;
+    sessionUploadLengthArray[currentCp] = 0;
+    cp[currentCp] = now;
+    lastElapsed = 0;
+    currentCp = currentCp ? 0 : 1;
+  }
+}

+ 29 - 0
src/TorrentDownloadEngine.h

@@ -28,10 +28,36 @@
 class TorrentDownloadEngine : public DownloadEngine {
 private:
   bool filenameFixed;
+
+  void initStatistics();
+  void calculateStatistics();
 protected:
+  struct timeval cp[2];
+  long long int sessionDownloadLengthArray[2];
+  long long int sessionUploadLengthArray[2];
+  int currentCp;
+
+  int downloadSpeed;
+  int uploadSpeed;
+  int lastElapsed;
+  long long int selectedDownloadLengthDiff;
+  long long int selectedTotalLength;
+  // The time when startup
+  struct timeval startup;
+  // The number of bytes downloaded since startup
+  long long int sessionDownloadLength;
+  // The average speed(bytes per second) since startup
+  int avgSpeed;
+  // The estimated remaining time to complete the download.
+  int eta;
+  long long int downloadLength;
+  long long int totalLength;
+
+  int calculateSpeed(long long int sessionLength, int elapsed);
   void onEndOfRun();
   void afterEachIteration();
   virtual void onSelectiveDownloadingCompletes() = 0;
+  virtual void sendStatistics() = 0;
 public:
   TorrentDownloadEngine():filenameFixed(false) {}
   virtual ~TorrentDownloadEngine() {}
@@ -39,6 +65,9 @@ public:
   TorrentMan* torrentMan;
 
   bool isFilenameFixed() const { return filenameFixed; }
+
+  // returns uploading speed in byte/sec.
+  int getUploadSpeed() const { return uploadSpeed; }
 };
 
 #endif // _D_TORRENT_DOWNLOAD_ENGINE_H_

+ 28 - 3
src/TorrentMan.cc

@@ -72,6 +72,7 @@ void TorrentMan::updatePeers(const Peers& peers) {
 }
 
 bool TorrentMan::addPeer(Peer* peer, bool duplicate) {
+  deleteOldErrorPeers(MAX_PEER_LIST_SIZE);
   if(duplicate) {
     for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
       Peer* p = *itr;
@@ -80,7 +81,6 @@ bool TorrentMan::addPeer(Peer* peer, bool duplicate) {
       }
     }
   } else {
-    deleteOldErrorPeers(MAX_PEER_LIST_SIZE);
     for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
       Peer* p = *itr;
       if(p->ipaddr == peer->ipaddr && p->port == peer->port) {
@@ -129,6 +129,9 @@ int TorrentMan::deleteOldErrorPeers(int maxNum) {
 }
 
 Peer* TorrentMan::getPeer() const {
+  if(connections > MAX_PEER_UPDATE) {
+    return Peer::nullPeer;
+  }
   for(Peers::const_iterator itr = peers.begin(); itr != peers.end(); itr++) {
     Peer* p = *itr;
     if(p->cuid == 0 && p->error < MAX_PEER_ERROR) {
@@ -350,7 +353,7 @@ void TorrentMan::readFileEntry(FileEntries& fileEntries, Directory** pTopDir, co
   }
 }
 
-void TorrentMan::setup(const string& metaInfoFile, const Strings& targetFilePaths) {
+void TorrentMan::setupInternal1(const string& metaInfoFile) {
   peerId = "-A2****-";
   for(int i = 0; i < 12; i++) {
     peerId += Util::itos((int)(((double)10)*random()/(RAND_MAX+1.0)));
@@ -400,7 +403,9 @@ void TorrentMan::setup(const string& metaInfoFile, const Strings& targetFilePath
   diskAdaptor->setStoreDir(storeDir);
   diskAdaptor->setTopDir(topDir);
   diskAdaptor->setFileEntries(fileEntries);
-  setFileFilter(targetFilePaths);
+}
+
+void TorrentMan::setupInternal2() {
   if(segmentFileExists()) {
     load();
     diskAdaptor->openExistingFile();
@@ -410,6 +415,26 @@ void TorrentMan::setup(const string& metaInfoFile, const Strings& targetFilePath
   setupComplete = true;
 }
 
+void TorrentMan::setup(const string& metaInfoFile, const Integers& targetFileIndexes) {
+  setupInternal1(metaInfoFile);
+  Strings targetFilePaths;
+  const FileEntries& entries = diskAdaptor->getFileEntries();
+  for(int i = 0; i < (int)entries.size(); i++) {
+    if(find(targetFileIndexes.begin(), targetFileIndexes.end(), i+1) != targetFileIndexes.end()) {
+      logger->debug("index=%d is %s", i+1, entries.at(i).path.c_str());
+      targetFilePaths.push_back(entries.at(i).path);
+    }
+  }
+  setFileFilter(targetFilePaths);
+  setupInternal2();
+}
+
+void TorrentMan::setup(const string& metaInfoFile, const Strings& targetFilePaths) {
+  setupInternal1(metaInfoFile);
+  setFileFilter(targetFilePaths);
+  setupInternal2();
+}
+
 void TorrentMan::setFileFilter(const Strings& filePaths) {
   if(fileMode != MULTI || filePaths.empty()) {
     return;

+ 16 - 0
src/TorrentMan.h

@@ -36,6 +36,7 @@
 #include <deque>
 #include <map>
 #include <string>
+#include <algorithm>
 
 using namespace std;
 
@@ -75,6 +76,7 @@ private:
   UsedPieces usedPieces;
   bool setupComplete;
   const Logger* logger;
+  Peers activePeers;
 
   FILE* openSegFile(const string& segFilename, const string& mode) const;
   void read(FILE* file);
@@ -86,6 +88,8 @@ private:
   void reduceUsedPieces(int max);
   void readFileEntry(FileEntries& fileEntries, Directory** pTopDir, const Dictionary* infoDic, const string& defaultName);
   void setFileFilter(const Strings& filePaths);
+  void setupInternal1(const string& metaInfoFile);
+  void setupInternal2();
 public:
   int pieceLength;
   int pieces;
@@ -142,6 +146,7 @@ public:
   }
 
   void setup(const string& metaInfoFile, const Strings& targetFilePaths);
+  void setup(const string& metaInfoFile, const Integers& targetFileIndexes);
 
   string getPieceHash(int index) const;
 
@@ -232,6 +237,17 @@ public:
 
   void onDownloadComplete();
 
+  void addActivePeer(Peer* peer) {
+    activePeers.push_back(peer);
+  }
+
+  Peers& getActivePeers() { return this->activePeers; }
+
+  void deleteActivePeer(Peer* peer) {
+    Peers::iterator itr = find(activePeers.begin(), activePeers.end(), peer);
+    activePeers.erase(itr);
+  }
+
   enum FILE_MODE {
     SINGLE,
     MULTI

+ 47 - 0
src/Util.cc

@@ -295,3 +295,50 @@ int Util::expandBuffer(char** pbuf, int curLength, int newLength) {
   *pbuf = newbuf;
   return newLength;
 }
+
+int getNum(const char* buf, int offset, int length) {
+  char* temp = new char[length+1];
+  memcpy(temp, buf+offset, length);
+  temp[length] = '\0';
+  int x = strtol(temp, NULL, 10);
+  delete [] temp;
+  return x;
+}
+
+void unfoldSubRange(const string& src, Integers& range) {
+  if(src.empty()) {
+    return;
+  }
+  string::size_type p = src.find_first_of(",-");
+  if(p == 0) {
+    return;
+  } else if(p == string::npos) {
+    range.push_back(atoi(src.c_str()));
+  } else {
+    if(src.at(p) == ',') {
+      int num = getNum(src.c_str(), 0, p);
+      range.push_back(num);
+      unfoldSubRange(src.substr(p+1), range);
+    } else if(src.at(p) == '-') {
+      int rightNumBegin = p+1;
+      string::size_type nextDelim = src.find_first_of(",", rightNumBegin);
+      if(nextDelim == string::npos) {
+	nextDelim = src.size();
+      }
+      int left = getNum(src.c_str(), 0, p);
+      int right = getNum(src.c_str(), rightNumBegin, nextDelim-rightNumBegin);
+      for(int i = left; i <= right; i++) {
+	range.push_back(i);
+      }
+      if(src.size() > nextDelim) {
+	unfoldSubRange(src.substr(nextDelim+1), range);
+      }
+    }
+  }
+}
+
+void Util::unfoldRange(const string& src, Integers& range) {
+  unfoldSubRange(src, range);
+  sort(range.begin(), range.end());
+  range.erase(unique(range.begin(), range.end()), range.end());
+}

+ 2 - 0
src/Util.h

@@ -73,6 +73,8 @@ public:
   static string secfmt(int sec);
 
   static int expandBuffer(char** pbuf, int curLength, int newLength);
+
+  static void unfoldRange(const string& src, Integers& range);
 };
 
 #endif // _D_UTIL_H_

+ 1 - 0
src/common.h

@@ -48,5 +48,6 @@
 using namespace std;
 
 typedef deque<string> Strings;
+typedef deque<int> Integers;
 
 #endif // _D_COMMON_H_

+ 47 - 14
src/main.cc

@@ -36,6 +36,7 @@
 #include "TrackerWatcherCommand.h"
 #include "TrackerUpdateCommand.h"
 #include "ByteArrayDiskWriter.h"
+#include "PeerChokeCommand.h"
 #include <deque>
 #include <algorithm>
 #include <time.h>
@@ -207,7 +208,15 @@ void showUsage() {
   cout << _(" --direct-file-mapping=true|false Directly read from and write to each file\n"
 	    "                              mentioned in .torrent file.\n"
 	    "                              Default: true") << endl;
-  cout << _(" --listen-port                Set port number to listen to for peer connection.") << endl;
+  cout << _(" --listen-port=PORT           Set port number to listen to for peer connection.") << endl;
+  cout << _(" --upload-limit=SPEED         Set upload speed limit in KB/sec. aria2 tries to\n"
+	    "                              keep upload speed under SPEED. 0 means unlimited.") << endl;
+  cout << _(" --select-file=INDEX...       Set file to download by specifing its index.\n"
+	    "                              You can know file index through --show-files\n"
+	    "                              option. Multiple indexes can be specified by using\n"
+	    "                              ',' like \"3,6\".\n"
+	    "                              You can also use '-' to specify rangelike \"1-5\".\n"
+	    "                              ',' and '-' can be used together.\n") << endl;
 #endif // ENABLE_BITTORRENT
   cout << _(" -v, --version                Print the version number and exit.") << endl;
   cout << _(" -h, --help                   Print this message and exit.") << endl;
@@ -219,7 +228,7 @@ void showUsage() {
 #ifdef ENABLE_BITTORRENT
   cout << "FILE:" << endl;
   cout << _(" Specify files in multi-file torrent to download. Use conjunction with\n"
-	    " -T option.") << endl;
+	    " -T option. This arguments are ignored if you specify --select-file option.") << endl;
   cout << endl;
 #endif // ENABLE_BITTORRENT
   cout << _("Examples:") << endl;
@@ -262,7 +271,7 @@ int main(int argc, char* argv[]) {
   string referer;
   string torrentFile;
   int listenPort = -1;
-  Strings args;
+  Integers selectFileIndexes;
 #ifdef ENABLE_BITTORRENT
   bool followTorrent = true;
 #else
@@ -284,7 +293,7 @@ int main(int argc, char* argv[]) {
   op->put(PREF_FTP_VIA_HTTP_PROXY, V_TUNNEL);
   op->put(PREF_AUTO_SAVE_INTERVAL, "60");
   op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE);
-
+  op->put(PREF_UPLOAD_LIMIT, "0");
   while(1) {
     int optIndex = 0;
     int lopt;
@@ -318,6 +327,8 @@ int main(int argc, char* argv[]) {
       { "show-files", no_argument, NULL, 'S' },
       { "no-preallocation", no_argument, &lopt, 18 },
       { "direct-file-mapping", required_argument, &lopt, 19 },
+      { "upload-limit", required_argument, &lopt, 20 },
+      { "select-file", required_argument, &lopt, 21 },
 #endif // ENABLE_BITTORRENT
       { "version", no_argument, NULL, 'v' },
       { "help", no_argument, NULL, 'h' },
@@ -460,10 +471,24 @@ int main(int argc, char* argv[]) {
 	} else if(string(optarg) == "false") {
 	  op->put(PREF_DIRECT_FILE_MAPPING, V_FALSE);
 	} else {
-	  cerr << "direct-file-mapping must be either 'true' or 'false'." << endl;
+	  cerr << _("direct-file-mapping must be either 'true' or 'false'.") << endl;
+	  showUsage();
+	  exit(1);
+	}
+	break;
+      case 20: {
+	int uploadSpeed = (int)strtol(optarg, NULL, 10);
+	if(0 > uploadSpeed) {
+	  cerr << _("upload-limit must be grater than or equal to 0.") << endl;
 	  showUsage();
 	  exit(1);
 	}
+	op->put(PREF_UPLOAD_LIMIT, Util::itos(uploadSpeed));
+	break;
+      }
+      case 21:
+	Util::unfoldRange(optarg, selectFileIndexes);
+	break;
       }
       break;
     }
@@ -546,9 +571,7 @@ int main(int argc, char* argv[]) {
     }
   }
   
-  for(int i = 1; optind+i-1 < argc; i++) {
-    args.push_back(argv[optind+i-1]);
-  }
+  Strings args(argv+optind, argv+argc);
 
 #ifdef HAVE_LIBSSL
   // for SSL initialization
@@ -646,18 +669,26 @@ int main(int argc, char* argv[]) {
 	FileEntries fileEntries =
 	  te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile);
 	cout << _("Files:") << endl;
+	cout << "idx|path/length" << endl;
+	cout << "===============================================================================" << endl;
+	int count = 1;
 	for(FileEntries::const_iterator itr = fileEntries.begin();
-	    itr != fileEntries.end(); itr++) {
-	  printf("%s %s Bytes\n", itr->path.c_str(),
+	    itr != fileEntries.end(); count++, itr++) {
+	  printf("%3d %s\n    %s Bytes\n", count, itr->path.c_str(),
 		 Util::llitos(itr->length, true).c_str());
+	  cout << "-------------------------------------------------------------------------------" << endl;
 	}
 	exit(0);
       } else {
-	Strings targetFiles;
-	if(!torrentFile.empty() && !args.empty()) {
-	  targetFiles = args;
+	if(selectFileIndexes.empty()) {
+	  Strings targetFiles;
+	  if(!torrentFile.empty() && !args.empty()) {
+	    targetFiles = args;
+	  }
+	  te->torrentMan->setup(targetTorrentFile, targetFiles);
+	} else {
+	  te->torrentMan->setup(targetTorrentFile, selectFileIndexes);
 	}
-	te->torrentMan->setup(targetTorrentFile, targetFiles);
       }
       PeerListenCommand* listenCommand =
 	new PeerListenCommand(te->torrentMan->getNewCuid(), te);
@@ -680,6 +711,8 @@ int main(int argc, char* argv[]) {
       te->commands.push(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(),
 						   te,
 						   op->getAsInt(PREF_AUTO_SAVE_INTERVAL)));
+      te->commands.push(new PeerChokeCommand(te->torrentMan->getNewCuid(),
+					     10, te));
       te->run();
       
       if(te->torrentMan->downloadComplete()) {

+ 2 - 0
src/prefs.h

@@ -96,5 +96,7 @@
 #define PREF_NO_PREALLOCATION "no_preallocation"
 // values: true | false
 #define PREF_DIRECT_FILE_MAPPING "direct_file_mapping"
+// values: 1*digit
+#define PREF_UPLOAD_LIMIT "upload_limit"
 
 #endif // _D_PREFS_H_