diff --git a/ChangeLog b/ChangeLog index 5c1ae00a..3c12fe48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,63 @@ +2006-04-19 Tatsuhiro Tsujikawa + + To add a readout of estimated remaining time to normal HTTP/FTP + downloads: + + * src/ConsoleDownloadEngine.h (startup): New variable. + (startupLength): New variable. + (isStartupLengthSet): New variable. + (avgSpeed): New variable. + (eta): New variable. + * src/ConsoleDownloadEngine.cc (sendStatistics): Added a readout of + estimated remaining time. + (initStatistics): Initialized newly added variables. + (calculateStatistics): Calculate average speed and estimated remaining + time. + + To decouple TorrentDownloadEngine from HttpResponseCommand: + + * src/TrackerDownloadCommand.h: Removed. + * src/TrackerDownloadCommand.cc: Removed. + * src/TrackerInitCommand.h: Removed. + * src/TrackerInitCommand.cc: Removed. + * src/TrackerUpdateCommand.h: Removed. + * src/TrackerUpdateCommand.cc: Removed. + * src/TrackerWatcherCommand.cc (execute): The construction of request + url written in TrackerInitCommand was moved here. Do not create + tracker request command if torretnMan->trackers != 0. + * src/CompactTrackerResponseProcessor.h: New class. + * src/CompactTrackerResponseProcessor.cc: New class. + * src/message.h (MSG_TRACKER_WARNING_MESSAGE): Updated. + * src/HttpResponseCommand.cc (createHttpDownloadCommand): + Decoupled TorrentDownloadEngine from this. + * src/SegmentMan.h (init): New function. + * src/SegmentMan.cc (init): New function. + * src/TorrentMan.h (responseProcessor): New variable. + (trackers): New variable. + (setTrackerResponseProcessor): New function. + (getTrackerResponseProcessor): New function. + (processTrackerResponse): New function. + * src/TorrentMan.cc (Constructor): Initialized new variable trackers. + (processTrackerResponse): New function. + * src/main.cc (main): Use ByteArrayDiskWriter and + CompactTrackerResponseProcessor. + * src/TorrentDownloadEngine.cc (afterEachIteration): Call torrentMan-> + processTrackerResponse(). + + * src/TorrentConsoleDownloadEngine.cc (printStatistics): Updated a + readout. + + * src/TorrentDownloadEngine.cc (afterEachIteration): Added log message + which indicates download has completed. + + * src/AbstractDiskWriter.cc (Destructor): fd >= 0, not fd >0 + (closeFile): fd >= 0, not fd > 0 + + * src/main.cc (main): Added short cut for show-files. + Added short cut for torrent-file. + Added new command-line option listen-port. + Updated i18n messages. + 2006-04-18 Tatsuhiro Tsujikawa To add LogFactory which creates singleton logger: diff --git a/README b/README index 69ae313d..7c83feb7 100644 --- a/README +++ b/README @@ -21,6 +21,7 @@ aria2 is in very early development stage. Currently it has following features: * Cookie support(currently aria2 ignores "expires") * It can run as a daemon process. * BitTorrent protocol support +* Selective download in multi-file torrent 3. How to build --------------- @@ -53,11 +54,22 @@ multi-file mode: The directory to store the top directory of downloaded files can be specified by -d option. -In both mode, aria2 needs at least 2 times more disk space than the file size -itself because it creates complete temporary file. +In the default behavior, before download starts, complete directory structure +is created if needed. Then aria2 opens all files mentioned in .torrent file, +directly writes to and reads from these files. +NOTE: Even in selective download, all files are opened. + +If "--direct-file-mapping" option set to be false, aria2 creates temporary +file in the store directory. The length of this file is the sum of length of +the files in .torrent file, so at least 2 times more disk space than the file +size itself is required. Writing and reading is done against this file. +After download completes, aria2 creates complete directory structure if needed, +and copies whole file or a part of it to the destination. Note: * -o option is used to change the filename of downloaded .torrent file. * This version only supports compact peers list format. * The ports aria2c uses are 6881-6999. * The maximum number of peers is 55. +* After selective download completes, aria2 is going to download rest of the +files. \ No newline at end of file diff --git a/TODO b/TODO index 417e1f9f..b61a54fa 100644 --- a/TODO +++ b/TODO @@ -11,11 +11,10 @@ * Add port range command-line option * Add max peers command-line option * Distinguish seeder from leecher +* Add Mainline-compatible DHT support +* Add Message stream encryption support +* Add announce-list support 0.4.0 release * try to use ftruncate to allocate file. -* add log message when download completes -0.4.1 release -* Add port command-line option -* Add estimated remaining time to normal HTTP/FTP downloading status ouput diff --git a/configure b/configure index e5863671..6bcbcbd6 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.59 for aria2c 0.3.1. +# Generated by GNU Autoconf 2.59 for aria2c 0.4.0. # # Report bugs to . # @@ -269,8 +269,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='aria2c' PACKAGE_TARNAME='aria2c' -PACKAGE_VERSION='0.3.1' -PACKAGE_STRING='aria2c 0.3.1' +PACKAGE_VERSION='0.4.0' +PACKAGE_STRING='aria2c 0.4.0' PACKAGE_BUGREPORT='tujikawa@rednoah.com' ac_unique_file="src/Socket.h" @@ -788,7 +788,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures aria2c 0.3.1 to adapt to many kinds of systems. +\`configure' configures aria2c 0.4.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -854,7 +854,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of aria2c 0.3.1:";; + short | recursive ) echo "Configuration of aria2c 0.4.0:";; esac cat <<\_ACEOF @@ -994,7 +994,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -aria2c configure 0.3.1 +aria2c configure 0.4.0 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -1008,7 +1008,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by aria2c $as_me 0.3.1, which was +It was created by aria2c $as_me 0.4.0, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -1651,7 +1651,7 @@ fi # Define the identity of the package. PACKAGE='aria2c' - VERSION='0.3.1' + VERSION='0.4.0' cat >>confdefs.h <<_ACEOF @@ -11528,7 +11528,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by aria2c $as_me 0.3.1, which was +This file was extended by aria2c $as_me 0.4.0, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -11591,7 +11591,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -aria2c config.status 0.3.1 +aria2c config.status 0.4.0 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.in b/configure.in index 38c28603..0fb98670 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. # AC_PREREQ(2.59) -AC_INIT(aria2c, 0.3.1, tujikawa@rednoah.com) +AC_INIT(aria2c, 0.4.0, tujikawa@rednoah.com) AM_INIT_AUTOMAKE() AM_PATH_CPPUNIT(1.10.2) AC_CONFIG_SRCDIR([src/Socket.h]) diff --git a/po/Makefile.in b/po/Makefile.in index 2fd3f8e5..3c256007 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -9,7 +9,7 @@ # General Public License and is *not* in the public domain. PACKAGE = aria2c -VERSION = 0.3.1 +VERSION = 0.4.0 SHELL = /bin/sh diff --git a/po/aria2c.pot b/po/aria2c.pot index a184808b..84472ae5 100644 --- a/po/aria2c.pot +++ b/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-12 22:55+0900\n" +"POT-Creation-Date: 2006-04-19 02:02+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -177,35 +177,39 @@ msgstr "" msgid "Got EOF from the server." msgstr "" -#: src/main.cc:63 +#: src/main.cc:64 #, c-format msgid "" "\n" "The download was complete. <%s>\n" msgstr "" -#: src/main.cc:67 +#: src/main.cc:72 msgid "" "\n" "The download was not complete because of errors. Check the log.\n" msgstr "" -#: src/main.cc:78 src/main.cc:87 +#: src/main.cc:91 src/main.cc:102 msgid "" "\n" -"SIGINT signal received." +"stopping application...\n" msgstr "" -#: src/main.cc:109 +#: src/main.cc:97 src/main.cc:114 +msgid "done\n" +msgstr "" + +#: src/main.cc:125 #, c-format msgid "Unrecognized URL or unsupported protocol: %s\n" msgstr "" -#: src/main.cc:115 +#: src/main.cc:131 msgid " version " msgstr "" -#: src/main.cc:119 +#: src/main.cc:135 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" @@ -222,40 +226,45 @@ msgid "" "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" msgstr "" -#: src/main.cc:133 +#: src/main.cc:149 #, c-format msgid "Contact Info: %s\n" msgstr "" -#: src/main.cc:139 +#: src/main.cc:155 #, c-format msgid "Usage: %s [options] URL ...\n" msgstr "" -#: src/main.cc:141 +#: src/main.cc:156 +#, c-format +msgid " %s [options] -T TORRENT_FILE FILE ...\n" +msgstr "" + +#: src/main.cc:159 msgid "Options:" msgstr "" -#: src/main.cc:142 +#: src/main.cc:160 msgid " -d, --dir=DIR The directory to store downloaded file." msgstr "" -#: src/main.cc:143 +#: src/main.cc:161 msgid " -o, --out=FILE The file name for downloaded file." msgstr "" -#: src/main.cc:144 +#: src/main.cc:162 msgid "" " -l, --log=LOG The file path to store log. If '-' is " "specified,\n" " log is written to stdout." msgstr "" -#: src/main.cc:146 +#: src/main.cc:164 msgid " -D, --daemon Run as daemon." msgstr "" -#: src/main.cc:147 +#: src/main.cc:165 msgid "" " -s, --split=N Download a file using N connections. N must " "be\n" @@ -265,24 +274,24 @@ msgid "" " N connections." msgstr "" -#: src/main.cc:151 +#: src/main.cc:169 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:154 +#: src/main.cc:172 msgid " -t, --timeout=SEC Set timeout in second. Default: 60" msgstr "" -#: src/main.cc:155 +#: src/main.cc:173 msgid "" " -m, --max-tries=N Set number of tries. 0 means unlimited.\n" " Default: 5" msgstr "" -#: src/main.cc:157 +#: src/main.cc:175 msgid "" " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n" " K or M(1K = 1024, 1M = 1024K). This\n" @@ -290,40 +299,40 @@ msgid "" " 1024." msgstr "" -#: src/main.cc:161 +#: src/main.cc:179 msgid "" " --http-proxy=HOST:PORT Use HTTP proxy server. This affects to all\n" " URLs." msgstr "" -#: src/main.cc:163 +#: src/main.cc:181 msgid " --http-user=USER Set HTTP user. This affects to all URLs." msgstr "" -#: src/main.cc:164 +#: src/main.cc:182 msgid "" " --http-passwd=PASSWD Set HTTP password. This affects to all URLs." msgstr "" -#: src/main.cc:165 +#: src/main.cc:183 msgid "" " --http-proxy-user=USER Set HTTP proxy user. This affects to all URLs" msgstr "" -#: src/main.cc:166 +#: src/main.cc:184 msgid "" " --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects to all " "URLs." msgstr "" -#: src/main.cc:167 +#: src/main.cc:185 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:170 +#: src/main.cc:188 msgid "" " --http-auth-scheme=SCHEME Set HTTP authentication scheme. Currently, " "basic\n" @@ -334,23 +343,23 @@ msgid "" " as well as --http-user and --http-passwd." msgstr "" -#: src/main.cc:174 +#: src/main.cc:192 msgid " --referer=REFERER Set Referer. This affects to all URLs." msgstr "" -#: src/main.cc:175 +#: src/main.cc:193 msgid "" " --ftp-user=USER Set FTP user. This affects to all URLs.\n" " Default: anonymous" msgstr "" -#: src/main.cc:177 +#: src/main.cc:195 msgid "" " --ftp-passwd=PASSWD Set FTP password. This affects to all URLs.\n" " Default: ARIA2USER@" msgstr "" -#: src/main.cc:179 +#: src/main.cc:197 msgid "" " --ftp-type=TYPE Set FTP transfer type. TYPE is either " "'binary'\n" @@ -358,11 +367,11 @@ msgid "" " Default: binary" msgstr "" -#: src/main.cc:182 +#: src/main.cc:200 msgid " -p, --ftp-pasv Use passive mode in FTP." msgstr "" -#: src/main.cc:183 +#: src/main.cc:201 msgid "" " --ftp-via-http-proxy=METHOD Use HTTP proxy in FTP. METHOD is either 'get' " "or\n" @@ -370,11 +379,11 @@ msgid "" " Default: tunnel" msgstr "" -#: src/main.cc:187 -msgid " --torrent-file=TORRENT_FILE The file path to .torrent file." +#: src/main.cc:205 +msgid " -T, --torrent-file=TORRENT_FILE The file path to .torrent file." msgstr "" -#: src/main.cc:188 +#: src/main.cc:206 msgid "" " --follow-torrent=true|false Setting this option to false prevents aria2 " "to\n" @@ -383,97 +392,142 @@ msgid "" " Default: true" msgstr "" -#: src/main.cc:193 +#: src/main.cc:210 +msgid "" +" -S, --show-files Print the file listing in .torrent file and " +"exit." +msgstr "" + +#: src/main.cc:211 +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:214 +msgid "" +" --listen-port Set port number to listen to for peer " +"connection." +msgstr "" + +#: src/main.cc:216 msgid " -v, --version Print the version number and exit." msgstr "" -#: src/main.cc:194 +#: src/main.cc:217 msgid " -h, --help Print this message and exit." msgstr "" -#: src/main.cc:197 +#: src/main.cc:220 msgid "" " You can specify multiple URLs. All URLs must point to the same file\n" " or downloading fails." msgstr "" -#: src/main.cc:200 +#: src/main.cc:224 +msgid "" +" Specify files in multi-file torrent to download. Use conjunction with\n" +" -T option." +msgstr "" + +#: src/main.cc:227 msgid "Examples:" msgstr "" -#: src/main.cc:201 +#: src/main.cc:228 msgid " Download a file by 1 connection:" msgstr "" -#: src/main.cc:203 +#: src/main.cc:230 msgid " Download a file by 2 connections:" msgstr "" -#: src/main.cc:205 +#: src/main.cc:232 msgid " Download a file by 2 connections, each connects to a different server:" msgstr "" -#: src/main.cc:207 +#: src/main.cc:234 msgid " You can mix up different protocols:" msgstr "" -#: src/main.cc:210 +#: src/main.cc:237 msgid " Download a torrent:" msgstr "" -#: src/main.cc:212 +#: src/main.cc:239 msgid " Download a torrent using local .torrent file:" msgstr "" -#: src/main.cc:216 -#, c-format -msgid "Reports bugs to %s" +#: src/main.cc:241 +msgid " Download only selected files:" msgstr "" -#: src/main.cc:307 +#: src/main.cc:245 +#, c-format +msgid "Report bugs to %s" +msgstr "" + +#: src/main.cc:338 msgid "unrecognized proxy format" msgstr "" -#: src/main.cc:333 +#: src/main.cc:364 msgid "Currently, supported authentication scheme is basic." msgstr "" -#: src/main.cc:342 +#: src/main.cc:373 msgid "retry-wait must be between 0 and 60." msgstr "" -#: src/main.cc:359 +#: src/main.cc:390 msgid "ftp-type must be either 'binary' or 'ascii'." msgstr "" -#: src/main.cc:368 +#: src/main.cc:399 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'." msgstr "" -#: src/main.cc:386 +#: src/main.cc:417 msgid "min-segment-size invalid" msgstr "" -#: src/main.cc:397 +#: src/main.cc:428 msgid "http-proxy-method must be either 'get' or 'tunnel'." msgstr "" -#: src/main.cc:411 +#: src/main.cc:436 +msgid "listen-port must be between 1024 and 65535." +msgstr "" + +#: src/main.cc:447 msgid "follow-torrent must be either 'true' or 'false'." msgstr "" -#: src/main.cc:454 +#: src/main.cc:487 msgid "split must be between 1 and 5." msgstr "" -#: src/main.cc:464 +#: src/main.cc:497 msgid "timeout must be between 1 and 600" msgstr "" -#: src/main.cc:473 +#: src/main.cc:506 msgid "max-tries invalid" msgstr "" -#: src/main.cc:496 +#: src/main.cc:535 msgid "specify at least one URL" msgstr "" + +#: src/main.cc:542 +msgid "daemon failed" +msgstr "" + +#: src/main.cc:640 +msgid "Files:" +msgstr "" + +#: src/main.cc:663 +msgid "Errors occurred while binding port.\n" +msgstr "" diff --git a/po/ja.gmo b/po/ja.gmo index 6767515c..0404b471 100644 Binary files a/po/ja.gmo and b/po/ja.gmo differ diff --git a/po/ja.po b/po/ja.po index aec0f185..193d20ca 100644 --- a/po/ja.po +++ b/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-12 22:55+0900\n" -"PO-Revision-Date: 2006-03-22 00:48+0900\n" +"POT-Creation-Date: 2006-04-19 02:02+0900\n" +"PO-Revision-Date: 2006-04-19 02:03+0900\n" "Last-Translator: Tatsuhiro Tsujikawa \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" @@ -185,7 +185,7 @@ msgstr " msgid "Got EOF from the server." msgstr "サーバーから EOF を受けとりました." -#: src/main.cc:63 +#: src/main.cc:64 #, c-format msgid "" "\n" @@ -194,7 +194,7 @@ msgstr "" "\n" "<%s> のダウンロードが完了しました.\n" -#: src/main.cc:67 +#: src/main.cc:72 msgid "" "\n" "The download was not complete because of errors. Check the log.\n" @@ -202,26 +202,30 @@ msgstr "" "\n" "ダウンロードはエラーのため完了していません. ログを確認してください.\n" -#: src/main.cc:78 src/main.cc:87 +#: src/main.cc:91 src/main.cc:102 msgid "" "\n" -"SIGINT signal received." +"stopping application...\n" msgstr "" "\n" -"SIGINT シグナルを受け取りました." +"アプリケーションを終了しています...\n" -#: src/main.cc:109 +#: src/main.cc:97 src/main.cc:114 +msgid "done\n" +msgstr "完了\n" + +#: src/main.cc:125 #, c-format msgid "Unrecognized URL or unsupported protocol: %s\n" msgstr "" "%s は, 理解できない URL フォーマット, または, サポートされないプロトコルで" "す.\n" -#: src/main.cc:115 +#: src/main.cc:131 msgid " version " msgstr " バージョン " -#: src/main.cc:119 +#: src/main.cc:135 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" @@ -252,31 +256,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:133 +#: src/main.cc:149 #, c-format msgid "Contact Info: %s\n" msgstr "連絡先: %s\n" -#: src/main.cc:139 +#: src/main.cc:155 #, c-format msgid "Usage: %s [options] URL ...\n" msgstr "使い方: %s [オプション] URL ...\n" -#: src/main.cc:141 +#: src/main.cc:156 +#, c-format +msgid " %s [options] -T TORRENT_FILE FILE ...\n" +msgstr " %s [オプション] -T TORRENT_FILE FILE ...\n" + +#: src/main.cc:159 msgid "Options:" msgstr "オプション:" -#: src/main.cc:142 +#: src/main.cc:160 msgid " -d, --dir=DIR The directory to store downloaded file." msgstr "" " -d, --dir=DIR ダウンロードしたファイルを保存するディレクトリ." -#: src/main.cc:143 +#: src/main.cc:161 msgid " -o, --out=FILE The file name for downloaded file." msgstr "" " -o, --out=FILE ダウンロードしたファイルの保存先ファイル名." -#: src/main.cc:144 +#: src/main.cc:162 msgid "" " -l, --log=LOG The file path to store log. If '-' is " "specified,\n" @@ -286,11 +295,11 @@ msgstr "" "力\n" " に出力します." -#: src/main.cc:146 +#: src/main.cc:164 msgid " -D, --daemon Run as daemon." msgstr " -D, --daemon デーモンとして起動します." -#: src/main.cc:147 +#: src/main.cc:165 msgid "" " -s, --split=N Download a file using N connections. N must " "be\n" @@ -309,7 +318,7 @@ msgstr "" "ショ\n" " ンを確立します." -#: src/main.cc:151 +#: src/main.cc:169 msgid "" " --retry-wait=SEC Set amount of time in second between requests\n" " for errors. Specify a value between 0 and 60.\n" @@ -320,13 +329,13 @@ msgstr "" " す. 0 - 60 の値を指定してください.\n" " デフォルト値: 5" -#: src/main.cc:154 +#: src/main.cc:172 msgid " -t, --timeout=SEC Set timeout in second. Default: 60" msgstr "" " -t, --timeout=SEC タイムアウトとなる時間を秒で指定します.\n" " デフォルト値: 60" -#: src/main.cc:155 +#: src/main.cc:173 msgid "" " -m, --max-tries=N Set number of tries. 0 means unlimited.\n" " Default: 5" @@ -335,7 +344,7 @@ msgstr "" "行\n" " します. デフォルト値: 5" -#: src/main.cc:157 +#: src/main.cc:175 msgid "" " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n" " K or M(1K = 1024, 1M = 1024K). This\n" @@ -348,7 +357,7 @@ msgstr "" "1024K).\n" " 1024 以上の値を指定してください." -#: src/main.cc:161 +#: src/main.cc:179 msgid "" " --http-proxy=HOST:PORT Use HTTP proxy server. This affects to all\n" " URLs." @@ -357,14 +366,14 @@ msgstr "" "シ\n" " ョンはすべての URL に影響します." -#: src/main.cc:163 +#: src/main.cc:181 msgid " --http-user=USER Set HTTP user. This affects to all URLs." msgstr "" " --http-user=USER HTTP での認証ユーザーを指定します. このオプショ" "ン\n" " はすべての URL に影響します." -#: src/main.cc:164 +#: src/main.cc:182 msgid "" " --http-passwd=PASSWD Set HTTP password. This affects to all URLs." msgstr "" @@ -372,7 +381,7 @@ msgstr "" "ショ\n" " ンはすべての URL に影響します." -#: src/main.cc:165 +#: src/main.cc:183 msgid "" " --http-proxy-user=USER Set HTTP proxy user. This affects to all URLs" msgstr "" @@ -382,7 +391,7 @@ msgstr "" "ま\n" " す." -#: src/main.cc:166 +#: src/main.cc:184 msgid "" " --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects to all " "URLs." @@ -393,7 +402,7 @@ msgstr "" "し\n" " ます." -#: src/main.cc:167 +#: src/main.cc:185 msgid "" " --http-proxy-method=METHOD Set the method to use in proxy request.\n" " METHOD is either 'get' or 'tunnel'.\n" @@ -404,7 +413,7 @@ msgstr "" " す. 'get' または 'tunnel' を指定してください.\n" " デフォルト値: tunnel" -#: src/main.cc:170 +#: src/main.cc:188 msgid "" " --http-auth-scheme=SCHEME Set HTTP authentication scheme. Currently, " "basic\n" @@ -422,14 +431,14 @@ msgstr "" "定\n" " する必要があります." -#: src/main.cc:174 +#: src/main.cc:192 msgid " --referer=REFERER Set Referer. This affects to all URLs." msgstr "" " --referer=REFERER リファラーを指定します. このオプションはすべて" "の\n" " URL に影響します." -#: src/main.cc:175 +#: src/main.cc:193 msgid "" " --ftp-user=USER Set FTP user. This affects to all URLs.\n" " Default: anonymous" @@ -439,7 +448,7 @@ msgstr "" " はすべての URL に影響します.\n" " デフォルト値: anonymous" -#: src/main.cc:177 +#: src/main.cc:195 msgid "" " --ftp-passwd=PASSWD Set FTP password. This affects to all URLs.\n" " Default: ARIA2USER@" @@ -449,7 +458,7 @@ msgstr "" " ンはすべての URL に影響します.\n" " デフォルト値: ARIA2USER@" -#: src/main.cc:179 +#: src/main.cc:197 msgid "" " --ftp-type=TYPE Set FTP transfer type. TYPE is either " "'binary'\n" @@ -460,11 +469,11 @@ msgstr "" " 'ascii' を指定してください. デフォルト値: " "binary" -#: src/main.cc:182 +#: src/main.cc:200 msgid " -p, --ftp-pasv Use passive mode in FTP." msgstr " -p, --ftp-pasv FTP で passive モードを使用します." -#: src/main.cc:183 +#: src/main.cc:201 msgid "" " --ftp-via-http-proxy=METHOD Use HTTP proxy in FTP. METHOD is either 'get' " "or\n" @@ -477,11 +486,11 @@ msgstr "" "く\n" " ださい. デフォルト値: tunnel" -#: src/main.cc:187 -msgid " --torrent-file=TORRENT_FILE The file path to .torrent file." -msgstr " --torrent-file=TORRENT_FILE .torrent ファイルのパスを指定." +#: src/main.cc:205 +msgid " -T, --torrent-file=TORRENT_FILE The file path to .torrent file." +msgstr " -T, --torrent-file=TORRENT_FILE .torrent ファイルのパスを指定." -#: src/main.cc:188 +#: src/main.cc:206 msgid "" " --follow-torrent=true|false Setting this option to false prevents aria2 " "to\n" @@ -496,16 +505,43 @@ msgstr "" " は, BitTorrent モードに入りません.\n" " デフォルト値: true" -#: src/main.cc:193 +#: src/main.cc:210 +msgid "" +" -S, --show-files Print the file listing in .torrent file and " +"exit." +msgstr "" +" -S, --show-files .torrent ファイルに記載のファイルリストを出力" +"し\n" +" 終了します." + +#: src/main.cc:211 +msgid "" +" --direct-file-mapping=true|false Directly read from and write to each file\n" +" mentioned in .torrent file.\n" +" Default: true" +msgstr "" +" --direct-file-mapping=true|false .torrent ファイル記載のファイルに直接読み書" +"き\n" +" します.\n" +" デフォルト値: true" + +#: src/main.cc:214 +msgid "" +" --listen-port Set port number to listen to for peer " +"connection." +msgstr "" +" --listen-port ピアからの接続を受け付けるポート番号を指定." + +#: src/main.cc:216 msgid " -v, --version Print the version number and exit." msgstr " -v, --version バージョン番号を表示し, 終了します." -#: src/main.cc:194 +#: src/main.cc:217 msgid " -h, --help Print this message and exit." msgstr "" " -h, --help このヘルプメッセージを表示し, 終了します." -#: src/main.cc:197 +#: src/main.cc:220 msgid "" " You can specify multiple URLs. All URLs must point to the same file\n" " or downloading fails." @@ -514,83 +550,112 @@ msgstr "" "れ\n" " ばなりません. さもなくばダウンロードは失敗します." -#: src/main.cc:200 +#: src/main.cc:224 +msgid "" +" Specify files in multi-file torrent to download. Use conjunction with\n" +" -T option." +msgstr "" +" multi-file torrent のとき, ダウンロードするファイルを指定. -T オプションと共" +"に\n" +" 使用する." + +#: src/main.cc:227 msgid "Examples:" msgstr "例:" -#: src/main.cc:201 +#: src/main.cc:228 msgid " Download a file by 1 connection:" msgstr " 1 コネクションでのダウンロード:" -#: src/main.cc:203 +#: src/main.cc:230 msgid " Download a file by 2 connections:" msgstr " 2 コネクションでのダウンロード:" -#: src/main.cc:205 +#: src/main.cc:232 msgid " Download a file by 2 connections, each connects to a different server:" msgstr " 二つの異なるサーバーに接続してダウンロード:" -#: src/main.cc:207 +#: src/main.cc:234 msgid " You can mix up different protocols:" msgstr " 異なるプロトコルを混合させてダウンロード:" -#: src/main.cc:210 +#: src/main.cc:237 msgid " Download a torrent:" msgstr "torrent をダウンロード:" -#: src/main.cc:212 +#: src/main.cc:239 msgid " Download a torrent using local .torrent file:" msgstr " ローカル .torrent ファイルを使ってダウンロード:" -#: src/main.cc:216 +#: src/main.cc:241 +msgid " Download only selected files:" +msgstr " ファイルを指定してダウンロード:" + +#: src/main.cc:245 #, c-format -msgid "Reports bugs to %s" +msgid "Report bugs to %s" msgstr "バグレポートはこちらへ: %s" -#: src/main.cc:307 +#: src/main.cc:338 msgid "unrecognized proxy format" msgstr "理解できないProxyフォーマットです." -#: src/main.cc:333 +#: src/main.cc:364 msgid "Currently, supported authentication scheme is basic." msgstr "現在サポートされている認証方法は basic です." -#: src/main.cc:342 +#: src/main.cc:373 msgid "retry-wait must be between 0 and 60." msgstr "retry-wait は 0 から 60 の間で指定してください." -#: src/main.cc:359 +#: src/main.cc:390 msgid "ftp-type must be either 'binary' or 'ascii'." msgstr "ftp-type は 'binary' または 'ascii' を指定してください." -#: src/main.cc:368 +#: src/main.cc:399 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'." msgstr "ftp-via-http-proxy は 'get' または 'tunnel' を指定してください." -#: src/main.cc:386 +#: src/main.cc:417 msgid "min-segment-size invalid" msgstr "min-segment-size が不正です." -#: src/main.cc:397 +#: src/main.cc:428 msgid "http-proxy-method must be either 'get' or 'tunnel'." msgstr "http-proxy-method は 'get' または 'tunnel' を指定してください." -#: src/main.cc:411 +#: src/main.cc:436 +msgid "listen-port must be between 1024 and 65535." +msgstr "listen-port は 1024 - 65535 の値を指定してください." + +#: src/main.cc:447 msgid "follow-torrent must be either 'true' or 'false'." msgstr "follow-torrent は 'true' または 'false を指定してください." -#: src/main.cc:454 +#: src/main.cc:487 msgid "split must be between 1 and 5." msgstr "split は 1 - 5 の値を指定してください." -#: src/main.cc:464 +#: src/main.cc:497 msgid "timeout must be between 1 and 600" msgstr "timeout は 1 - 600 の値を指定してください." -#: src/main.cc:473 +#: src/main.cc:506 msgid "max-tries invalid" msgstr "max-tries が不正です." -#: src/main.cc:496 +#: src/main.cc:535 msgid "specify at least one URL" msgstr "一個以上の URL を指定してください." + +#: src/main.cc:542 +msgid "daemon failed" +msgstr "デーモン起動に失敗" + +#: src/main.cc:640 +msgid "Files:" +msgstr "ファイル:" + +#: src/main.cc:663 +msgid "Errors occurred while binding port.\n" +msgstr "ポートをバインド中にエラーが発生しました.\n" diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index 74b35b63..b5199587 100644 --- a/src/AbstractDiskWriter.cc +++ b/src/AbstractDiskWriter.cc @@ -36,7 +36,7 @@ AbstractDiskWriter::AbstractDiskWriter():fd(0) { } AbstractDiskWriter::~AbstractDiskWriter() { - if(fd > 0) { + if(fd >= 0) { close(fd); } #ifdef ENABLE_SHA1DIGEST @@ -54,9 +54,9 @@ void AbstractDiskWriter::openFile(const string& filename) { } void AbstractDiskWriter::closeFile() { - if(fd > 0) { + if(fd >= 0) { close(fd); - fd = 0; + fd = -1; } } diff --git a/src/CompactTrackerResponseProcessor.cc b/src/CompactTrackerResponseProcessor.cc new file mode 100644 index 00000000..52c82301 --- /dev/null +++ b/src/CompactTrackerResponseProcessor.cc @@ -0,0 +1,136 @@ +/* */ +#include "CompactTrackerResponseProcessor.h" +#include "LogFactory.h" +#include "TorrentDownloadEngine.h" +#include "MetaFileUtil.h" +#include "DlAbortEx.h" +#include "message.h" +#include "PeerInitiateConnectionCommand.h" +#include + +CompactTrackerResponseProcessor::CompactTrackerResponseProcessor(ByteArrayDiskWriter* diskWriter, TorrentDownloadEngine* e, Request* req): + diskWriter(diskWriter), + e(e), + req(req) { + logger = LogFactory::getInstance(); +} + +CompactTrackerResponseProcessor::~CompactTrackerResponseProcessor() {} + +void CompactTrackerResponseProcessor::resetTrackerResponse() { + if(e->segmentMan->finished()) { + diskWriter->reset(); + e->segmentMan->init(); + } +} + +void CompactTrackerResponseProcessor::execute() { + MetaEntry* entry = NULL; + try { + entry = MetaFileUtil::bdecoding(diskWriter->getByteArray(), + diskWriter->getByteArrayLength()); + Dictionary* response = (Dictionary*)entry; + Data* failureReason = (Data*)response->get("failure reason"); + if(failureReason != NULL) { + throw new DlAbortEx("Tracker returned failure reason: %s", failureReason->toString().c_str()); + } + Data* warningMessage = (Data*)response->get("warning message"); + if(warningMessage != NULL) { + logger->warn(MSG_TRACKER_WARNING_MESSAGE, warningMessage->toString().c_str()); + } + Data* trackerId = (Data*)response->get("tracker id"); + if(trackerId != NULL) { + e->torrentMan->trackerId = trackerId->toString(); + logger->debug("Tracker ID:%s", e->torrentMan->trackerId.c_str()); + } + Data* interval = (Data*)response->get("interval"); + if(interval != NULL) { + e->torrentMan->interval = interval->toInt(); + logger->debug("interval:%d", e->torrentMan->interval); + } + Data* minInterval = (Data*)response->get("min interval"); + if(minInterval != NULL) { + e->torrentMan->minInterval = minInterval->toInt(); + logger->debug("min interval:%d", e->torrentMan->minInterval); + } + if(e->torrentMan->minInterval > e->torrentMan->interval) { + e->torrentMan->minInterval = e->torrentMan->interval; + } + Data* complete = (Data*)response->get("complete"); + if(complete != NULL) { + e->torrentMan->complete = complete->toInt(); + logger->debug("complete:%d", e->torrentMan->complete); + } + Data* incomplete = (Data*)response->get("incomplete"); + if(incomplete != NULL) { + e->torrentMan->incomplete = incomplete->toInt(); + logger->debug("incomplete:%d", e->torrentMan->incomplete); + } + Data* peers = (Data*)response->get("peers"); + if(peers != NULL) { + for(int i = 0; i < peers->getLen(); i += 6) { + unsigned int ipaddr1 = (unsigned char)*(peers->getData()+i); + unsigned int ipaddr2 = (unsigned char)*(peers->getData()+i+1); + unsigned int ipaddr3 = (unsigned char)*(peers->getData()+i+2); + unsigned int ipaddr4 = (unsigned char)*(peers->getData()+i+3); + unsigned int port = ntohs(*(unsigned short int*)(peers->getData()+i+4)); + char ipaddr[16]; + + snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%d", + ipaddr1, ipaddr2, ipaddr3, ipaddr4); + Peer* peer = new Peer(ipaddr, port, e->torrentMan->pieceLength, + e->torrentMan->getTotalLength()); + if(e->torrentMan->addPeer(peer)) { + logger->debug("adding peer %s:%d", peer->ipaddr.c_str(), peer->port); + } else { + delete peer; + } + } + } else { + logger->info("no peer list received."); + } + while(e->torrentMan->isPeerAvailable() && + e->torrentMan->connections < MAX_PEER_UPDATE) { + Peer* peer = e->torrentMan->getPeer(); + int newCuid = e->torrentMan->getNewCuid(); + peer->cuid = newCuid; + PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e); + e->commands.push(command); + logger->debug("adding new command CUID#%d", newCuid); + } + if(req->getTrackerEvent() == Request::STARTED) { + req->setTrackerEvent(Request::AUTO); + } + } catch(Exception* err) { + logger->error("Error occurred while processing tracker response.", err); + delete(err); + } + if(entry != NULL) { + delete entry; + } + e->torrentMan->trackers = 0; +} + +bool CompactTrackerResponseProcessor::isFeeded() const { + return e->segmentMan->finished(); +} diff --git a/src/TrackerUpdateCommand.h b/src/CompactTrackerResponseProcessor.h similarity index 62% rename from src/TrackerUpdateCommand.h rename to src/CompactTrackerResponseProcessor.h index 7d68a222..43931f03 100644 --- a/src/TrackerUpdateCommand.h +++ b/src/CompactTrackerResponseProcessor.h @@ -19,24 +19,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* copyright --> */ -#ifndef _D_TRACKER_UPDATE_COMMAND_H_ -#define _D_TRACKER_UPDATE_COMMAND_H_ +#ifndef _D_COMPACT_TRACKER_RESPONSE_PROCESSOR_H_ +#define _D_COMPACT_TRACKER_RESPONSE_PROCESSOR_H_ -#include "Command.h" +#include "common.h" +#include "ByteArrayDiskWriter.h" #include "Request.h" -#include "TorrentDownloadEngine.h" -#include "MetaEntry.h" -class TrackerUpdateCommand : public Command { +class TorrentDownloadEngine; +class Logger; + +class CompactTrackerResponseProcessor { private: - Request* req; + ByteArrayDiskWriter* diskWriter; TorrentDownloadEngine* e; - MetaEntry* trackerResponse; + Request* req; + const Logger* logger; public: - TrackerUpdateCommand(int cuid, Request* req, TorrentDownloadEngine* e, MetaEntry* trackerResponse); - ~TrackerUpdateCommand(); + CompactTrackerResponseProcessor(ByteArrayDiskWriter* diskWriter, + TorrentDownloadEngine* e, + Request* req); + ~CompactTrackerResponseProcessor(); - bool execute(); + bool isFeeded() const; + void execute(); + void resetTrackerResponse(); }; -#endif // _D_TRACKER_UPDATE_COMMAND_H_ +#endif // _D_COMPACT_TRACKER_RESPONSE_PROCESSOR_H_ diff --git a/src/ConsoleDownloadEngine.cc b/src/ConsoleDownloadEngine.cc index aa0bac17..3ceba824 100644 --- a/src/ConsoleDownloadEngine.cc +++ b/src/ConsoleDownloadEngine.cc @@ -27,35 +27,55 @@ ConsoleDownloadEngine::ConsoleDownloadEngine() {} ConsoleDownloadEngine::~ConsoleDownloadEngine() {} void ConsoleDownloadEngine::sendStatistics(long long int currentSize, long long int totalSize) { - cout << "\r "; - cout << "\rProgress " << - Util::llitos(currentSize, true) << " Bytes/" << - Util::llitos(totalSize, true) << " Bytes " << - (totalSize == 0 ? 0 : (currentSize*100)/totalSize) << "% " << - speed/1000.0 << "KB/s " << - "(" << commands.size() << " connections)" << flush; + printf("\r "); + printf("\r"); + printf("%s/%s Bytes %d%% %s %.2f KB/s %d connections", + Util::llitos(currentSize, true).c_str(), + Util::llitos(totalSize, true).c_str(), + (totalSize == 0 ? 0 : (int)((currentSize*100)/totalSize)), + avgSpeed == 0 ? "-" : Util::secfmt(eta).c_str(), + speed/1024.0, + commands.size()); + fflush(stdout); } void ConsoleDownloadEngine::initStatistics() { cp.tv_sec = cp.tv_usec = 0; speed = 0; psize = 0; + avgSpeed = 0; + eta = 0; + startupLength = 0; + isStartupLengthSet = false; + gettimeofday(&startup, NULL); } void ConsoleDownloadEngine::calculateStatistics() { long long int dlSize = segmentMan->getDownloadedSize(); + if(!isStartupLengthSet && dlSize > 0) { + startupLength = dlSize; + isStartupLengthSet = true; + } struct timeval now; gettimeofday(&now, NULL); if(cp.tv_sec == 0 && cp.tv_usec == 0) { cp = now; psize = dlSize; } else { - long long int elapsed = Util::difftv(now, cp); - if(elapsed >= 500000) { - int nspeed = (int)((dlSize-psize)/(elapsed/1000000.0)); + int elapsed = Util::difftvsec(now, cp); + if(elapsed >= 1) { + int nspeed = (int)((dlSize-psize)/elapsed); speed = (nspeed+speed)/2; cp = now; psize = dlSize; + + avgSpeed = (int)((dlSize-startupLength)/Util::difftvsec(now, startup)); + if(avgSpeed < 0) { + avgSpeed = 0; + } else if(avgSpeed != 0 && segmentMan->totalSize > 0) { + eta = (segmentMan->totalSize-dlSize)/avgSpeed; + } + sendStatistics(dlSize, segmentMan->totalSize); } } diff --git a/src/ConsoleDownloadEngine.h b/src/ConsoleDownloadEngine.h index 64d787d7..cd986bb1 100644 --- a/src/ConsoleDownloadEngine.h +++ b/src/ConsoleDownloadEngine.h @@ -29,6 +29,15 @@ private: struct timeval cp; long long int psize; int speed; + // The time when startup + struct timeval startup; + // The number of bytes downloaded at startup + long long int startupLength; + bool isStartupLengthSet; + // The average speed(bytes per second) since startup + int avgSpeed; + // The estimated remaining time to complete the download. + int eta; protected: void sendStatistics(long long int currentSize, long long int totalSize); void initStatistics(); diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 7961f34d..dd27ab57 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -26,9 +26,6 @@ #include "HttpInitiateConnectionCommand.h" #include "message.h" #include "Util.h" -#include "TrackerDownloadCommand.h" -// TODO -#include "TorrentDownloadEngine.h" HttpResponseCommand::HttpResponseCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s): AbstractCommand(cuid, req, e, s) { @@ -97,6 +94,7 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) { long long int size = headers.getFirstAsLLInt("Content-Length"); e->segmentMan->totalSize = size; e->segmentMan->isSplittable = false; + e->segmentMan->downloadStarted = true; createHttpDownloadCommand(); return true; } @@ -138,22 +136,17 @@ bool HttpResponseCommand::handleOtherEncoding(string transferEncoding, const Htt } void HttpResponseCommand::createHttpDownloadCommand(string transferEncoding) { - if(!req->isTorrent) { - HttpDownloadCommand* command = new HttpDownloadCommand(cuid, req, e, socket); - TransferEncoding* enc = NULL; - if(transferEncoding.size() && (enc = command->getTransferEncoding(transferEncoding)) == NULL) { - delete(command); - throw new DlAbortEx(EX_TRANSFER_ENCODING_NOT_SUPPORTED, transferEncoding.c_str()); - } else { - if(enc != NULL) { - command->transferEncoding = transferEncoding; - enc->init(); - } - e->commands.push(command); - } + + HttpDownloadCommand* command = new HttpDownloadCommand(cuid, req, e, socket); + TransferEncoding* enc = NULL; + if(transferEncoding.size() && (enc = command->getTransferEncoding(transferEncoding)) == NULL) { + delete(command); + throw new DlAbortEx(EX_TRANSFER_ENCODING_NOT_SUPPORTED, transferEncoding.c_str()); } else { - // TODO - TrackerDownloadCommand* command = new TrackerDownloadCommand(cuid, req, (TorrentDownloadEngine*)e, socket); + if(enc != NULL) { + command->transferEncoding = transferEncoding; + enc->init(); + } e->commands.push(command); } } diff --git a/src/Makefile.am b/src/Makefile.am index 484a49ed..b599564c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,9 +54,6 @@ SRCS = Socket.cc Socket.h\ MetaFileUtil.cc MetaFileUtil.h\ MetaEntryVisitor.h\ ShaVisitor.cc ShaVisitor.h\ - TrackerInitCommand.cc TrackerInitCommand.h\ - TrackerDownloadCommand.cc TrackerDownloadCommand.h\ - TrackerUpdateCommand.cc TrackerUpdateCommand.h\ TorrentMan.cc TorrentMan.h\ PeerConnection.cc PeerConnection.h\ PeerMessageUtil.cc PeerMessageUtil.h\ @@ -85,7 +82,9 @@ SRCS = Socket.cc Socket.h\ DirectDiskAdaptor.cc DirectDiskAdaptor.h\ MultiDiskAdaptor.cc MultiDiskAdaptor.h\ FileEntry.h\ - LogFactory.cc LogFactory.h + LogFactory.cc LogFactory.h\ + CompactTrackerResponseProcessor.cc CompactTrackerResponseProcessor.h\ + ByteArrayDiskWriter.cc ByteArrayDiskWriter.h noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ diff --git a/src/Makefile.in b/src/Makefile.in index 677e1422..58fea880 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -86,10 +86,8 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \ File.$(OBJEXT) Option.$(OBJEXT) Base64.$(OBJEXT) \ CookieBox.$(OBJEXT) Data.$(OBJEXT) Dictionary.$(OBJEXT) \ List.$(OBJEXT) MetaFileUtil.$(OBJEXT) ShaVisitor.$(OBJEXT) \ - TrackerInitCommand.$(OBJEXT) TrackerDownloadCommand.$(OBJEXT) \ - TrackerUpdateCommand.$(OBJEXT) TorrentMan.$(OBJEXT) \ - PeerConnection.$(OBJEXT) PeerMessageUtil.$(OBJEXT) \ - PeerAbstractCommand.$(OBJEXT) \ + TorrentMan.$(OBJEXT) PeerConnection.$(OBJEXT) \ + PeerMessageUtil.$(OBJEXT) PeerAbstractCommand.$(OBJEXT) \ PeerInitiateConnectionCommand.$(OBJEXT) \ PeerInteractionCommand.$(OBJEXT) Peer.$(OBJEXT) \ BitfieldMan.$(OBJEXT) TorrentDownloadEngine.$(OBJEXT) \ @@ -101,7 +99,8 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \ SendMessageQueue.$(OBJEXT) MultiDiskWriter.$(OBJEXT) \ DiskAdaptor.$(OBJEXT) CopyDiskAdaptor.$(OBJEXT) \ DirectDiskAdaptor.$(OBJEXT) MultiDiskAdaptor.$(OBJEXT) \ - LogFactory.$(OBJEXT) + LogFactory.$(OBJEXT) CompactTrackerResponseProcessor.$(OBJEXT) \ + ByteArrayDiskWriter.$(OBJEXT) am_libaria2c_a_OBJECTS = $(am__objects_1) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" @@ -305,9 +304,6 @@ SRCS = Socket.cc Socket.h\ MetaFileUtil.cc MetaFileUtil.h\ MetaEntryVisitor.h\ ShaVisitor.cc ShaVisitor.h\ - TrackerInitCommand.cc TrackerInitCommand.h\ - TrackerDownloadCommand.cc TrackerDownloadCommand.h\ - TrackerUpdateCommand.cc TrackerUpdateCommand.h\ TorrentMan.cc TorrentMan.h\ PeerConnection.cc PeerConnection.h\ PeerMessageUtil.cc PeerMessageUtil.h\ @@ -336,7 +332,9 @@ SRCS = Socket.cc Socket.h\ DirectDiskAdaptor.cc DirectDiskAdaptor.h\ MultiDiskAdaptor.cc MultiDiskAdaptor.h\ FileEntry.h\ - LogFactory.cc LogFactory.h + LogFactory.cc LogFactory.h\ + CompactTrackerResponseProcessor.cc CompactTrackerResponseProcessor.h\ + ByteArrayDiskWriter.cc ByteArrayDiskWriter.h noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) @@ -426,7 +424,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AbstractDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncoding.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompactTrackerResponseProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleDownloadEngine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyDiskAdaptor.Po@am__quote@ @@ -488,9 +488,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentConsoleDownloadEngine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentDownloadEngine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentMan.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerDownloadCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerInitCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerUpdateCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 8dca9306..886b05a8 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -212,3 +212,9 @@ long long int SegmentMan::getDownloadedSize() const { return size; } +void SegmentMan::init() { + totalSize = 0; + isSplittable = false; + downloadStarted = false; + segments.clear(); +} diff --git a/src/SegmentMan.h b/src/SegmentMan.h index 24eaf061..139f6e8e 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -89,6 +89,9 @@ public: SegmentMan(); ~SegmentMan(); + // Initializes totalSize, isSplittable, downloadStarted. + void init(); + /** * Returns dir+"/"+filename. * If filename is empty, then returns dir+"/"+"inex.html"; diff --git a/src/TorrentConsoleDownloadEngine.cc b/src/TorrentConsoleDownloadEngine.cc index 13b76795..16428413 100644 --- a/src/TorrentConsoleDownloadEngine.cc +++ b/src/TorrentConsoleDownloadEngine.cc @@ -45,7 +45,7 @@ void TorrentConsoleDownloadEngine::printStatistics() { avgSpeed == 0 ? "-" : Util::secfmt(eta).c_str(), downloadSpeed/1024.0); } - printf(" U:%.2f(%s) %dpeers", + printf(" U:%.2f(%s) %d peers", uploadSpeed/1024.0, Util::llitos(torrentMan->getUploadLength(), true).c_str(), torrentMan->connections); @@ -76,7 +76,7 @@ void TorrentConsoleDownloadEngine::initStatistics() { } int TorrentConsoleDownloadEngine::calculateSpeed(long long int sessionLength, int elapsed) { - int nowSpeed = (int)(sessionLength/(elapsed*1.0)); + int nowSpeed = (int)(sessionLength/elapsed); return nowSpeed; } diff --git a/src/TorrentDownloadEngine.cc b/src/TorrentDownloadEngine.cc index 008c0734..6e5b9cbb 100644 --- a/src/TorrentDownloadEngine.cc +++ b/src/TorrentDownloadEngine.cc @@ -35,9 +35,11 @@ void TorrentDownloadEngine::afterEachIteration() { if(torrentMan->isSelectiveDownloadingMode()) { onSelectiveDownloadingCompletes(); } + logger->info("The download was complete."); torrentMan->onDownloadComplete(); if(torrentMan->downloadComplete()) { filenameFixed = true; } } + torrentMan->processTrackerResponse(); } diff --git a/src/TorrentMan.cc b/src/TorrentMan.cc index 181bf6bb..7cdd647c 100644 --- a/src/TorrentMan.cc +++ b/src/TorrentMan.cc @@ -50,7 +50,7 @@ TorrentMan::TorrentMan():bitfield(NULL), interval(DEFAULT_ANNOUNCE_INTERVAL), minInterval(DEFAULT_ANNOUNCE_MIN_INTERVAL), complete(0), incomplete(0), - connections(0), diskAdaptor(NULL) { + connections(0), trackers(0), diskAdaptor(NULL) { logger = LogFactory::getInstance(); } @@ -394,7 +394,7 @@ void TorrentMan::setup(string metaInfoFile, const Strings& targetFilePaths) { diskAdaptor = new MultiDiskAdaptor(new MultiDiskWriter(pieceLength)); } } else { - diskAdaptor = new CopyDiskAdaptor(new DefaultDiskWriter(totalLength)); + diskAdaptor = new CopyDiskAdaptor(new PreAllocationDiskWriter(totalLength)); ((CopyDiskAdaptor*)diskAdaptor)->setTempFilename(name+".a2tmp"); } diskAdaptor->setStoreDir(storeDir); @@ -567,3 +567,10 @@ void TorrentMan::onDownloadComplete() { finishSelectiveDownloadingMode(); } } + +void TorrentMan::processTrackerResponse() { + if(responseProcessor->isFeeded()) { + responseProcessor->execute(); + responseProcessor->resetTrackerResponse(); + } +} diff --git a/src/TorrentMan.h b/src/TorrentMan.h index 8452e5eb..32118028 100644 --- a/src/TorrentMan.h +++ b/src/TorrentMan.h @@ -32,6 +32,7 @@ #include "Option.h" #include "FileEntry.h" #include "DiskAdaptor.h" +#include "CompactTrackerResponseProcessor.h" #include #include #include @@ -74,6 +75,7 @@ private: UsedPieces usedPieces; bool setupComplete; const Logger* logger; + CompactTrackerResponseProcessor* responseProcessor; FILE* openSegFile(string segFilename, string mode) const; void read(FILE* file); @@ -97,6 +99,8 @@ public: int complete; int incomplete; int connections; + // The number of tracker request command currently in the command queue. + int trackers; public: TorrentMan(); ~TorrentMan(); @@ -227,6 +231,15 @@ public: void onDownloadComplete(); + void setTrackerResponseProcessor(CompactTrackerResponseProcessor* proc) { + this->responseProcessor = proc; + } + CompactTrackerResponseProcessor* getTrackerResponseProcessor() const { + return this->responseProcessor; + } + + void processTrackerResponse(); + enum FILE_MODE { SINGLE, MULTI diff --git a/src/TrackerDownloadCommand.cc b/src/TrackerDownloadCommand.cc deleted file mode 100644 index da3aa843..00000000 --- a/src/TrackerDownloadCommand.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* */ -#include "TrackerDownloadCommand.h" -#include "TrackerUpdateCommand.h" -#include "ChunkedEncoding.h" -#include "DlRetryEx.h" -#include "message.h" -#include "MetaFileUtil.h" -#include "DlAbortEx.h" - -TrackerDownloadCommand::TrackerDownloadCommand(int cuid, Request* req, - TorrentDownloadEngine* e, - const Socket* s) - :AbstractCommand(cuid, req, e, s), len(0) { - resSize = 256; - res = new char[resSize]; - ChunkedEncoding* ce = new ChunkedEncoding(); - transferEncodings["chunked"] = ce; -} - -TrackerDownloadCommand::~TrackerDownloadCommand() { - delete [] res; - for(map::iterator itr = transferEncodings.begin(); itr != transferEncodings.end(); itr++) { - delete((*itr).second); - } -} - -bool TrackerDownloadCommand::executeInternal(Segment seg) { - TransferEncoding* te = NULL; - if(transferEncoding.size()) { - te = getTransferEncoding(transferEncoding); - assert(te != NULL); - } - int bufSize = 4096; - char buf[bufSize]; - socket->readData(buf, bufSize); - if(te != NULL) { - int infbufSize = 4096; - char infbuf[infbufSize]; - te->inflate(infbuf, infbufSize, buf, bufSize); - if(len+infbufSize >= resSize) { - expandBuffer(len+infbufSize); - } - memcpy(res+len, infbuf, infbufSize); - len += infbufSize; - } else { - if(len+bufSize >= resSize) { - expandBuffer(len+bufSize); - } - memcpy(res+len, buf, bufSize); - len += bufSize; - } - if(e->segmentMan->totalSize != 0 && bufSize == 0) { - throw new DlRetryEx(EX_GOT_EOF); - } - if(te != NULL && te->finished() - || te == NULL && len == e->segmentMan->totalSize - || bufSize == 0) { - if(te != NULL) te->end(); - logger->info(MSG_DOWNLOAD_COMPLETED, cuid); - MetaEntry* entry = MetaFileUtil::bdecoding(res, len); - e->commands.push(new TrackerUpdateCommand(cuid, req, (TorrentDownloadEngine*)e, entry)); - return true; - } else { - e->commands.push(this); - return false; - } -} - -TransferEncoding* TrackerDownloadCommand::getTransferEncoding(string name) { - return transferEncodings[name]; -} - -void TrackerDownloadCommand::expandBuffer(int newSize) { - char* newbuf = new char[newSize]; - memcpy(newbuf, res, len); - delete [] res; - res = newbuf; - resSize = newSize; -} diff --git a/src/TrackerDownloadCommand.h b/src/TrackerDownloadCommand.h deleted file mode 100644 index c37f76da..00000000 --- a/src/TrackerDownloadCommand.h +++ /dev/null @@ -1,50 +0,0 @@ -/* */ -#ifndef _D_TRACKER_DOWNLOAD_COMMAND_H_ -#define _D_TRACKER_DOWNLOAD_COMMAND_H_ - -#include "AbstractCommand.h" -#include "TorrentDownloadEngine.h" -#include "TransferEncoding.h" -#include "Segment.h" -#include - -class TrackerDownloadCommand : public AbstractCommand { -private: - char* res; - int resSize; - int len; - map transferEncodings; - void expandBuffer(int newSize); -protected: - bool executeInternal(Segment segment); -public: - TrackerDownloadCommand(int cuid, Request* req, TorrentDownloadEngine* e, const Socket* s); - ~TrackerDownloadCommand(); - - TransferEncoding* getTransferEncoding(string transferEncoding); - - string transferEncoding; -}; - -#endif // _D_TRACKER_DOWNLOAD_COMMAND_H_ - diff --git a/src/TrackerInitCommand.cc b/src/TrackerInitCommand.cc deleted file mode 100644 index 565077ce..00000000 --- a/src/TrackerInitCommand.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* */ -#include "TrackerInitCommand.h" -#include "Request.h" -#include "InitiateConnectionCommandFactory.h" -#include "TorrentMan.h" -#include "Util.h" - -TrackerInitCommand::TrackerInitCommand(int cuid, Request* req, TorrentDownloadEngine* e):Command(cuid), req(req), e(e) {} - -TrackerInitCommand::~TrackerInitCommand() {} - -bool TrackerInitCommand::execute() { - if(e->torrentMan->downloadComplete()) { - if(req->getTrackerEvent() == Request::COMPLETED) { - req->setTrackerEvent(Request::AFTER_COMPLETED); - } else { - if(req->getTrackerEvent() == Request::STARTED) { - req->setTrackerEvent(Request::AFTER_COMPLETED); - } else if(req->getTrackerEvent() != Request::AFTER_COMPLETED) { - req->setTrackerEvent(Request::COMPLETED); - } - } - } - string event; - switch(req->getTrackerEvent()) { - case Request::STARTED: - event = "started"; - break; - case Request::STOPPED: - event = "stopped"; - break; - case Request::COMPLETED: - event = "completed"; - break; - } - string url = e->torrentMan->announce+"?"+ - "info_hash="+Util::urlencode(e->torrentMan->getInfoHash(), 20)+"&"+ - "peer_id="+e->torrentMan->peerId+"&"+ - "port="+Util::itos(e->torrentMan->getPort())+"&"+ - "uploaded="+Util::llitos(e->torrentMan->getSessionUploadLength())+"&"+ - "downloaded="+Util::llitos(e->torrentMan->getSessionDownloadLength())+"&"+ - "left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0 - ? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+ - "compact=1"+"&"+ - "key="+e->torrentMan->peerId; - if(!event.empty()) { - url += string("&")+"event="+event; - } - if(!e->torrentMan->trackerId.empty()) { - url += string("&")+"trackerid="+e->torrentMan->trackerId; - } - req->setUrl(url); - Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e); - e->commands.push(command); - return true; -} - diff --git a/src/TrackerInitCommand.h b/src/TrackerInitCommand.h deleted file mode 100644 index cf08c58e..00000000 --- a/src/TrackerInitCommand.h +++ /dev/null @@ -1,40 +0,0 @@ -/* */ -#ifndef _D_TRACKER_INIT_COMMAND_H_ -#define _D_TRACKER_INIT_COMMAND_H_ - -#include "TorrentDownloadEngine.h" -#include "Request.h" -#include "Command.h" - -class TrackerInitCommand : public Command { -private: - Request* req; - TorrentDownloadEngine* e; -public: - TrackerInitCommand(int cuid, Request* req, TorrentDownloadEngine* e); - ~TrackerInitCommand(); - - bool execute(); -}; - -#endif // _D_TRACKER_INIT_COMMAND_H_ diff --git a/src/TrackerUpdateCommand.cc b/src/TrackerUpdateCommand.cc deleted file mode 100644 index 6b2ed6b6..00000000 --- a/src/TrackerUpdateCommand.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* */ -#include "TrackerUpdateCommand.h" -#include "PeerInitiateConnectionCommand.h" -#include "PeerListenCommand.h" -#include "Dictionary.h" -#include "Data.h" -#include "DlAbortEx.h" -#include "message.h" -#include - -TrackerUpdateCommand::TrackerUpdateCommand(int cuid, Request* req, - TorrentDownloadEngine* e, - MetaEntry* trackerResponse) - :Command(cuid), req(req), e(e), trackerResponse(trackerResponse) { -} - -TrackerUpdateCommand::~TrackerUpdateCommand() { - delete trackerResponse; -} - -bool TrackerUpdateCommand::execute() { - Dictionary* response = (Dictionary*)trackerResponse; - Data* failureReason = (Data*)response->get("failure reason"); - if(failureReason != NULL) { - throw new DlAbortEx("Tracker returned failure reason: %s", failureReason->toString().c_str()); - } - Data* warningMessage = (Data*)response->get("warning message"); - if(warningMessage != NULL) { - logger->warn(MSG_TRACKER_WARNING_MESSAGE, cuid, warningMessage->toString().c_str()); - } - Data* trackerId = (Data*)response->get("tracker id"); - if(trackerId != NULL) { - e->torrentMan->trackerId = trackerId->toString(); - logger->debug("CUID#%d - Tracker ID:%s", cuid, e->torrentMan->trackerId.c_str()); - } - Data* interval = (Data*)response->get("interval"); - if(interval != NULL) { - e->torrentMan->interval = interval->toInt(); - logger->debug("CUID#%d - interval:%d", cuid, e->torrentMan->interval); - } - Data* minInterval = (Data*)response->get("min interval"); - if(minInterval != NULL) { - e->torrentMan->minInterval = minInterval->toInt(); - logger->debug("CUID#%d - min interval:%d", cuid, e->torrentMan->minInterval); - } - if(e->torrentMan->minInterval > e->torrentMan->interval) { - e->torrentMan->minInterval = e->torrentMan->interval; - } - Data* complete = (Data*)response->get("complete"); - if(complete != NULL) { - e->torrentMan->complete = complete->toInt(); - logger->debug("CUID#%d - complete:%d", cuid, e->torrentMan->complete); - } - Data* incomplete = (Data*)response->get("incomplete"); - if(incomplete != NULL) { - e->torrentMan->incomplete = incomplete->toInt(); - logger->debug("CUID#%d - incomplete:%d", cuid, e->torrentMan->incomplete); - } - Data* peers = (Data*)response->get("peers"); - if(peers != NULL) { - for(int i = 0; i < peers->getLen(); i += 6) { - unsigned int ipaddr1 = (unsigned char)*(peers->getData()+i); - unsigned int ipaddr2 = (unsigned char)*(peers->getData()+i+1); - unsigned int ipaddr3 = (unsigned char)*(peers->getData()+i+2); - unsigned int ipaddr4 = (unsigned char)*(peers->getData()+i+3); - unsigned int port = ntohs(*(unsigned short int*)(peers->getData()+i+4)); - char ipaddr[16]; - - snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%d", - ipaddr1, ipaddr2, ipaddr3, ipaddr4); - Peer* peer = new Peer(ipaddr, port, e->torrentMan->pieceLength, - e->torrentMan->getTotalLength()); - if(e->torrentMan->addPeer(peer)) { - logger->debug("CUID#%d - adding peer %s:%d", cuid, - peer->ipaddr.c_str(), peer->port); - } else { - delete peer; - } - } - } else { - logger->info("CUID#%d - no peer list received.", cuid); - } - while(e->torrentMan->isPeerAvailable() && - e->torrentMan->connections < MAX_PEER_UPDATE) { - Peer* peer = e->torrentMan->getPeer(); - int newCuid = e->torrentMan->getNewCuid(); - peer->cuid = newCuid; - PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e); - e->commands.push(command); - logger->debug("CUID#%d - adding new command CUID#%d", cuid, newCuid); - } - if(req->getTrackerEvent() == Request::STARTED) { - req->setTrackerEvent(Request::AUTO); - } - return true; -} diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index f622a52a..7ff43ee4 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -21,7 +21,8 @@ /* copyright --> */ #include "TrackerWatcherCommand.h" #include "SleepCommand.h" -#include "TrackerInitCommand.h" +#include "InitiateConnectionCommandFactory.h" +#include "Util.h" TrackerWatcherCommand::TrackerWatcherCommand(int cuid, Request* req, TorrentDownloadEngine* e): @@ -31,14 +32,55 @@ TrackerWatcherCommand::TrackerWatcherCommand(int cuid, Request* req, TrackerWatcherCommand::~TrackerWatcherCommand() {} bool TrackerWatcherCommand::execute() { - req->resetTryCount(); - Command* command = new TrackerInitCommand(e->torrentMan->getNewCuid(), - req, - e); - logger->info("CUID#%d - creating new tracker request command #%d", cuid, - command->getCuid()); - e->commands.push(command); - + if(e->torrentMan->trackers == 0) { + req->resetTryCount(); + + if(e->torrentMan->downloadComplete()) { + if(req->getTrackerEvent() == Request::COMPLETED) { + req->setTrackerEvent(Request::AFTER_COMPLETED); + } else { + if(req->getTrackerEvent() == Request::STARTED) { + req->setTrackerEvent(Request::AFTER_COMPLETED); + } else if(req->getTrackerEvent() != Request::AFTER_COMPLETED) { + req->setTrackerEvent(Request::COMPLETED); + } + } + } + string event; + switch(req->getTrackerEvent()) { + case Request::STARTED: + event = "started"; + break; + case Request::STOPPED: + event = "stopped"; + break; + case Request::COMPLETED: + event = "completed"; + break; + } + string url = e->torrentMan->announce+"?"+ + "info_hash="+Util::urlencode(e->torrentMan->getInfoHash(), 20)+"&"+ + "peer_id="+e->torrentMan->peerId+"&"+ + "port="+Util::itos(e->torrentMan->getPort())+"&"+ + "uploaded="+Util::llitos(e->torrentMan->getSessionUploadLength())+"&"+ + "downloaded="+Util::llitos(e->torrentMan->getSessionDownloadLength())+"&"+ + "left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0 + ? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+ + "compact=1"+"&"+ + "key="+e->torrentMan->peerId; + if(!event.empty()) { + url += string("&")+"event="+event; + } + if(!e->torrentMan->trackerId.empty()) { + url += string("&")+"trackerid="+e->torrentMan->trackerId; + } + req->setUrl(url); + Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(e->torrentMan->getNewCuid(), req, e); + e->commands.push(command); + e->torrentMan->trackers++; + logger->info("CUID#%d - creating new tracker request command #%d", cuid, + command->getCuid()); + } SleepCommand* slpCommand = new SleepCommand(cuid, e, this, e->torrentMan->minInterval); e->commands.push(slpCommand); diff --git a/src/main.cc b/src/main.cc index d20f56e2..2e1cb6de 100644 --- a/src/main.cc +++ b/src/main.cc @@ -31,10 +31,11 @@ #include "Util.h" #include "InitiateConnectionCommandFactory.h" #include "prefs.h" -#include "TrackerInitCommand.h" #include "PeerListenCommand.h" #include "TorrentAutoSaveCommand.h" #include "TrackerWatcherCommand.h" +#include "CompactTrackerResponseProcessor.h" +#include "ByteArrayDiskWriter.h" #include #include #include @@ -93,7 +94,7 @@ void handler(int signal) { if(e->diskWriter != NULL) { e->diskWriter->closeFile(); } - printf("done\n"); + printf(_("done\n")); exit(0); } @@ -110,7 +111,7 @@ void torrentHandler(int signal) { } else { te->torrentMan->save(); } - printf("done\n"); + printf(_("done\n")); exit(0); } @@ -152,6 +153,8 @@ void showVersion() { void showUsage() { printf(_("Usage: %s [options] URL ...\n"), PACKAGE_NAME); + printf(_(" %s [options] -T TORRENT_FILE FILE ...\n"), PACKAGE_NAME); + cout << endl; cout << _("Options:") << endl; cout << _(" -d, --dir=DIR The directory to store downloaded file.") << endl; @@ -199,11 +202,16 @@ void showUsage() { " 'tunnel'.\n" " Default: tunnel") << endl; #ifdef ENABLE_BITTORRENT - cout << _(" --torrent-file=TORRENT_FILE The file path to .torrent file.") << endl; + cout << _(" -T, --torrent-file=TORRENT_FILE The file path to .torrent file.") << endl; cout << _(" --follow-torrent=true|false Setting this option to false prevents aria2 to\n" " enter BitTorrent mode even if the filename of\n" " downloaded file ends with .torrent.\n" " Default: true") << endl; + cout << _(" -S, --show-files Print the file listing in .torrent file and exit.") << endl; + 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; #endif // ENABLE_BITTORRENT cout << _(" -v, --version Print the version number and exit.") << endl; cout << _(" -h, --help Print this message and exit.") << endl; @@ -212,6 +220,10 @@ void showUsage() { cout << _(" You can specify multiple URLs. All URLs must point to the same file\n" " or downloading fails.") << endl; cout << endl; + cout << "FILE:" << endl; + cout << _(" Specify files in multi-file torrent to download. Use conjunction with\n" + " -T option.") << endl; + cout << endl; cout << _("Examples:") << endl; cout << _(" Download a file by 1 connection:") << endl; cout << " aria2c http://AAA.BBB.CCC/file.zip" << endl; @@ -226,9 +238,11 @@ void showUsage() { cout << " aria2c -o test.torrent http://AAA.BBB.CCC/file.torrent" << endl; cout << _(" Download a torrent using local .torrent file:") << endl; cout << " aria2c --torrent-file test.torrent" << endl; + cout << _(" Download only selected files:") << endl; + cout << " aria2c --torrent-file test.torrent dir/file1.zip dir/file2.zip" << endl; cout << endl; #endif // ENABLE_BITTORRENT - printf(_("Reports bugs to %s"), ""); + printf(_("Report bugs to %s"), ""); cout << endl; } @@ -247,6 +261,7 @@ int main(int argc, char* argv[]) { bool daemonMode = false; string referer; string torrentFile; + int listenPort = -1; Strings args; #ifdef ENABLE_BITTORRENT bool followTorrent = true; @@ -296,9 +311,10 @@ int main(int argc, char* argv[]) { { "min-segment-size", required_argument, &lopt, 13 }, { "http-proxy-method", required_argument, &lopt, 14 }, #ifdef ENABLE_BITTORRENT - { "torrent-file", required_argument, &lopt, 15 }, + { "torrent-file", required_argument, NULL, 'T' }, + { "listen-port", required_argument, &lopt, 15 }, { "follow-torrent", required_argument, &lopt, 16 }, - { "show-files", no_argument, &lopt, 17 }, + { "show-files", no_argument, NULL, 'S' }, { "no-preallocation", no_argument, &lopt, 18 }, { "direct-file-mapping", required_argument, &lopt, 19 }, #endif // ENABLE_BITTORRENT @@ -306,7 +322,7 @@ int main(int argc, char* argv[]) { { "help", no_argument, NULL, 'h' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vh", longOpts, &optIndex); + c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vhST:", longOpts, &optIndex); if(c == -1) { break; } @@ -415,7 +431,12 @@ int main(int argc, char* argv[]) { } break; case 15: - torrentFile = string(optarg); + listenPort = (int)strtol(optarg, NULL, 10); + if(!(1024 <= listenPort && listenPort <= 65535)) { + cerr << _("listen-port must be between 1024 and 65535.") << endl; + showUsage(); + exit(1); + } break; case 16: if(string(optarg) == "true") { @@ -428,9 +449,6 @@ int main(int argc, char* argv[]) { exit(1); } break; - case 17: - op->put(PREF_SHOW_FILES, V_TRUE); - break; case 18: op->put(PREF_NO_PREALLOCATION, V_TRUE); break; @@ -495,6 +513,12 @@ int main(int argc, char* argv[]) { case 'p': op->put(PREF_FTP_PASV_ENABLED, V_TRUE); break; + case 'S': + op->put(PREF_SHOW_FILES, V_TRUE); + break; + case 'T': + torrentFile = string(optarg); + break; case 'v': showVersion(); exit(0); @@ -515,7 +539,7 @@ int main(int argc, char* argv[]) { } if(daemonMode) { if(daemon(1, 1) < 0) { - perror("daemon failed"); + perror(_("daemon failed")); exit(1); } } @@ -597,18 +621,23 @@ int main(int argc, char* argv[]) { req->setTrackerEvent(Request::STARTED); te = new TorrentConsoleDownloadEngine(); te->option = op; - te->diskWriter = new DefaultDiskWriter(); + ByteArrayDiskWriter* byteArrayDiskWriter = new ByteArrayDiskWriter(); + te->diskWriter = byteArrayDiskWriter; te->segmentMan = new SegmentMan(); te->segmentMan->option = op; te->segmentMan->splitter = splitter; te->torrentMan = new TorrentMan(); te->torrentMan->setStoreDir(dir); te->torrentMan->option = op; + CompactTrackerResponseProcessor* responseProcessor = + new CompactTrackerResponseProcessor(byteArrayDiskWriter, te, req); + te->torrentMan->setTrackerResponseProcessor(responseProcessor); string targetTorrentFile = torrentFile.empty() ? downloadedTorrentFile : torrentFile; if(op->get(PREF_SHOW_FILES) == V_TRUE) { - FileEntries fileEntries = te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile); - cout << "Files:" << endl; + FileEntries fileEntries = + te->torrentMan->readFileEntryFromMetaInfoFile(targetTorrentFile); + cout << _("Files:") << endl; for(FileEntries::const_iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { printf("%s %s Bytes\n", itr->path.c_str(), @@ -624,9 +653,14 @@ int main(int argc, char* argv[]) { } PeerListenCommand* listenCommand = new PeerListenCommand(te->torrentMan->getNewCuid(), te); - int port = listenCommand->bindPort(6881, 6999); + int port; + if(listenPort == -1) { + port = listenCommand->bindPort(6881, 6999); + } else { + port = listenCommand->bindPort(listenPort, listenPort); + } if(port == -1) { - printf("Errors occurred while binding port.\n"); + printf(_("Errors occurred while binding port.\n")); exit(1); } te->torrentMan->setPort(port); @@ -644,6 +678,7 @@ int main(int argc, char* argv[]) { printDownloadAbortMessage(); } delete(req); + delete(responseProcessor); delete(te->segmentMan); delete(te->torrentMan); delete(te->diskWriter); diff --git a/src/message.h b/src/message.h index c38b2adc..c54a4fc3 100644 --- a/src/message.h +++ b/src/message.h @@ -43,7 +43,7 @@ #define MSG_GOT_NEW_PIECE "CUID#%d - we got new piece. index=%d" #define MSG_GOT_WRONG_PIECE "CUID#%d - we got wrong piece. index=%d" -#define MSG_TRACKER_WARNING_MESSAGE "CUID#%d - Tracker returned warning message: %s" +#define MSG_TRACKER_WARNING_MESSAGE "Tracker returned warning message: %s" #define MSG_SEGMENT_FILE_EXISTS _("The segment file %s exists.") #define MSG_SEGMENT_FILE_DOES_NOT_EXIST _("The segment file %s does not exist.")