Explorar el Código

added bittorrent support(experimental)

Tatsuhiro Tsujikawa hace 19 años
padre
commit
df6c7c0385
Se han modificado 100 ficheros con 7221 adiciones y 352 borrados
  1. 4 0
      ChangeLog
  2. 5 1
      TODO
  3. 106 85
      po/aria2c.pot
  4. BIN
      po/ja.gmo
  5. 112 89
      po/ja.po
  6. 61 2
      src/AbstractDiskWriter.cc
  7. 9 0
      src/AbstractDiskWriter.h
  8. 277 0
      src/BitfieldMan.cc
  9. 90 0
      src/BitfieldMan.h
  10. 34 0
      src/ConsoleDownloadEngine.cc
  11. 7 0
      src/ConsoleDownloadEngine.h
  12. 81 0
      src/Data.cc
  13. 54 0
      src/Data.h
  14. 0 7
      src/DefaultDiskWriter.cc
  15. 0 2
      src/DefaultDiskWriter.h
  16. 57 0
      src/Dictionary.cc
  17. 51 0
      src/Dictionary.h
  18. 59 0
      src/Directory.cc
  19. 44 0
      src/Directory.h
  20. 6 0
      src/DiskWriter.h
  21. 10 30
      src/DownloadEngine.cc
  22. 4 6
      src/DownloadEngine.h
  23. 8 0
      src/File.cc
  24. 2 0
      src/File.h
  25. 47 0
      src/HandshakeMessage.h
  26. 46 25
      src/HttpConnection.cc
  27. 5 1
      src/HttpConnection.h
  28. 5 4
      src/HttpRequestCommand.cc
  29. 1 1
      src/HttpRequestCommand.h
  30. 27 9
      src/HttpResponseCommand.cc
  31. 47 0
      src/List.cc
  32. 48 0
      src/List.h
  33. 31 1
      src/Makefile.am
  34. 460 2
      src/Makefile.in
  35. 40 0
      src/MetaEntry.h
  36. 34 0
      src/MetaEntryVisitor.h
  37. 170 0
      src/MetaFileUtil.cc
  38. 50 0
      src/MetaFileUtil.h
  39. 48 0
      src/Peer.cc
  40. 115 0
      src/Peer.h
  41. 181 0
      src/PeerAbstractCommand.cc
  42. 58 0
      src/PeerAbstractCommand.h
  43. 378 0
      src/PeerConnection.cc
  44. 82 0
      src/PeerConnection.h
  45. 74 0
      src/PeerInitiateConnectionCommand.cc
  46. 40 0
      src/PeerInitiateConnectionCommand.h
  47. 477 0
      src/PeerInteractionCommand.cc
  48. 76 0
      src/PeerInteractionCommand.h
  49. 91 0
      src/PeerListenCommand.cc
  50. 42 0
      src/PeerListenCommand.h
  51. 72 0
      src/PeerMessage.cc
  52. 83 0
      src/PeerMessage.h
  53. 231 0
      src/PeerMessageUtil.cc
  54. 51 0
      src/PeerMessageUtil.h
  55. 115 0
      src/PendingMessage.cc
  56. 71 0
      src/PendingMessage.h
  57. 84 0
      src/Piece.cc
  58. 81 0
      src/Piece.h
  59. 25 26
      src/PreAllocationDiskWriter.cc
  60. 2 4
      src/PreAllocationDiskWriter.h
  61. 1 1
      src/Request.cc
  62. 13 0
      src/Request.h
  63. 70 0
      src/RequestSlot.cc
  64. 63 0
      src/RequestSlot.h
  65. 98 0
      src/RequestSlotMan.cc
  66. 72 0
      src/RequestSlotMan.h
  67. 82 0
      src/ShaVisitor.cc
  68. 47 0
      src/ShaVisitor.h
  69. 6 2
      src/Socket.cc
  70. 6 1
      src/Socket.h
  71. 17 9
      src/SocketCore.cc
  72. 12 4
      src/SocketCore.h
  73. 37 0
      src/TorrentAutoSaveCommand.cc
  74. 40 0
      src/TorrentAutoSaveCommand.h
  75. 132 0
      src/TorrentConsoleDownloadEngine.cc
  76. 52 0
      src/TorrentConsoleDownloadEngine.h
  77. 32 0
      src/TorrentDownloadEngine.cc
  78. 38 0
      src/TorrentDownloadEngine.h
  79. 505 0
      src/TorrentMan.cc
  80. 217 0
      src/TorrentMan.h
  81. 99 0
      src/TrackerDownloadCommand.cc
  82. 50 0
      src/TrackerDownloadCommand.h
  83. 67 0
      src/TrackerInitCommand.cc
  84. 40 0
      src/TrackerInitCommand.h
  85. 126 0
      src/TrackerUpdateCommand.cc
  86. 42 0
      src/TrackerUpdateCommand.h
  87. 72 0
      src/Util.cc
  88. 9 0
      src/Util.h
  89. 2 0
      src/common.h
  90. 173 36
      src/main.cc
  91. 11 1
      src/message.h
  92. 2 0
      src/prefs.h
  93. 76 0
      test/BitfieldManTest.cc
  94. 70 0
      test/DataTest.cc
  95. 35 0
      test/DefaultDiskWriterTest.cc
  96. 35 0
      test/DictionaryTest.cc
  97. 7 0
      test/FileTest.cc
  98. 33 0
      test/ListTest.cc
  99. 10 1
      test/Makefile.am
  100. 153 2
      test/Makefile.in

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+2006-03-17  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	* SocketCore.cc: remove the assignment of addrinfo.ai_addr.
+
 2006-03-09  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	* ChunkedEncoding.{h,cc}: fixed the bug that if chunk data is binary,

+ 5 - 1
TODO

@@ -5,4 +5,8 @@
 * Better HTTP status handling
 * Download files listed in a specifed file.
 * check MD5 checksum
-* Add the feature which adds or removes URLs on-the-fly.
+* Add the feature which adds or removes URLs on-the-fly.
+* Tracker UDP protocol
+* no-compact peers format
+* Add port range command-line option
+* Add max peers command-line option

+ 106 - 85
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-03-07 22:57+0900\n"
+"POT-Creation-Date: 2006-03-21 23:10+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"
@@ -77,122 +77,135 @@ msgstr ""
 msgid "CUID#%d - Unregistering cuid from segmentManager."
 msgstr ""
 
-#: src/message.h:39
+#: src/message.h:48
 #, c-format
 msgid "The segment file %s exists."
 msgstr ""
 
-#: src/message.h:40
+#: src/message.h:49
 #, c-format
 msgid "The segment file %s does not exist."
 msgstr ""
 
-#: src/message.h:41
+#: src/message.h:50
 #, c-format
 msgid "Saving the segment file %s"
 msgstr ""
 
-#: src/message.h:42
+#: src/message.h:51
 msgid "The segment file was saved successfully."
 msgstr ""
 
-#: src/message.h:43
+#: src/message.h:52
 #, c-format
 msgid "Loading the segment file %s."
 msgstr ""
 
-#: src/message.h:44
+#: src/message.h:53
 msgid "The segment file was loaded successfully."
 msgstr ""
 
-#: src/message.h:46
+#: src/message.h:55
 msgid "Timeout."
 msgstr ""
 
-#: src/message.h:47
+#: src/message.h:56
 msgid "Invalid chunk size."
 msgstr ""
 
-#: src/message.h:48
+#: src/message.h:57
 #, c-format
 msgid "Too large chunk. size = %d"
 msgstr ""
 
-#: src/message.h:49
+#: src/message.h:58
 msgid "Invalid header."
 msgstr ""
 
-#: src/message.h:50
+#: src/message.h:59
 msgid "Invalid response."
 msgstr ""
 
-#: src/message.h:51
+#: src/message.h:60
 msgid "No header found."
 msgstr ""
 
-#: src/message.h:52
+#: src/message.h:61
 msgid "No status header."
 msgstr ""
 
-#: src/message.h:53
+#: src/message.h:62
 msgid "Proxy connection failed."
 msgstr ""
 
-#: src/message.h:54
+#: src/message.h:63
 msgid "Connection failed."
 msgstr ""
 
-#: src/message.h:55
+#: src/message.h:64
 #, c-format
 msgid ""
 "The requested filename and the previously registered one are not same. %s != "
 "%s"
 msgstr ""
 
-#: src/message.h:56
+#: src/message.h:65
 #, c-format
 msgid "The response status is not successful. status = %d"
 msgstr ""
 
-#: src/message.h:57
+#: src/message.h:66
 #, c-format
 msgid "Too large file size. size = %lld"
 msgstr ""
 
-#: src/message.h:58
+#: src/message.h:67
 #, c-format
 msgid "Transfer encoding %s is not supported."
 msgstr ""
 
-#: src/message.h:59
+#: src/message.h:68
 msgid "SSL initialization failed."
 msgstr ""
 
-#: src/message.h:60
+#: src/message.h:69
 #, c-format
 msgid "Size mismatch %lld != %lld"
 msgstr ""
 
-#: src/message.h:61
+#: src/message.h:70
 msgid "Got EOF from the server."
 msgstr ""
 
-#: src/main.cc:57
+#: src/main.cc:58
+#, c-format
+msgid ""
+"\n"
+"The download was complete. <%s>\n"
+msgstr ""
+
+#: src/main.cc:62
+msgid ""
+"\n"
+"The download was not complete because of errors. Check the log.\n"
+msgstr ""
+
+#: src/main.cc:73 src/main.cc:82
 msgid ""
 "\n"
 "SIGINT signal received."
 msgstr ""
 
-#: src/main.cc:72
+#: src/main.cc:104
 #, c-format
 msgid "Unrecognized URL or unsupported protocol: %s\n"
 msgstr ""
 
-#: src/main.cc:78
+#: src/main.cc:110
 msgid " version "
 msgstr ""
 
-#: src/main.cc:82
+#: src/main.cc:114
 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"
@@ -209,40 +222,40 @@ msgid ""
 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
 msgstr ""
 
-#: src/main.cc:96
+#: src/main.cc:128
 #, c-format
 msgid "Contact Info: %s\n"
 msgstr ""
 
-#: src/main.cc:102
+#: src/main.cc:134
 #, c-format
 msgid "Usage: %s [options] URL ...\n"
 msgstr ""
 
-#: src/main.cc:104
+#: src/main.cc:136
 msgid "Options:"
 msgstr ""
 
-#: src/main.cc:105
+#: src/main.cc:137
 msgid " -d, --dir=DIR                The directory to store downloaded file."
 msgstr ""
 
-#: src/main.cc:106
+#: src/main.cc:138
 msgid " -o, --out=FILE               The file name for downloaded file."
 msgstr ""
 
-#: src/main.cc:107
+#: src/main.cc:139
 msgid ""
 " -l, --log=LOG                The file path to store log. If '-' is "
 "specified,\n"
 "                              log is written to stdout."
 msgstr ""
 
-#: src/main.cc:109
+#: src/main.cc:141
 msgid " -D, --daemon                 Run as daemon."
 msgstr ""
 
-#: src/main.cc:110
+#: src/main.cc:142
 msgid ""
 " -s, --split=N                Download a file using N connections. N must "
 "be\n"
@@ -252,24 +265,24 @@ msgid ""
 "                              N connections."
 msgstr ""
 
-#: src/main.cc:114
+#: src/main.cc:146
 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:117
+#: src/main.cc:149
 msgid " -t, --timeout=SEC            Set timeout in second. Default: 60"
 msgstr ""
 
-#: src/main.cc:118
+#: src/main.cc:150
 msgid ""
 " -m, --max-tries=N            Set number of tries. 0 means unlimited.\n"
 "                              Default: 5"
 msgstr ""
 
-#: src/main.cc:120
+#: src/main.cc:152
 msgid ""
 " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
 "                              K or M(1K = 1024, 1M = 1024K). This\n"
@@ -277,40 +290,40 @@ msgid ""
 "                              1024."
 msgstr ""
 
-#: src/main.cc:124
+#: src/main.cc:156
 msgid ""
 " --http-proxy=HOST:PORT       Use HTTP proxy server. This affects to all\n"
 "                              URLs."
 msgstr ""
 
-#: src/main.cc:126
+#: src/main.cc:158
 msgid " --http-user=USER             Set HTTP user. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:127
+#: src/main.cc:159
 msgid ""
 " --http-passwd=PASSWD         Set HTTP password. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:128
+#: src/main.cc:160
 msgid ""
 " --http-proxy-user=USER       Set HTTP proxy user. This affects to all URLs"
 msgstr ""
 
-#: src/main.cc:129
+#: src/main.cc:161
 msgid ""
 " --http-proxy-passwd=PASSWD   Set HTTP proxy password. This affects to all "
 "URLs."
 msgstr ""
 
-#: src/main.cc:130
+#: src/main.cc:162
 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:133
+#: src/main.cc:165
 msgid ""
 " --http-auth-scheme=SCHEME    Set HTTP authentication scheme. Currently, "
 "basic\n"
@@ -321,23 +334,23 @@ msgid ""
 "                              as well as --http-user and --http-passwd."
 msgstr ""
 
-#: src/main.cc:137
+#: src/main.cc:169
 msgid " --referer=REFERER            Set Referer. This affects to all URLs."
 msgstr ""
 
-#: src/main.cc:138
+#: src/main.cc:170
 msgid ""
 " --ftp-user=USER              Set FTP user. This affects to all URLs.\n"
 "                              Default: anonymous"
 msgstr ""
 
-#: src/main.cc:140
+#: src/main.cc:172
 msgid ""
 " --ftp-passwd=PASSWD          Set FTP password. This affects to all URLs.\n"
 "                              Default: ARIA2USER@"
 msgstr ""
 
-#: src/main.cc:142
+#: src/main.cc:174
 msgid ""
 " --ftp-type=TYPE              Set FTP transfer type. TYPE is either "
 "'binary'\n"
@@ -345,11 +358,11 @@ msgid ""
 "                              Default: binary"
 msgstr ""
 
-#: src/main.cc:145
+#: src/main.cc:177
 msgid " -p, --ftp-pasv               Use passive mode in FTP."
 msgstr ""
 
-#: src/main.cc:146
+#: src/main.cc:178
 msgid ""
 " --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' "
 "or\n"
@@ -357,98 +370,106 @@ msgid ""
 "                              Default: tunnel"
 msgstr ""
 
-#: src/main.cc:149
+#: src/main.cc:181
+msgid " --torrent-file=TORRENT_FILE  The file path to .torrent file."
+msgstr ""
+
+#: src/main.cc:182
+msgid ""
+" --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"
+msgstr ""
+
+#: src/main.cc:186
 msgid " -v, --version                Print the version number and exit."
 msgstr ""
 
-#: src/main.cc:150
+#: src/main.cc:187
 msgid " -h, --help                   Print this message and exit."
 msgstr ""
 
-#: src/main.cc:153
+#: src/main.cc:190
 msgid ""
 " You can specify multiple URLs. All URLs must point to the same file\n"
 " or downloading fails."
 msgstr ""
 
-#: src/main.cc:156
+#: src/main.cc:193
 msgid "Examples:"
 msgstr ""
 
-#: src/main.cc:157
+#: src/main.cc:194
 msgid " Download a file by 1 connection:"
 msgstr ""
 
-#: src/main.cc:159
+#: src/main.cc:196
 msgid " Download a file by 2 connections:"
 msgstr ""
 
-#: src/main.cc:161
+#: src/main.cc:198
 msgid " Download a file by 2 connections, each connects to a different server:"
 msgstr ""
 
-#: src/main.cc:163
+#: src/main.cc:200
 msgid " You can mix up different protocols:"
 msgstr ""
 
-#: src/main.cc:166
+#: src/main.cc:202
+msgid " Download a torrent"
+msgstr ""
+
+#: src/main.cc:205
 #, c-format
 msgid "Reports bugs to %s"
 msgstr ""
 
-#: src/main.cc:240
+#: src/main.cc:284
 msgid "unrecognized proxy format"
 msgstr ""
 
-#: src/main.cc:266
+#: src/main.cc:310
 msgid "Currently, supported authentication scheme is basic."
 msgstr ""
 
-#: src/main.cc:275
+#: src/main.cc:319
 msgid "retry-wait must be between 0 and 60."
 msgstr ""
 
-#: src/main.cc:292
+#: src/main.cc:336
 msgid "ftp-type must be either 'binary' or 'ascii'."
 msgstr ""
 
-#: src/main.cc:301
+#: src/main.cc:345
 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'."
 msgstr ""
 
-#: src/main.cc:319
+#: src/main.cc:363
 msgid "min-segment-size invalid"
 msgstr ""
 
-#: src/main.cc:330
+#: src/main.cc:374
 msgid "http-proxy-method must be either 'get' or 'tunnel'."
 msgstr ""
 
-#: src/main.cc:357
+#: src/main.cc:388
+msgid "follow-torrent must be either 'true' or 'false'."
+msgstr ""
+
+#: src/main.cc:414
 msgid "split must be between 1 and 5."
 msgstr ""
 
-#: src/main.cc:367
+#: src/main.cc:424
 msgid "timeout must be between 1 and 600"
 msgstr ""
 
-#: src/main.cc:376
+#: src/main.cc:433
 msgid "max-tries invalid"
 msgstr ""
 
-#: src/main.cc:398
+#: src/main.cc:456
 msgid "specify at least one URL"
 msgstr ""
-
-#: src/main.cc:449
-#, c-format
-msgid ""
-"\n"
-"The download was complete. <%s>\n"
-msgstr ""
-
-#: src/main.cc:451
-msgid ""
-"\n"
-"The download was not complete because of errors. Check the log.\n"
-msgstr ""

BIN
po/ja.gmo


+ 112 - 89
po/ja.po

@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: aria2c 0.2.1\n"
 "Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
-"POT-Creation-Date: 2006-03-07 22:57+0900\n"
+"POT-Creation-Date: 2006-03-21 23:10+0900\n"
 "PO-Revision-Date: 2006-03-05 15:21+0900\n"
 "Last-Translator: Tatsuhiro Tsujikawa <tujikawa@rednoah.com>\n"
 "Language-Team: Japanese <ja@li.org>\n"
@@ -85,107 +85,124 @@ msgstr ""
 msgid "CUID#%d - Unregistering cuid from segmentManager."
 msgstr "CUID#%d - cuid をセグメントマネジャーから削除します."
 
-#: src/message.h:39
+#: src/message.h:48
 #, c-format
 msgid "The segment file %s exists."
 msgstr "セグメントファイル %s が存在します."
 
-#: src/message.h:40
+#: src/message.h:49
 #, c-format
 msgid "The segment file %s does not exist."
 msgstr "セグメントファイル %s が存在しません."
 
-#: src/message.h:41
+#: src/message.h:50
 #, c-format
 msgid "Saving the segment file %s"
 msgstr "セグメントファイル %s を保存しています."
 
-#: src/message.h:42
+#: src/message.h:51
 msgid "The segment file was saved successfully."
 msgstr "セグメントファイルの保存が完了しました."
 
-#: src/message.h:43
+#: src/message.h:52
 #, c-format
 msgid "Loading the segment file %s."
 msgstr "セグメントファイル %s をロードしています."
 
-#: src/message.h:44
+#: src/message.h:53
 msgid "The segment file was loaded successfully."
 msgstr "セグメントファイルのロードが完了しました."
 
-#: src/message.h:46
+#: src/message.h:55
 msgid "Timeout."
 msgstr "タイムアウトしました."
 
-#: src/message.h:47
+#: src/message.h:56
 msgid "Invalid chunk size."
 msgstr "chunk サイズが不正です."
 
-#: src/message.h:48
+#: src/message.h:57
 #, c-format
 msgid "Too large chunk. size = %d"
 msgstr "chunk サイズ (%d) が大きすぎます."
 
-#: src/message.h:49
+#: src/message.h:58
 msgid "Invalid header."
 msgstr "ヘッダーが不正です."
 
-#: src/message.h:50
+#: src/message.h:59
 msgid "Invalid response."
 msgstr "サーバーから不正なレスポンスを受け取りました."
 
-#: src/message.h:51
+#: src/message.h:60
 msgid "No header found."
 msgstr "ヘッダーが見つかりません."
 
-#: src/message.h:52
+#: src/message.h:61
 msgid "No status header."
 msgstr "status ヘッダーが見つかりません."
 
-#: src/message.h:53
+#: src/message.h:62
 msgid "Proxy connection failed."
 msgstr "Proxy 接続に失敗しました."
 
-#: src/message.h:54
+#: src/message.h:63
 msgid "Connection failed."
 msgstr "接続に失敗しました."
 
-#: src/message.h:55
+#: src/message.h:64
 #, c-format
 msgid ""
 "The requested filename and the previously registered one are not same. %s != "
 "%s"
 msgstr "リクエストしたファイル名 (%s) と登録済みファイル名 (%s) が異なります."
 
-#: src/message.h:56
+#: src/message.h:65
 #, c-format
 msgid "The response status is not successful. status = %d"
 msgstr "レスポンスのステータス (%d) が異常です."
 
-#: src/message.h:57
+#: src/message.h:66
 #, c-format
 msgid "Too large file size. size = %lld"
 msgstr "ファイルサイズ (%lld) が大きすぎます."
 
-#: src/message.h:58
+#: src/message.h:67
 #, c-format
 msgid "Transfer encoding %s is not supported."
 msgstr "トランスファー・エンコーディング %s はサポートされていません."
 
-#: src/message.h:59
+#: src/message.h:68
 msgid "SSL initialization failed."
 msgstr "SSL 初期化に失敗しました."
 
-#: src/message.h:60
+#: src/message.h:69
 #, c-format
 msgid "Size mismatch %lld != %lld"
 msgstr "サイズが合いません (%lld != %lld)"
 
-#: src/message.h:61
+#: src/message.h:70
 msgid "Got EOF from the server."
 msgstr "サーバーから EOF を受けとりました."
 
-#: src/main.cc:57
+#: src/main.cc:58
+#, c-format
+msgid ""
+"\n"
+"The download was complete. <%s>\n"
+msgstr ""
+"\n"
+"<%s> のダウンロードが完了しました.\n"
+
+#: src/main.cc:62
+msgid ""
+"\n"
+"The download was not complete because of errors. Check the log.\n"
+msgstr ""
+"\n"
+"ダウンロードはエラーのため完了していません. ログを確認してください.\n"
+
+#: src/main.cc:73 src/main.cc:82
 msgid ""
 "\n"
 "SIGINT signal received."
@@ -193,18 +210,18 @@ msgstr ""
 "\n"
 "SIGINT シグナルを受け取りました."
 
-#: src/main.cc:72
+#: src/main.cc:104
 #, c-format
 msgid "Unrecognized URL or unsupported protocol: %s\n"
 msgstr ""
 "%s は, 理解できない URL フォーマット, または, サポートされないプロトコルで"
 "す.\n"
 
-#: src/main.cc:78
+#: src/main.cc:110
 msgid " version "
 msgstr " バージョン "
 
-#: src/main.cc:82
+#: src/main.cc:114
 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"
@@ -235,31 +252,31 @@ 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:96
+#: src/main.cc:128
 #, c-format
 msgid "Contact Info: %s\n"
 msgstr "連絡先: %s\n"
 
-#: src/main.cc:102
+#: src/main.cc:134
 #, c-format
 msgid "Usage: %s [options] URL ...\n"
 msgstr "使い方: %s [オプション] URL ...\n"
 
-#: src/main.cc:104
+#: src/main.cc:136
 msgid "Options:"
 msgstr "オプション:"
 
-#: src/main.cc:105
+#: src/main.cc:137
 msgid " -d, --dir=DIR                The directory to store downloaded file."
 msgstr ""
 " -d, --dir=DIR                ダウンロードしたファイルを保存するディレクトリ."
 
-#: src/main.cc:106
+#: src/main.cc:138
 msgid " -o, --out=FILE               The file name for downloaded file."
 msgstr ""
 " -o, --out=FILE               ダウンロードしたファイルの保存先ファイル名."
 
-#: src/main.cc:107
+#: src/main.cc:139
 msgid ""
 " -l, --log=LOG                The file path to store log. If '-' is "
 "specified,\n"
@@ -269,11 +286,11 @@ msgstr ""
 "力\n"
 "                              に出力します."
 
-#: src/main.cc:109
+#: src/main.cc:141
 msgid " -D, --daemon                 Run as daemon."
 msgstr " -D, --daemon                 デーモンとして起動します."
 
-#: src/main.cc:110
+#: src/main.cc:142
 msgid ""
 " -s, --split=N                Download a file using N connections. N must "
 "be\n"
@@ -292,7 +309,7 @@ msgstr ""
 "ショ\n"
 "                              ンを確立します."
 
-#: src/main.cc:114
+#: src/main.cc:146
 msgid ""
 " --retry-wait=SEC             Set amount of time in second between requests\n"
 "                              for errors. Specify a value between 0 and 60.\n"
@@ -303,13 +320,13 @@ msgstr ""
 "                              す. 0 - 60 の値を指定してください.\n"
 "                              デフォルト値: 5"
 
-#: src/main.cc:117
+#: src/main.cc:149
 msgid " -t, --timeout=SEC            Set timeout in second. Default: 60"
 msgstr ""
 " -t, --timeout=SEC            タイムアウトとなる時間を秒で指定します.\n"
 "                              デフォルト値: 60"
 
-#: src/main.cc:118
+#: src/main.cc:150
 msgid ""
 " -m, --max-tries=N            Set number of tries. 0 means unlimited.\n"
 "                              Default: 5"
@@ -318,7 +335,7 @@ msgstr ""
 "行\n"
 "                              します. デフォルト値: 5"
 
-#: src/main.cc:120
+#: src/main.cc:152
 msgid ""
 " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
 "                              K or M(1K = 1024, 1M = 1024K). This\n"
@@ -331,7 +348,7 @@ msgstr ""
 "1024K).\n"
 "                              1024 以上の値を指定してください."
 
-#: src/main.cc:124
+#: src/main.cc:156
 msgid ""
 " --http-proxy=HOST:PORT       Use HTTP proxy server. This affects to all\n"
 "                              URLs."
@@ -340,14 +357,14 @@ msgstr ""
 "シ\n"
 "                              ョンはすべての URL に影響します."
 
-#: src/main.cc:126
+#: src/main.cc:158
 msgid " --http-user=USER             Set HTTP user. This affects to all URLs."
 msgstr ""
 " --http-user=USER             HTTP での認証ユーザーを指定します. このオプショ"
 "ン\n"
 "                              はすべての URL に影響します."
 
-#: src/main.cc:127
+#: src/main.cc:159
 msgid ""
 " --http-passwd=PASSWD         Set HTTP password. This affects to all URLs."
 msgstr ""
@@ -355,7 +372,7 @@ msgstr ""
 "ショ\n"
 "                              ンはすべての URL に影響します."
 
-#: src/main.cc:128
+#: src/main.cc:160
 msgid ""
 " --http-proxy-user=USER       Set HTTP proxy user. This affects to all URLs"
 msgstr ""
@@ -365,7 +382,7 @@ msgstr ""
 "ま\n"
 "                              す."
 
-#: src/main.cc:129
+#: src/main.cc:161
 msgid ""
 " --http-proxy-passwd=PASSWD   Set HTTP proxy password. This affects to all "
 "URLs."
@@ -376,7 +393,7 @@ msgstr ""
 "し\n"
 "                              ます."
 
-#: src/main.cc:130
+#: src/main.cc:162
 msgid ""
 " --http-proxy-method=METHOD   Set the method to use in proxy request.\n"
 "                              METHOD is either 'get' or 'tunnel'.\n"
@@ -387,7 +404,7 @@ msgstr ""
 "                              す. 'get' または 'tunnel' を指定してください.\n"
 "                              デフォルト値: tunnel"
 
-#: src/main.cc:133
+#: src/main.cc:165
 msgid ""
 " --http-auth-scheme=SCHEME    Set HTTP authentication scheme. Currently, "
 "basic\n"
@@ -405,14 +422,14 @@ msgstr ""
 "定\n"
 "                              する必要があります."
 
-#: src/main.cc:137
+#: src/main.cc:169
 msgid " --referer=REFERER            Set Referer. This affects to all URLs."
 msgstr ""
 " --referer=REFERER            リファラーを指定します. このオプションはすべて"
 "の\n"
 "                               URL に影響します."
 
-#: src/main.cc:138
+#: src/main.cc:170
 msgid ""
 " --ftp-user=USER              Set FTP user. This affects to all URLs.\n"
 "                              Default: anonymous"
@@ -422,7 +439,7 @@ msgstr ""
 "                              はすべての URL に影響します.\n"
 "                              デフォルト値: anonymous"
 
-#: src/main.cc:140
+#: src/main.cc:172
 msgid ""
 " --ftp-passwd=PASSWD          Set FTP password. This affects to all URLs.\n"
 "                              Default: ARIA2USER@"
@@ -432,7 +449,7 @@ msgstr ""
 "                              ンはすべての URL に影響します.\n"
 "                              デフォルト値: ARIA2USER@"
 
-#: src/main.cc:142
+#: src/main.cc:174
 msgid ""
 " --ftp-type=TYPE              Set FTP transfer type. TYPE is either "
 "'binary'\n"
@@ -443,11 +460,11 @@ msgstr ""
 "                              'ascii' を指定してください. デフォルト値: "
 "binary"
 
-#: src/main.cc:145
+#: src/main.cc:177
 msgid " -p, --ftp-pasv               Use passive mode in FTP."
 msgstr " -p, --ftp-pasv               FTP で passive モードを使用します."
 
-#: src/main.cc:146
+#: src/main.cc:178
 msgid ""
 " --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' "
 "or\n"
@@ -460,16 +477,29 @@ msgstr ""
 "く\n"
 "                              ださい. デフォルト値: tunnel"
 
-#: src/main.cc:149
+#: src/main.cc:181
+msgid " --torrent-file=TORRENT_FILE  The file path to .torrent file."
+msgstr ""
+
+#: src/main.cc:182
+msgid ""
+" --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"
+msgstr ""
+
+#: src/main.cc:186
 msgid " -v, --version                Print the version number and exit."
 msgstr " -v, --version                バージョン番号を表示し, 終了します."
 
-#: src/main.cc:150
+#: src/main.cc:187
 msgid " -h, --help                   Print this message and exit."
 msgstr ""
 " -h, --help                   このヘルプメッセージを表示し, 終了します."
 
-#: src/main.cc:153
+#: src/main.cc:190
 msgid ""
 " You can specify multiple URLs. All URLs must point to the same file\n"
 " or downloading fails."
@@ -478,88 +508,81 @@ msgstr ""
 "れ\n"
 " ばなりません. さもなくばダウンロードは失敗します."
 
-#: src/main.cc:156
+#: src/main.cc:193
 msgid "Examples:"
 msgstr "例:"
 
-#: src/main.cc:157
+#: src/main.cc:194
 msgid " Download a file by 1 connection:"
 msgstr " 1 コネクションでのダウンロード:"
 
-#: src/main.cc:159
+#: src/main.cc:196
 msgid " Download a file by 2 connections:"
 msgstr " 2 コネクションでのダウンロード:"
 
-#: src/main.cc:161
+#: src/main.cc:198
 msgid " Download a file by 2 connections, each connects to a different server:"
 msgstr " 二つの異なるサーバーに接続してダウンロード:"
 
-#: src/main.cc:163
+#: src/main.cc:200
 msgid " You can mix up different protocols:"
 msgstr " 異なるプロトコルを混合させてダウンロード:"
 
-#: src/main.cc:166
+#: src/main.cc:202
+#, fuzzy
+msgid " Download a torrent"
+msgstr "CUID#%d - ダウンロードを中止します."
+
+#: src/main.cc:205
 #, c-format
 msgid "Reports bugs to %s"
 msgstr "バグレポートはこちらへ: %s"
 
-#: src/main.cc:240
+#: src/main.cc:284
 msgid "unrecognized proxy format"
 msgstr "理解できないProxyフォーマットです."
 
-#: src/main.cc:266
+#: src/main.cc:310
 msgid "Currently, supported authentication scheme is basic."
 msgstr "現在サポートされている認証方法は basic です."
 
-#: src/main.cc:275
+#: src/main.cc:319
 msgid "retry-wait must be between 0 and 60."
 msgstr "retry-wait は 0 から 60 の間で指定してください."
 
-#: src/main.cc:292
+#: src/main.cc:336
 msgid "ftp-type must be either 'binary' or 'ascii'."
 msgstr "ftp-type は 'binary' または 'ascii' を指定してください."
 
-#: src/main.cc:301
+#: src/main.cc:345
 msgid "ftp-via-http-proxy must be either 'get' or 'tunnel'."
 msgstr "ftp-via-http-proxy は 'get' または 'tunnel' を指定してください."
 
-#: src/main.cc:319
+#: src/main.cc:363
 msgid "min-segment-size invalid"
 msgstr "min-segment-size が不正です."
 
-#: src/main.cc:330
+#: src/main.cc:374
 msgid "http-proxy-method must be either 'get' or 'tunnel'."
 msgstr "http-proxy-method は 'get' または 'tunnel' を指定してください."
 
-#: src/main.cc:357
+#: src/main.cc:388
+#, fuzzy
+msgid "follow-torrent must be either 'true' or 'false'."
+msgstr "ftp-type は 'binary' または 'ascii' を指定してください."
+
+#: src/main.cc:414
 msgid "split must be between 1 and 5."
 msgstr "split は 1 - 5 の値を指定してください."
 
-#: src/main.cc:367
+#: src/main.cc:424
 msgid "timeout must be between 1 and 600"
 msgstr "timeout は 1 - 600 の値を指定してください."
 
-#: src/main.cc:376
+#: src/main.cc:433
 msgid "max-tries invalid"
 msgstr "max-tries が不正です."
 
-#: src/main.cc:398
+#: src/main.cc:456
 msgid "specify at least one URL"
 msgstr "一個以上の URL を指定してください."
-
-#: src/main.cc:449
-#, c-format
-msgid ""
-"\n"
-"The download was complete. <%s>\n"
-msgstr ""
-"\n"
-"<%s> のダウンロードが完了しました.\n"
-
-#: src/main.cc:451
-msgid ""
-"\n"
-"The download was not complete because of errors. Check the log.\n"
-msgstr ""
-"\n"
-"ダウンロードはエラーのため完了していません. ログを確認してください.\n"

+ 61 - 2
src/AbstractDiskWriter.cc

@@ -27,6 +27,8 @@
 #include <fcntl.h>
 #include "DlAbortEx.h"
 #include "File.h"
+#include <openssl/evp.h>
+#include "Util.h"
 
 AbstractDiskWriter::AbstractDiskWriter():fd(0) {}
 
@@ -49,7 +51,7 @@ void AbstractDiskWriter::openExistingFile(string filename) {
     throw new DlAbortEx(strerror(errno));
   }
 
-  if((fd = open(filename.c_str(), O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
+  if((fd = open(filename.c_str(), O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
     throw new DlAbortEx(strerror(errno));
   }
 }
@@ -60,7 +62,7 @@ void AbstractDiskWriter::createFile(string filename, int addFlags) {
 //   if(filename.empty()) {
 //     filename = "index.html";
 //   }
-  if((fd = open(filename.c_str(), O_CREAT|O_WRONLY|O_TRUNC|addFlags, S_IRUSR|S_IWUSR)) < 0) {
+  if((fd = open(filename.c_str(), O_CREAT|O_RDWR|O_TRUNC|addFlags, S_IRUSR|S_IWUSR)) < 0) {
     throw new DlAbortEx(strerror(errno));
   }  
 }
@@ -70,3 +72,60 @@ void AbstractDiskWriter::writeDataInternal(const char* data, int len) {
     throw new DlAbortEx(strerror(errno));
   }
 }
+
+int AbstractDiskWriter::readDataInternal(char* data, int len) {
+  int ret;
+  if((ret = read(fd, data, len)) < 0) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  return ret;
+}
+
+string AbstractDiskWriter::sha1Sum(long long int offset, long long int length) {
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+  EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
+
+  try {
+    int BUFSIZE = 4096;
+    char buf[BUFSIZE];
+    for(int i = 0; i < length/BUFSIZE; i++) {
+      if(BUFSIZE != readData(buf, BUFSIZE, offset)) {
+	throw "error";
+      }
+      EVP_DigestUpdate(&ctx, buf, BUFSIZE);
+      offset += BUFSIZE;
+    }
+    int r = length%BUFSIZE;
+    if(r > 0) {
+      if(r != readData(buf, r, offset)) {
+	throw "error";
+      }
+      EVP_DigestUpdate(&ctx, buf, r);
+    }
+    unsigned char hashValue[20];
+    int len;
+    EVP_DigestFinal_ex(&ctx, hashValue, (unsigned int*)&len);
+    EVP_MD_CTX_cleanup(&ctx);
+    return Util::toHex(hashValue, 20);
+  } catch(string ex) {
+    EVP_MD_CTX_cleanup(&ctx);
+    throw new DlAbortEx(strerror(errno));
+  }
+}
+
+void AbstractDiskWriter::seek(long long int offset) {
+  if(offset != lseek(fd, offset, SEEK_SET)) {
+    throw new DlAbortEx(strerror(errno));
+  }
+}
+
+void AbstractDiskWriter::writeData(const char* data, int len, long long int offset) {
+  seek(offset);
+  writeDataInternal(data, len);
+}
+
+int AbstractDiskWriter::readData(char* data, int len, long long int offset) {
+  seek(offset);
+  return readDataInternal(data, len);
+}

+ 9 - 0
src/AbstractDiskWriter.h

@@ -31,6 +31,7 @@ protected:
   void createFile(string filename, int addFlags = 0);
 
   void writeDataInternal(const char* data, int len);
+  int readDataInternal(char* data, int len);
 public:
   AbstractDiskWriter();
   virtual ~AbstractDiskWriter();
@@ -38,6 +39,14 @@ public:
   void closeFile();
 
   void openExistingFile(string filename);
+
+  string sha1Sum(long long int offset, long long int length);
+
+  void seek(long long int offset);
+
+  void writeData(const char* data, int len, long long int offset);
+
+  int readData(char* data, int len, long long int offset);
 };
 
 #endif // _D_ABSTRACT_DISK_WRITER_H_

+ 277 - 0
src/BitfieldMan.cc

@@ -0,0 +1,277 @@
+/* <!-- 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 "BitfieldMan.h"
+#include <string.h>
+
+BitfieldMan::BitfieldMan(int blockLength, long long int totalLength)
+  :blockLength(blockLength), totalLength(totalLength) {
+  if(blockLength > 0 && totalLength > 0) {
+    blocks = totalLength/blockLength+(totalLength%blockLength ? 1 : 0);
+    bitfieldLength = blocks/8+(blocks%8 ? 1 : 0);
+    bitfield = new unsigned char[bitfieldLength];
+    useBitfield = new unsigned char[bitfieldLength];
+    memset(bitfield, 0, bitfieldLength);
+    memset(useBitfield, 0, bitfieldLength);
+  }
+}
+
+BitfieldMan::BitfieldMan(const BitfieldMan& bitfieldMan) {
+  blockLength = bitfieldMan.blockLength;
+  totalLength = bitfieldMan.totalLength;
+  blocks = bitfieldMan.blocks;
+  bitfieldLength = bitfieldMan.bitfieldLength;
+  bitfield = new unsigned char[bitfieldLength];
+  useBitfield = new unsigned char[bitfieldLength];
+  memcpy(bitfield, bitfieldMan.bitfield, bitfieldLength);
+  memcpy(useBitfield, bitfieldMan.useBitfield, bitfieldLength);
+}
+
+BitfieldMan::~BitfieldMan() {
+  delete [] bitfield;
+  delete [] useBitfield;
+}
+
+BitfieldMan& BitfieldMan::operator=(const BitfieldMan& bitfieldMan) {
+  if(this != &bitfieldMan) {
+    blockLength = bitfieldMan.blockLength;
+    totalLength = bitfieldMan.totalLength;
+    if(bitfieldLength != bitfieldMan.bitfieldLength) {
+      delete [] bitfield;
+      delete [] useBitfield;
+      bitfield = new unsigned char[bitfieldMan.bitfieldLength];
+      useBitfield = new unsigned char[bitfieldMan.bitfieldLength];
+    }
+    blocks = bitfieldMan.blocks;
+    bitfieldLength = bitfieldMan.bitfieldLength;
+    memcpy(bitfield, bitfieldMan.bitfield, bitfieldLength);
+    memcpy(useBitfield, bitfieldMan.useBitfield, bitfieldLength);
+  }
+  return *this;
+}
+
+int BitfieldMan::countSetBit(const unsigned char* bitfield, int len) const {
+  int count = 0;
+  for(int i = 0; i < len; i++) {
+    unsigned char bit = bitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	count++;
+      }
+    }
+  }
+  return count;
+}
+
+int BitfieldMan::getMissingIndexRandomly(const unsigned char* bitfield, int len, int randMax) const {
+  int index = -1;
+  int nth = 1+(int)(((double)randMax)*random()/(RAND_MAX+1.0));
+  for(int i = 0; i < len && index == -1; i++) {
+    unsigned char bit = bitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	nth--;
+	if(nth == 0) {
+	  index = i*8+7-bs;
+	  break;
+	}
+      }
+    }
+  }
+  return index;
+}
+
+int BitfieldMan::getMissingIndex(const unsigned char* peerBitfield, int length) const {
+  if(bitfieldLength != length) {
+    return -1;
+  }
+  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
+  for(int i = 0; i < bitfieldLength; i++) {
+    tempBitfield[i] = peerBitfield[i] & ~bitfield[i];
+  }
+  int max = countSetBit(tempBitfield, bitfieldLength);
+  int index = getMissingIndexRandomly(tempBitfield, bitfieldLength, max);
+  return index;
+}
+
+int BitfieldMan::getMissingUnusedIndex(const unsigned char* peerBitfield, int length) const {
+  if(bitfieldLength != length) {
+    return -1;
+  }
+  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
+  for(int i = 0; i < bitfieldLength; i++) {
+    tempBitfield[i] = peerBitfield[i] & ~bitfield[i] & ~useBitfield[i];
+  }
+  int max = countSetBit(tempBitfield, bitfieldLength);
+  /*
+  int max = 0;
+  for(int i = 0; i < bitfieldLength; i++) {
+    unsigned char bit = tempBitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	max++;
+      }
+    }
+  }
+  */
+  int index = getMissingIndexRandomly(tempBitfield, bitfieldLength, max);
+  /*
+  int index = -1;
+  int nth = 1+(int)(((double)max)*random()/(RAND_MAX+1.0));
+  for(int i = 0; i < bitfieldLength && index == -1; i++) {
+    unsigned char bit = tempBitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	nth--;
+	if(nth == 0) {
+	  index = i*8+7-bs;
+	  break;
+	}
+      }
+    }
+  }
+  */
+  return index;
+}
+
+int BitfieldMan::getFirstMissingUnusedIndex(const unsigned char* peerBitfield, int length) const {
+  if(bitfieldLength != length) {
+    return -1;
+  }
+  for(int i = 0; i < bitfieldLength; i++) {
+    unsigned char bit = peerBitfield[i] & ~bitfield[i] & ~useBitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	return i*8+7-bs;
+      }
+    }
+  }
+  return -1;
+}
+
+int BitfieldMan::getFirstMissingUnusedIndex() const {
+  for(int i = 0; i < bitfieldLength; i++) {
+    unsigned char bit = ~bitfield[i] & ~useBitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	return i*8+7-bs;
+      }
+    }
+  }
+  return -1;
+}
+
+vector<int> BitfieldMan::getAllMissingIndexes() const {
+  vector<int> missingIndexes;
+  for(int i = 0; i < bitfieldLength; i++) {
+    unsigned char bit = ~bitfield[i];
+    for(int bs = 7; bs >= 0 && i*8+7-bs < blocks; bs--) {
+      unsigned char mask = 1 << bs;
+      if(bit & mask) {
+	missingIndexes.push_back(i*8+7-bs);
+      }
+    }
+  }
+  return missingIndexes;
+}
+
+int BitfieldMan::countMissingBlock() const {
+  return blocks-countSetBit(bitfield, bitfieldLength);
+}
+
+bool BitfieldMan::setUseBit(int index) {
+  if(blocks <= index) { return false; }
+  unsigned char mask = 128 >> index%8;
+  useBitfield[index/8] |= mask;
+  return true;
+}
+
+bool BitfieldMan::unsetUseBit(int index) {
+  if(blocks <= index) { return false; }
+  unsigned char mask = 128 >> index%8;
+  useBitfield[index/8] &= ~mask;
+  return true;
+}
+
+bool BitfieldMan::setBit(int index) {
+  if(blocks <= index) { return false; }
+  unsigned char mask = 128 >> index%8;
+  bitfield[index/8] |= mask;
+  return true;
+}
+bool BitfieldMan::unsetBit(int index) {
+  if(blocks <= index) { return false; }
+  unsigned char mask = 128 >> index%8;
+  bitfield[index/8] &= ~mask;
+  return true;
+}
+
+bool BitfieldMan::isAllBitSet() const {
+  for(int i = 0; i < bitfieldLength-1; i++) {
+    if(bitfield[i] != 0xff) {
+      return false;
+    }
+  }
+  unsigned char b = ~((128 >> (blocks-1)%8)-1);
+  if(bitfield[bitfieldLength-1] != b) {
+    return false;
+  }
+  return true;
+}
+
+bool BitfieldMan::isBitSetInternal(const unsigned char* bitfield, int index) const {
+  if(blocks <= index) { return false; }
+  unsigned char mask = 128 >> index%8;
+  return (bitfield[index/8] & mask) != 0;
+}
+
+bool BitfieldMan::isBitSet(int index) const {
+  return isBitSetInternal(bitfield, index);
+}
+
+bool BitfieldMan::isUseBitSet(int index) const {
+  return isBitSetInternal(useBitfield, index);
+}
+
+void BitfieldMan::setBitfield(const unsigned char* bitfield, int bitfieldLength) {
+  if(this->bitfieldLength != bitfieldLength) {
+    return;
+  }
+  memcpy(this->bitfield, bitfield, this->bitfieldLength);
+  memset(this->useBitfield, 0, this->bitfieldLength);
+}
+
+void BitfieldMan::clearAllBit() {
+  memset(this->bitfield, 0, this->bitfieldLength);
+  memset(this->useBitfield, 0, this->bitfieldLength);
+}
+
+void BitfieldMan::setAllBit() {
+  for(int i = 0; i < blocks; i++) {
+    setBit(i);
+  }
+}

+ 90 - 0
src/BitfieldMan.h

@@ -0,0 +1,90 @@
+/* <!-- 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_BITFIELD_MAN_H_
+#define _D_BITFIELD_MAN_H_
+
+#include "common.h"
+#include <vector>
+
+class BitfieldMan {
+private:
+  int blockLength;
+  long long int totalLength;
+  unsigned char* bitfield;
+  unsigned char* useBitfield;
+  int bitfieldLength;
+  int blocks;
+
+  int countSetBit(const unsigned char* bitfield, int len) const;
+  int getMissingIndexRandomly(const unsigned char* bitfield, int len, int randMax) const;
+  bool isBitSetInternal(const unsigned char* bitfield, int index) const;
+public:
+  BitfieldMan(int blockLength, long long int totalLength);
+  BitfieldMan(const BitfieldMan& bitfieldMan);
+  ~BitfieldMan();
+
+  BitfieldMan& operator=(const BitfieldMan& bitfieldMan);
+
+  int getBlockLength() const { return blockLength; }
+  int getLastBlockLength() const {
+    return totalLength-blockLength*(blocks-1);
+  }
+  int getBlockLength(int index) const {
+    if(index == blocks-1) {
+      return getLastBlockLength();
+    } else if(0 <= index && index < blocks-1) {
+      return getBlockLength();
+    } else {
+      return 0;
+    }
+  }
+  long long int getTotalLength() const { return totalLength; }
+
+  int getMissingIndex(const unsigned char* bitfield, int len) const;
+  int getFirstMissingUnusedIndex(const unsigned char* bitfield, int len) const;
+  int getFirstMissingUnusedIndex() const;
+  int getMissingUnusedIndex(const unsigned char* bitfield, int len) const;
+  vector<int> getAllMissingIndexes() const;
+  int countMissingBlock() const;
+  bool setUseBit(int index);
+  bool unsetUseBit(int index);
+
+  bool setBit(int index);
+  bool unsetBit(int index);
+
+  bool isBitSet(int index) const;
+  bool isUseBitSet(int index) const;
+
+  bool isAllBitSet() const;
+
+  const unsigned char* getBitfield() const { return bitfield; }
+  int getBitfieldLength() const { return bitfieldLength; }
+
+  int countBlock() const { return blocks; }
+
+  void setBitfield(const unsigned char* bitfield, int bitfieldLength);
+
+  void clearAllBit();
+  void setAllBit();
+};
+
+#endif // _D_BITFIELD_MAN_H_

+ 34 - 0
src/ConsoleDownloadEngine.cc

@@ -35,3 +35,37 @@ void ConsoleDownloadEngine::sendStatistics(long long int currentSize, long long
     speed/1000.0 << "KB/s " <<
     "(" << commands.size() << " connections)" << flush;
 }
+
+void ConsoleDownloadEngine::initStatistics() {
+  cp.tv_sec = cp.tv_usec = 0;
+  speed = 0;
+  psize = 0;
+}
+
+void ConsoleDownloadEngine::calculateStatistics() {
+  long long int dlSize = segmentMan->getDownloadedSize();
+  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));
+      speed = (nspeed+speed)/2;
+      cp = now;
+      psize = dlSize;
+      sendStatistics(dlSize, segmentMan->totalSize);
+    }
+  }
+}
+
+void ConsoleDownloadEngine::onEndOfRun() {
+  diskWriter->closeFile();
+  if(segmentMan->finished()) {
+    segmentMan->remove();
+  } else {
+    segmentMan->save();
+  }
+}

+ 7 - 0
src/ConsoleDownloadEngine.h

@@ -25,8 +25,15 @@
 #include "DownloadEngine.h"
 
 class ConsoleDownloadEngine : public DownloadEngine {
+private:
+  struct timeval cp;
+  long long int psize;
+  int speed;
 protected:
   void sendStatistics(long long int currentSize, long long int totalSize);
+  void initStatistics();
+  void calculateStatistics();
+  void onEndOfRun();
 public:
   ConsoleDownloadEngine();
   ~ConsoleDownloadEngine();

+ 81 - 0
src/Data.cc

@@ -0,0 +1,81 @@
+/* <!-- 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 "Data.h"
+#include "MetaEntryVisitor.h"
+
+Data::Data(const char* data, int len, bool number):number(number) {
+  if(data == NULL) {
+    this->data = NULL;
+    this->len = 0;
+  } else {
+    this->data = new char[len];
+    memcpy(this->data, data, len);
+    this->len = len;
+  }
+}
+
+Data::~Data() {
+  delete [] data;
+}
+
+string Data::toString() const {
+  if(len == 0) {
+    return "";
+  } else {
+    char* temp = new char[len+1];
+    memcpy(temp, data, len);
+    temp[len] = '\0';
+    return string(temp);
+  }
+}
+
+const char* Data::getData() const {
+  if(this->len == 0) {
+    return NULL;
+  } else {
+    return data;
+  }
+}
+
+int Data::getLen() const {
+  return len;
+}
+
+int Data::toInt() const {
+  return (int)toLLInt();
+}
+
+long long int Data::toLLInt() const {
+  if(len == 0) {
+    return 0;
+  } else {
+    return strtoll(data, NULL, 10);
+  }
+}
+
+bool Data::isNumber() const {
+  return number;
+}
+
+void Data::accept(MetaEntryVisitor* v) const {
+  v->visit(this);
+}

+ 54 - 0
src/Data.h

@@ -0,0 +1,54 @@
+/* <!-- 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_DATA_H_
+#define _D_DATA_H_
+
+#include "MetaEntry.h"
+#include <string>
+
+using namespace std;
+
+class Data : public MetaEntry {
+private:
+  int len;
+  char* data;
+  bool number;
+public:
+  /**
+   * This class stores the copy of data. So caller must take care of freeing
+   * memory of data.
+   */
+  Data(const char* data, int len, bool number = false);
+  ~Data();
+
+  string toString() const;
+  int toInt() const;
+  long long int toLLInt() const;
+  
+  const char* getData() const;
+  int getLen() const;
+  bool isNumber() const;
+
+  void accept(MetaEntryVisitor* v) const;
+};
+
+#endif // _D_DATA_H_

+ 0 - 7
src/DefaultDiskWriter.cc

@@ -30,10 +30,3 @@ DefaultDiskWriter::~DefaultDiskWriter() {}
 void DefaultDiskWriter::initAndOpenFile(string filename) {
   createFile(filename);
 }
-
-void DefaultDiskWriter::writeData(const char* data, int len, long long int offset) {
-  if(offset != lseek(fd, offset, SEEK_SET)) {
-    throw new DlAbortEx(strerror(errno));
-  }
-  writeDataInternal(data, len);
-}

+ 0 - 2
src/DefaultDiskWriter.h

@@ -30,8 +30,6 @@ public:
   ~DefaultDiskWriter();
 
   void initAndOpenFile(string filename);
-
-  void writeData(const char* data, int len, long long int position);
 };
 
 #endif // _D_DEFAULT_DISK_WRITER_H_

+ 57 - 0
src/Dictionary.cc

@@ -0,0 +1,57 @@
+/* <!-- 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 "Dictionary.h"
+#include "MetaEntryVisitor.h"
+
+Dictionary::Dictionary() {}
+
+Dictionary::~Dictionary() {
+  clearTable();
+}
+
+void Dictionary::clearTable() {
+  for(MetaTable::iterator itr = table.begin(); itr != table.end(); itr++) {
+    delete itr->second;
+  }
+}
+
+const MetaEntry* Dictionary::get(string name) const {
+  MetaTable::const_iterator itr = table.find(name);
+  if(itr == table.end()) {
+    return NULL;
+  } else {
+    return itr->second;
+  }
+}
+
+void Dictionary::put(string name, MetaEntry* entry) {
+  table[name] = entry;
+  order.push_back(name);
+}
+
+void Dictionary::accept(MetaEntryVisitor* v) const {
+  v->visit(this);
+}
+
+const vector<string>& Dictionary::getOrder() const {
+  return order;
+}

+ 51 - 0
src/Dictionary.h

@@ -0,0 +1,51 @@
+/* <!-- 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_DICTIONARY_H_
+#define _D_DICTIONARY_H_
+
+#include "MetaEntry.h"
+#include <map>
+#include <vector>
+#include <string>
+
+using namespace std;
+
+typedef map<string, MetaEntry*> MetaTable;
+
+class Dictionary : public MetaEntry {
+private:
+  MetaTable table;
+  vector<string> order;
+  void clearTable();
+public:
+  Dictionary();
+  ~Dictionary();
+
+  const MetaEntry* get(string name) const;
+  void put(string name, MetaEntry* entry);
+
+  void accept(MetaEntryVisitor* v) const;
+  const vector<string>& getOrder() const;
+  
+};
+
+#endif // _D_DICTIONARY_H_

+ 59 - 0
src/Directory.cc

@@ -0,0 +1,59 @@
+/* <!-- 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 "Directory.h"
+#include "File.h"
+#include "DlAbortEx.h"
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+Directory::Directory(string name):name(name) {}
+
+Directory::~Directory() {
+  for(Files::iterator itr = files.begin(); itr != files.end(); itr++) {
+    delete *itr;
+  }
+}
+
+void Directory::createDir(string parentDir, bool recursive) const {
+  string path = parentDir+"/"+name;
+  File f(path);
+  if(f.exists()) {
+    if(!f.isDir()) {
+      throw new DlAbortEx("%s is already exists and it is not a directory.",
+			  path.c_str());
+    }
+  } else {
+    if(mkdir(path.c_str(), S_IRUSR|S_IWUSR|S_IXUSR) == -1) {
+      throw new DlAbortEx(strerror(errno));
+    }
+  }
+  if(recursive) {
+    for(Files::const_iterator itr = files.begin(); itr != files.end(); itr++) {
+      (*itr)->createDir(path, true);
+    }
+  }
+}
+
+void Directory::addFile(Directory* directory) {
+  files.push_back(directory);
+}

+ 44 - 0
src/Directory.h

@@ -0,0 +1,44 @@
+/* <!-- 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_DIRECTORY_H_
+#define _D_DIRECTORY_H_
+
+#include "common.h"
+#include <string>
+#include <vector>
+
+class Directory {
+
+typedef vector<Directory*> Files;
+
+private:
+  string name;
+  Files files;
+public:
+  Directory(string name);
+  ~Directory();
+
+  void createDir(string parentDir, bool recursive) const;
+  void addFile(Directory* directory);
+};
+
+#endif // _D_DIRECTORY_H_

+ 6 - 0
src/DiskWriter.h

@@ -64,6 +64,12 @@ public:
    * @param position the offset of this binary stream
    */
   virtual void writeData(const char* data, int len, long long int position = 0) = 0;
+
+  virtual int readData(char* data, int len, long long int position) = 0;
+
+  virtual string sha1Sum(long long int offset, long long int length) = 0;
+
+  virtual void seek(long long int offset) = 0;
 };
 
 #endif // _D_DISK_WRITER_H_

+ 10 - 30
src/DownloadEngine.cc

@@ -29,7 +29,7 @@
 
 using namespace std;
 
-DownloadEngine::DownloadEngine():noWait(false) {}
+DownloadEngine::DownloadEngine():noWait(false), segmentMan(NULL) {}
 
 DownloadEngine::~DownloadEngine() {
   assert(rsockets.empty());
@@ -47,43 +47,23 @@ void DownloadEngine::run() {
 	delete(com);
       }
     }
+    shortSleep();
     if(!noWait && !commands.empty()) {
       waitData();
     }
     noWait = false;
     calculateStatistics();
   }
-  diskWriter->closeFile();
-  if(segmentMan->finished()) {
-    segmentMan->remove();
-  } else {
-    segmentMan->save();
-  }
+  onEndOfRun();
 }
 
-void DownloadEngine::initStatistics() {
-  cp.tv_sec = cp.tv_usec = 0;
-  speed = 0;
-  psize = 0;
-}
-
-void DownloadEngine::calculateStatistics() {
-  long long int dlSize = segmentMan->getDownloadedSize();
-  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));
-      speed = (nspeed+speed)/2;
-      cp = now;
-      psize = dlSize;
-      sendStatistics(dlSize, segmentMan->totalSize);
-    }
-  }
+void DownloadEngine::shortSleep() const {
+  struct timeval tv;
+  tv.tv_sec = 0;
+  tv.tv_usec = 1000;
+  fd_set rfds;
+  FD_ZERO(&rfds);
+  select(0, &rfds, NULL, NULL, &tv);
 }
 
 void DownloadEngine::waitData() {

+ 4 - 6
src/DownloadEngine.h

@@ -41,15 +41,13 @@ private:
   vector<Socket*> rsockets;
   vector<Socket*> wsockets;
 
+  void shortSleep() const;
   bool addSocket(vector<Socket*>& sockets, Socket* socket);
   bool deleteSocket(vector<Socket*>& sockets, Socket* socket);
-  struct timeval cp;
-  long long int psize;
-  void initStatistics();
-  void calculateStatistics();
 protected:
-  int speed;
-  virtual void sendStatistics(long long int currentSize, long long int totalSize) {};
+  virtual void initStatistics() = 0;
+  virtual void calculateStatistics() = 0;
+  virtual void onEndOfRun() = 0;
 public:
   bool noWait;
   queue<Command*> commands;

+ 8 - 0
src/File.cc

@@ -62,3 +62,11 @@ bool File::remove() {
     return false;
   }
 }
+
+long long int File::size() {
+  struct stat fstat;
+  if(fillStat(fstat) < 0) {
+    return 0;
+  }
+  return fstat.st_size;
+}

+ 2 - 0
src/File.h

@@ -58,6 +58,8 @@ public:
    * If name denotes a directory, it must be empty in order to delete.
    */
   bool remove();
+
+  long long int size();
 };
 
 #endif // _D_FILE_H_

+ 47 - 0
src/HandshakeMessage.h

@@ -0,0 +1,47 @@
+/* <!-- 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_HANDSHAKE_MESSAGE_H_
+#define _D_HANDSHAKE_MESSAGE_H_
+
+#include "common.h"
+#include "Util.h"
+
+#define PSTR "BitTorrent protocol"
+#define HANDSHAKE_MESSAGE_LENGTH 68
+
+class HandshakeMessage {
+public:
+  char pstrlen;
+  string pstr;
+  unsigned char infoHash[20];
+  char peerId[20];
+public:
+  HandshakeMessage() {}
+  ~HandshakeMessage() {}
+
+  string toString() const {
+    return "handshake peerId="+
+      Util::urlencode((unsigned char*)peerId, sizeof(peerId));
+  }
+};
+
+#endif // _D_HANDSHAKE_MESSAGE_H_

+ 46 - 25
src/HttpConnection.cc

@@ -27,7 +27,7 @@
 #include "prefs.h"
 
 HttpConnection::HttpConnection(int cuid, const Socket* socket, const Request* req, const Option* op, const Logger* logger):
-  cuid(cuid), socket(socket), req(req), option(op), logger(logger) {}
+  cuid(cuid), socket(socket), req(req), option(op), logger(logger), headerBufLength(0) {}
 
 void HttpConnection::sendRequest(const Segment& segment) const {
   string request = createRequest(segment);
@@ -101,39 +101,60 @@ string HttpConnection::createRequest(const Segment& segment) const {
   return request;
 }
 
-int HttpConnection::receiveResponse(HttpHeader& headers) {
-  char buf[512];
-  while(socket->isReadable(0)) {
-    int size = sizeof(buf)-1;
-    socket->peekData(buf, size);
-    if(size == 0) {
-      throw new DlRetryEx(EX_INVALID_RESPONSE);
+int HttpConnection::findEndOfHeader(const char* buf, const char* substr, int bufLength) const {
+  const char* p = buf;
+  while(bufLength > p-buf && bufLength-(p-buf) >= (int)strlen(substr)) {
+    if(memcmp(p, substr, strlen(substr)) == 0) {
+      return p-buf;
     }
-    buf[size] = '\0';
-    int hlenTemp = header.size();
-    header += buf;
-    string::size_type p;
-    if((p = header.find("\r\n\r\n")) == string::npos) {
-      socket->readData(buf, size);
+    p++;
+  }
+  return -1;
+}
+
+int HttpConnection::receiveResponse(HttpHeader& headers) {
+  //char buf[512];
+  string header;
+  int delimiterSwith = 0;
+  char* delimiters[] = { "\r\n", "\n" };
+
+  int size = HEADERBUF_SIZE-headerBufLength;
+  if(size < 0) {
+    // TODO too large header
+    throw new DlRetryEx("too large header > 4096");
+  }
+  socket->peekData(headerBuf+headerBufLength, size);
+  if(size == 0) {
+    throw new DlRetryEx(EX_INVALID_RESPONSE);
+  }
+  //buf[size] = '\0';
+  int hlenTemp = headerBufLength+size;
+  //header += buf;
+  //string::size_type p;
+  int eohIndex;
+  if((eohIndex = findEndOfHeader(headerBuf, "\r\n\r\n", hlenTemp)) == -1 &&
+     (eohIndex = findEndOfHeader(headerBuf, "\n\n", hlenTemp)) == -1) {
+    socket->readData(headerBuf+headerBufLength, size);
+  } else {
+    if(eohIndex[headerBuf] == '\n') {
+      // for crapping non-standard HTTP server
+      delimiterSwith = 1;
     } else {
-      if(Util::endsWith(header, "\r\n\r\n")) {
-	socket->readData(buf, size);
-      } else {
-	header.erase(p+4);
-	size = p+4-hlenTemp;
-	socket->readData(buf, size);
-      }
-      break;
+      delimiterSwith = 0;
     }
+    headerBuf[eohIndex+strlen(delimiters[delimiterSwith])*2] = '\0';
+    header = headerBuf;
+    size = eohIndex+strlen(delimiters[delimiterSwith])*2-headerBufLength;
+    socket->readData(headerBuf+headerBufLength, size);
   }
-  if(!Util::endsWith(header, "\r\n\r\n")) {
+  if(!Util::endsWith(header, "\r\n\r\n") && !Util::endsWith(header, "\n\n")) {
     return 0;
   }
   // OK, we got all headers.
   logger->info(MSG_RECEIVE_RESPONSE, cuid, header.c_str());
   string::size_type p, np;
   p = np = 0;
-  np = header.find("\r\n", p);
+  np = header.find(delimiters[delimiterSwith], p);
   if(np == string::npos) {
     throw new DlRetryEx(EX_NO_STATUS_HEADER);
   }
@@ -141,7 +162,7 @@ int HttpConnection::receiveResponse(HttpHeader& headers) {
   string status = header.substr(9, 3);
   p = np+2;
   // retreive status name-value pairs, then push these into map
-  while((np = header.find("\r\n", p)) != string::npos && np != p) {
+  while((np = header.find(delimiters[delimiterSwith], p)) != string::npos && np != p) {
     string line = header.substr(p, np-p);
     p = np+2;
     pair<string, string> hp;

+ 5 - 1
src/HttpConnection.h

@@ -33,10 +33,13 @@
 
 using namespace std;
 
+#define HEADERBUF_SIZE 4096
+
 class HttpConnection {
 private:
   string getHost(const string& host, int port) const;
   string createRequest(const Segment& segment) const;
+  int findEndOfHeader(const char* buf, const char* substr, int bufLength) const;
   bool useProxy() const;
   bool useProxyAuth() const;
   bool useProxyGet() const;
@@ -46,7 +49,8 @@ private:
   const Request* req;
   const Option* option;
   const Logger* logger;
-  string header;
+  char headerBuf[HEADERBUF_SIZE+1];
+  int headerBufLength;
 public:
   HttpConnection(int cuid, const Socket* socket, const Request* req, const Option* op, const Logger* logger);
 

+ 5 - 4
src/HttpRequestCommand.cc

@@ -21,9 +21,6 @@
 /* copyright --> */
 #include "HttpRequestCommand.h"
 #include "HttpResponseCommand.h"
-#include "HttpInitiateConnectionCommand.h"
-#include "Socket.h"
-#include "Util.h"
 #include "HttpConnection.h"
 
 HttpRequestCommand::HttpRequestCommand(int cuid, Request* req, DownloadEngine* e, Socket* s):AbstractCommand(cuid, req, e, s) {
@@ -43,7 +40,11 @@ bool HttpRequestCommand::executeInternal(Segment seg) {
   req->seg = seg;
   http.sendRequest(seg);
 
-  HttpResponseCommand* command = new HttpResponseCommand(cuid, req, e, socket);
+  Command* command = getNextCommand();
   e->commands.push(command);
   return true;
 }
+
+Command* HttpRequestCommand::getNextCommand() const {
+  return new HttpResponseCommand(cuid, req, e, socket);
+}

+ 1 - 1
src/HttpRequestCommand.h

@@ -27,7 +27,7 @@
 class HttpRequestCommand:public AbstractCommand {
 protected:
   bool executeInternal(Segment segment);
-  
+  Command* getNextCommand() const;
 public:
   HttpRequestCommand(int cuid, Request* req, DownloadEngine* e, Socket* s);
   ~HttpRequestCommand();

+ 27 - 9
src/HttpResponseCommand.cc

@@ -26,6 +26,9 @@
 #include "HttpInitiateConnectionCommand.h"
 #include "message.h"
 #include "Util.h"
+#include "TrackerDownloadCommand.h"
+// TODO
+#include "TorrentDownloadEngine.h"
 
 HttpResponseCommand::HttpResponseCommand(int cuid, Request* req, DownloadEngine* e, Socket* s):
   AbstractCommand(cuid, req, e, s) {
@@ -89,6 +92,15 @@ bool HttpResponseCommand::handleRedirect(string url, const HttpHeader& headers)
 }
 
 bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) {
+  // TODO quick and dirty way 
+  if(req->isTorrent) {
+    long long int size = headers.getFirstAsLLInt("Content-Length");
+    e->segmentMan->totalSize = size;
+    e->segmentMan->isSplittable = false;
+    createHttpDownloadCommand();
+    return true;
+  }
+
   long long int size = headers.getFirstAsLLInt("Content-Length");
   if(size == LONG_LONG_MAX || size < 0) {
     throw new DlAbortEx(EX_TOO_LARGE_FILE, size);
@@ -126,16 +138,22 @@ bool HttpResponseCommand::handleOtherEncoding(string transferEncoding, const Htt
 }
 
 void HttpResponseCommand::createHttpDownloadCommand(string transferEncoding) {
-  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();
+  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);
     }
+  } else {
+    // TODO
+    TrackerDownloadCommand* command = new TrackerDownloadCommand(cuid, req, (TorrentDownloadEngine*)e, socket);
     e->commands.push(command);
   }
 }

+ 47 - 0
src/List.cc

@@ -0,0 +1,47 @@
+/* <!-- 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 "List.h"
+#include "MetaEntryVisitor.h"
+
+List::List() {}
+
+List::~List() {
+  clearList();
+}
+
+void List::clearList() {
+  for(MetaList::iterator itr = mlist.begin(); itr != mlist.end(); itr++) {
+    delete *itr;
+  }
+}
+
+void List::add(MetaEntry* entry) {
+  mlist.push_back(entry);
+}
+
+const MetaList& List::getList() const {
+  return mlist;
+}
+
+void List::accept(MetaEntryVisitor* v) const {
+  v->visit(this);
+}

+ 48 - 0
src/List.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_LIST_H_
+#define _D_LIST_H_
+
+#include "MetaEntry.h"
+#include <vector>
+
+using namespace std;
+
+typedef vector<MetaEntry*> MetaList;
+
+class List : public MetaEntry {
+private:
+  MetaList mlist;
+
+  void clearList();
+public:
+  List();
+  ~List();
+
+  void add(MetaEntry* entry);
+
+  const MetaList& getList() const;
+
+  void accept(MetaEntryVisitor* v) const;
+};
+
+#endif // _D_LIST_H_

+ 31 - 1
src/Makefile.am

@@ -41,11 +41,41 @@ SRCS =  Socket.cc Socket.h\
 	ChunkedEncoding.cc ChunkedEncoding.h\
 	DiskWriter.h\
 	DefaultDiskWriter.cc DefaultDiskWriter.h\
+	PreAllocationDiskWriter.cc PreAllocationDiskWriter.h\
 	AbstractDiskWriter.cc AbstractDiskWriter.h\
 	File.cc File.h\
 	Option.cc Option.h\
 	Base64.cc Base64.h\
-	CookieBox.cc CookieBox.h
+	CookieBox.cc CookieBox.h\
+	MetaEntry.h\
+	Data.cc Data.h\
+	Dictionary.cc Dictionary.h\
+	List.cc List.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\
+	PeerAbstractCommand.cc PeerAbstractCommand.h\
+	PeerInitiateConnectionCommand.cc PeerInitiateConnectionCommand.h\
+	PeerInteractionCommand.cc PeerInteractionCommand.h\
+	Peer.cc Peer.h\
+	BitfieldMan.cc BitfieldMan.h\
+	TorrentDownloadEngine.cc TorrentDownloadEngine.h\
+	TorrentConsoleDownloadEngine.cc TorrentConsoleDownloadEngine.h\
+	PeerListenCommand.cc PeerListenCommand.h\
+	PendingMessage.cc PendingMessage.h\
+	PeerMessage.cc PeerMessage.h\
+	HandshakeMessage.h\
+	Piece.cc Piece.h\
+	RequestSlot.cc RequestSlot.h\
+	RequestSlotMan.cc RequestSlotMan.h\
+	TorrentAutoSaveCommand.cc TorrentAutoSaveCommand.h\
+	Directory.cc Directory.h
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@

+ 460 - 2
src/Makefile.in

@@ -91,9 +91,32 @@ am__objects_1 = libaria2c_a-Socket.$(OBJEXT) \
 	libaria2c_a-SimpleLogger.$(OBJEXT) \
 	libaria2c_a-ChunkedEncoding.$(OBJEXT) \
 	libaria2c_a-DefaultDiskWriter.$(OBJEXT) \
+	libaria2c_a-PreAllocationDiskWriter.$(OBJEXT) \
 	libaria2c_a-AbstractDiskWriter.$(OBJEXT) \
 	libaria2c_a-File.$(OBJEXT) libaria2c_a-Option.$(OBJEXT) \
-	libaria2c_a-Base64.$(OBJEXT) libaria2c_a-CookieBox.$(OBJEXT)
+	libaria2c_a-Base64.$(OBJEXT) libaria2c_a-CookieBox.$(OBJEXT) \
+	libaria2c_a-Data.$(OBJEXT) libaria2c_a-Dictionary.$(OBJEXT) \
+	libaria2c_a-List.$(OBJEXT) libaria2c_a-MetaFileUtil.$(OBJEXT) \
+	libaria2c_a-ShaVisitor.$(OBJEXT) \
+	libaria2c_a-TrackerInitCommand.$(OBJEXT) \
+	libaria2c_a-TrackerDownloadCommand.$(OBJEXT) \
+	libaria2c_a-TrackerUpdateCommand.$(OBJEXT) \
+	libaria2c_a-TorrentMan.$(OBJEXT) \
+	libaria2c_a-PeerConnection.$(OBJEXT) \
+	libaria2c_a-PeerMessageUtil.$(OBJEXT) \
+	libaria2c_a-PeerAbstractCommand.$(OBJEXT) \
+	libaria2c_a-PeerInitiateConnectionCommand.$(OBJEXT) \
+	libaria2c_a-PeerInteractionCommand.$(OBJEXT) \
+	libaria2c_a-Peer.$(OBJEXT) libaria2c_a-BitfieldMan.$(OBJEXT) \
+	libaria2c_a-TorrentDownloadEngine.$(OBJEXT) \
+	libaria2c_a-TorrentConsoleDownloadEngine.$(OBJEXT) \
+	libaria2c_a-PeerListenCommand.$(OBJEXT) \
+	libaria2c_a-PendingMessage.$(OBJEXT) \
+	libaria2c_a-PeerMessage.$(OBJEXT) libaria2c_a-Piece.$(OBJEXT) \
+	libaria2c_a-RequestSlot.$(OBJEXT) \
+	libaria2c_a-RequestSlotMan.$(OBJEXT) \
+	libaria2c_a-TorrentAutoSaveCommand.$(OBJEXT) \
+	libaria2c_a-Directory.$(OBJEXT)
 am_libaria2c_a_OBJECTS = $(am__objects_1)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -275,11 +298,41 @@ SRCS = Socket.cc Socket.h\
 	ChunkedEncoding.cc ChunkedEncoding.h\
 	DiskWriter.h\
 	DefaultDiskWriter.cc DefaultDiskWriter.h\
+	PreAllocationDiskWriter.cc PreAllocationDiskWriter.h\
 	AbstractDiskWriter.cc AbstractDiskWriter.h\
 	File.cc File.h\
 	Option.cc Option.h\
 	Base64.cc Base64.h\
-	CookieBox.cc CookieBox.h
+	CookieBox.cc CookieBox.h\
+	MetaEntry.h\
+	Data.cc Data.h\
+	Dictionary.cc Dictionary.h\
+	List.cc List.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\
+	PeerAbstractCommand.cc PeerAbstractCommand.h\
+	PeerInitiateConnectionCommand.cc PeerInitiateConnectionCommand.h\
+	PeerInteractionCommand.cc PeerInteractionCommand.h\
+	Peer.cc Peer.h\
+	BitfieldMan.cc BitfieldMan.h\
+	TorrentDownloadEngine.cc TorrentDownloadEngine.h\
+	TorrentConsoleDownloadEngine.cc TorrentConsoleDownloadEngine.h\
+	PeerListenCommand.cc PeerListenCommand.h\
+	PendingMessage.cc PendingMessage.h\
+	PeerMessage.cc PeerMessage.h\
+	HandshakeMessage.h\
+	Piece.cc Piece.h\
+	RequestSlot.cc RequestSlot.h\
+	RequestSlotMan.cc RequestSlotMan.h\
+	TorrentAutoSaveCommand.cc TorrentAutoSaveCommand.h\
+	Directory.cc Directory.h
 
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
@@ -366,10 +419,14 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-AbstractCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-AbstractDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Base64.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-BitfieldMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-ChunkedEncoding.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-ConsoleDownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-CookieBox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Data.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-DefaultDiskWriter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Dictionary.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Directory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-DownloadCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-DownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-File.Po@am__quote@
@@ -388,16 +445,39 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-HttpRequestCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-HttpResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-InitiateConnectionCommandFactory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-List.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-MetaFileUtil.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Option.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Peer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerConnection.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerListenCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerMessage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PeerMessageUtil.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PendingMessage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Piece.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Request.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-RequestSlot.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-RequestSlotMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SegmentMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SegmentSplitter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-ShaVisitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SimpleLogger.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SleepCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Socket.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SocketCore.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SplitFirstSegmentSplitter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-SplitSlowestSegmentSplitter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TorrentMan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TrackerInitCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libaria2c_a-Util.Po@am__quote@
 
 .cc.o:
@@ -848,6 +928,20 @@ libaria2c_a-DefaultDiskWriter.obj: DefaultDiskWriter.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-DefaultDiskWriter.obj `if test -f 'DefaultDiskWriter.cc'; then $(CYGPATH_W) 'DefaultDiskWriter.cc'; else $(CYGPATH_W) '$(srcdir)/DefaultDiskWriter.cc'; fi`
 
+libaria2c_a-PreAllocationDiskWriter.o: PreAllocationDiskWriter.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PreAllocationDiskWriter.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Tpo" -c -o libaria2c_a-PreAllocationDiskWriter.o `test -f 'PreAllocationDiskWriter.cc' || echo '$(srcdir)/'`PreAllocationDiskWriter.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Tpo" "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PreAllocationDiskWriter.cc' object='libaria2c_a-PreAllocationDiskWriter.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PreAllocationDiskWriter.o `test -f 'PreAllocationDiskWriter.cc' || echo '$(srcdir)/'`PreAllocationDiskWriter.cc
+
+libaria2c_a-PreAllocationDiskWriter.obj: PreAllocationDiskWriter.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PreAllocationDiskWriter.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Tpo" -c -o libaria2c_a-PreAllocationDiskWriter.obj `if test -f 'PreAllocationDiskWriter.cc'; then $(CYGPATH_W) 'PreAllocationDiskWriter.cc'; else $(CYGPATH_W) '$(srcdir)/PreAllocationDiskWriter.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Tpo" "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PreAllocationDiskWriter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PreAllocationDiskWriter.cc' object='libaria2c_a-PreAllocationDiskWriter.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PreAllocationDiskWriter.obj `if test -f 'PreAllocationDiskWriter.cc'; then $(CYGPATH_W) 'PreAllocationDiskWriter.cc'; else $(CYGPATH_W) '$(srcdir)/PreAllocationDiskWriter.cc'; fi`
+
 libaria2c_a-AbstractDiskWriter.o: AbstractDiskWriter.cc
 @am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-AbstractDiskWriter.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-AbstractDiskWriter.Tpo" -c -o libaria2c_a-AbstractDiskWriter.o `test -f 'AbstractDiskWriter.cc' || echo '$(srcdir)/'`AbstractDiskWriter.cc; \
 @am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-AbstractDiskWriter.Tpo" "$(DEPDIR)/libaria2c_a-AbstractDiskWriter.Po"; else rm -f "$(DEPDIR)/libaria2c_a-AbstractDiskWriter.Tpo"; exit 1; fi
@@ -918,6 +1012,370 @@ libaria2c_a-CookieBox.obj: CookieBox.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-CookieBox.obj `if test -f 'CookieBox.cc'; then $(CYGPATH_W) 'CookieBox.cc'; else $(CYGPATH_W) '$(srcdir)/CookieBox.cc'; fi`
 
+libaria2c_a-Data.o: Data.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Data.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-Data.Tpo" -c -o libaria2c_a-Data.o `test -f 'Data.cc' || echo '$(srcdir)/'`Data.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Data.Tpo" "$(DEPDIR)/libaria2c_a-Data.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Data.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Data.cc' object='libaria2c_a-Data.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Data.o `test -f 'Data.cc' || echo '$(srcdir)/'`Data.cc
+
+libaria2c_a-Data.obj: Data.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Data.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-Data.Tpo" -c -o libaria2c_a-Data.obj `if test -f 'Data.cc'; then $(CYGPATH_W) 'Data.cc'; else $(CYGPATH_W) '$(srcdir)/Data.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Data.Tpo" "$(DEPDIR)/libaria2c_a-Data.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Data.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Data.cc' object='libaria2c_a-Data.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Data.obj `if test -f 'Data.cc'; then $(CYGPATH_W) 'Data.cc'; else $(CYGPATH_W) '$(srcdir)/Data.cc'; fi`
+
+libaria2c_a-Dictionary.o: Dictionary.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Dictionary.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-Dictionary.Tpo" -c -o libaria2c_a-Dictionary.o `test -f 'Dictionary.cc' || echo '$(srcdir)/'`Dictionary.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Dictionary.Tpo" "$(DEPDIR)/libaria2c_a-Dictionary.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Dictionary.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Dictionary.cc' object='libaria2c_a-Dictionary.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Dictionary.o `test -f 'Dictionary.cc' || echo '$(srcdir)/'`Dictionary.cc
+
+libaria2c_a-Dictionary.obj: Dictionary.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Dictionary.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-Dictionary.Tpo" -c -o libaria2c_a-Dictionary.obj `if test -f 'Dictionary.cc'; then $(CYGPATH_W) 'Dictionary.cc'; else $(CYGPATH_W) '$(srcdir)/Dictionary.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Dictionary.Tpo" "$(DEPDIR)/libaria2c_a-Dictionary.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Dictionary.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Dictionary.cc' object='libaria2c_a-Dictionary.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Dictionary.obj `if test -f 'Dictionary.cc'; then $(CYGPATH_W) 'Dictionary.cc'; else $(CYGPATH_W) '$(srcdir)/Dictionary.cc'; fi`
+
+libaria2c_a-List.o: List.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-List.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-List.Tpo" -c -o libaria2c_a-List.o `test -f 'List.cc' || echo '$(srcdir)/'`List.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-List.Tpo" "$(DEPDIR)/libaria2c_a-List.Po"; else rm -f "$(DEPDIR)/libaria2c_a-List.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='List.cc' object='libaria2c_a-List.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-List.o `test -f 'List.cc' || echo '$(srcdir)/'`List.cc
+
+libaria2c_a-List.obj: List.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-List.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-List.Tpo" -c -o libaria2c_a-List.obj `if test -f 'List.cc'; then $(CYGPATH_W) 'List.cc'; else $(CYGPATH_W) '$(srcdir)/List.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-List.Tpo" "$(DEPDIR)/libaria2c_a-List.Po"; else rm -f "$(DEPDIR)/libaria2c_a-List.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='List.cc' object='libaria2c_a-List.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-List.obj `if test -f 'List.cc'; then $(CYGPATH_W) 'List.cc'; else $(CYGPATH_W) '$(srcdir)/List.cc'; fi`
+
+libaria2c_a-MetaFileUtil.o: MetaFileUtil.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-MetaFileUtil.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-MetaFileUtil.Tpo" -c -o libaria2c_a-MetaFileUtil.o `test -f 'MetaFileUtil.cc' || echo '$(srcdir)/'`MetaFileUtil.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-MetaFileUtil.Tpo" "$(DEPDIR)/libaria2c_a-MetaFileUtil.Po"; else rm -f "$(DEPDIR)/libaria2c_a-MetaFileUtil.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='MetaFileUtil.cc' object='libaria2c_a-MetaFileUtil.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-MetaFileUtil.o `test -f 'MetaFileUtil.cc' || echo '$(srcdir)/'`MetaFileUtil.cc
+
+libaria2c_a-MetaFileUtil.obj: MetaFileUtil.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-MetaFileUtil.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-MetaFileUtil.Tpo" -c -o libaria2c_a-MetaFileUtil.obj `if test -f 'MetaFileUtil.cc'; then $(CYGPATH_W) 'MetaFileUtil.cc'; else $(CYGPATH_W) '$(srcdir)/MetaFileUtil.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-MetaFileUtil.Tpo" "$(DEPDIR)/libaria2c_a-MetaFileUtil.Po"; else rm -f "$(DEPDIR)/libaria2c_a-MetaFileUtil.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='MetaFileUtil.cc' object='libaria2c_a-MetaFileUtil.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-MetaFileUtil.obj `if test -f 'MetaFileUtil.cc'; then $(CYGPATH_W) 'MetaFileUtil.cc'; else $(CYGPATH_W) '$(srcdir)/MetaFileUtil.cc'; fi`
+
+libaria2c_a-ShaVisitor.o: ShaVisitor.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-ShaVisitor.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-ShaVisitor.Tpo" -c -o libaria2c_a-ShaVisitor.o `test -f 'ShaVisitor.cc' || echo '$(srcdir)/'`ShaVisitor.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-ShaVisitor.Tpo" "$(DEPDIR)/libaria2c_a-ShaVisitor.Po"; else rm -f "$(DEPDIR)/libaria2c_a-ShaVisitor.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='ShaVisitor.cc' object='libaria2c_a-ShaVisitor.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-ShaVisitor.o `test -f 'ShaVisitor.cc' || echo '$(srcdir)/'`ShaVisitor.cc
+
+libaria2c_a-ShaVisitor.obj: ShaVisitor.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-ShaVisitor.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-ShaVisitor.Tpo" -c -o libaria2c_a-ShaVisitor.obj `if test -f 'ShaVisitor.cc'; then $(CYGPATH_W) 'ShaVisitor.cc'; else $(CYGPATH_W) '$(srcdir)/ShaVisitor.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-ShaVisitor.Tpo" "$(DEPDIR)/libaria2c_a-ShaVisitor.Po"; else rm -f "$(DEPDIR)/libaria2c_a-ShaVisitor.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='ShaVisitor.cc' object='libaria2c_a-ShaVisitor.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-ShaVisitor.obj `if test -f 'ShaVisitor.cc'; then $(CYGPATH_W) 'ShaVisitor.cc'; else $(CYGPATH_W) '$(srcdir)/ShaVisitor.cc'; fi`
+
+libaria2c_a-TrackerInitCommand.o: TrackerInitCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TrackerInitCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Tpo" -c -o libaria2c_a-TrackerInitCommand.o `test -f 'TrackerInitCommand.cc' || echo '$(srcdir)/'`TrackerInitCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Tpo" "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TrackerInitCommand.cc' object='libaria2c_a-TrackerInitCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TrackerInitCommand.o `test -f 'TrackerInitCommand.cc' || echo '$(srcdir)/'`TrackerInitCommand.cc
+
+libaria2c_a-TrackerInitCommand.obj: TrackerInitCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TrackerInitCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Tpo" -c -o libaria2c_a-TrackerInitCommand.obj `if test -f 'TrackerInitCommand.cc'; then $(CYGPATH_W) 'TrackerInitCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TrackerInitCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Tpo" "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TrackerInitCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TrackerInitCommand.cc' object='libaria2c_a-TrackerInitCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TrackerInitCommand.obj `if test -f 'TrackerInitCommand.cc'; then $(CYGPATH_W) 'TrackerInitCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TrackerInitCommand.cc'; fi`
+
+libaria2c_a-TrackerDownloadCommand.o: TrackerDownloadCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TrackerDownloadCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Tpo" -c -o libaria2c_a-TrackerDownloadCommand.o `test -f 'TrackerDownloadCommand.cc' || echo '$(srcdir)/'`TrackerDownloadCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Tpo" "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TrackerDownloadCommand.cc' object='libaria2c_a-TrackerDownloadCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TrackerDownloadCommand.o `test -f 'TrackerDownloadCommand.cc' || echo '$(srcdir)/'`TrackerDownloadCommand.cc
+
+libaria2c_a-TrackerDownloadCommand.obj: TrackerDownloadCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TrackerDownloadCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Tpo" -c -o libaria2c_a-TrackerDownloadCommand.obj `if test -f 'TrackerDownloadCommand.cc'; then $(CYGPATH_W) 'TrackerDownloadCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TrackerDownloadCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Tpo" "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TrackerDownloadCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TrackerDownloadCommand.cc' object='libaria2c_a-TrackerDownloadCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TrackerDownloadCommand.obj `if test -f 'TrackerDownloadCommand.cc'; then $(CYGPATH_W) 'TrackerDownloadCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TrackerDownloadCommand.cc'; fi`
+
+libaria2c_a-TrackerUpdateCommand.o: TrackerUpdateCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TrackerUpdateCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Tpo" -c -o libaria2c_a-TrackerUpdateCommand.o `test -f 'TrackerUpdateCommand.cc' || echo '$(srcdir)/'`TrackerUpdateCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Tpo" "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TrackerUpdateCommand.cc' object='libaria2c_a-TrackerUpdateCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TrackerUpdateCommand.o `test -f 'TrackerUpdateCommand.cc' || echo '$(srcdir)/'`TrackerUpdateCommand.cc
+
+libaria2c_a-TrackerUpdateCommand.obj: TrackerUpdateCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TrackerUpdateCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Tpo" -c -o libaria2c_a-TrackerUpdateCommand.obj `if test -f 'TrackerUpdateCommand.cc'; then $(CYGPATH_W) 'TrackerUpdateCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TrackerUpdateCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Tpo" "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TrackerUpdateCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TrackerUpdateCommand.cc' object='libaria2c_a-TrackerUpdateCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TrackerUpdateCommand.obj `if test -f 'TrackerUpdateCommand.cc'; then $(CYGPATH_W) 'TrackerUpdateCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TrackerUpdateCommand.cc'; fi`
+
+libaria2c_a-TorrentMan.o: TorrentMan.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentMan.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentMan.Tpo" -c -o libaria2c_a-TorrentMan.o `test -f 'TorrentMan.cc' || echo '$(srcdir)/'`TorrentMan.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentMan.Tpo" "$(DEPDIR)/libaria2c_a-TorrentMan.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentMan.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentMan.cc' object='libaria2c_a-TorrentMan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentMan.o `test -f 'TorrentMan.cc' || echo '$(srcdir)/'`TorrentMan.cc
+
+libaria2c_a-TorrentMan.obj: TorrentMan.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentMan.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentMan.Tpo" -c -o libaria2c_a-TorrentMan.obj `if test -f 'TorrentMan.cc'; then $(CYGPATH_W) 'TorrentMan.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentMan.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentMan.Tpo" "$(DEPDIR)/libaria2c_a-TorrentMan.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentMan.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentMan.cc' object='libaria2c_a-TorrentMan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentMan.obj `if test -f 'TorrentMan.cc'; then $(CYGPATH_W) 'TorrentMan.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentMan.cc'; fi`
+
+libaria2c_a-PeerConnection.o: PeerConnection.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerConnection.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerConnection.Tpo" -c -o libaria2c_a-PeerConnection.o `test -f 'PeerConnection.cc' || echo '$(srcdir)/'`PeerConnection.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerConnection.Tpo" "$(DEPDIR)/libaria2c_a-PeerConnection.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerConnection.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerConnection.cc' object='libaria2c_a-PeerConnection.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerConnection.o `test -f 'PeerConnection.cc' || echo '$(srcdir)/'`PeerConnection.cc
+
+libaria2c_a-PeerConnection.obj: PeerConnection.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerConnection.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerConnection.Tpo" -c -o libaria2c_a-PeerConnection.obj `if test -f 'PeerConnection.cc'; then $(CYGPATH_W) 'PeerConnection.cc'; else $(CYGPATH_W) '$(srcdir)/PeerConnection.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerConnection.Tpo" "$(DEPDIR)/libaria2c_a-PeerConnection.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerConnection.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerConnection.cc' object='libaria2c_a-PeerConnection.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerConnection.obj `if test -f 'PeerConnection.cc'; then $(CYGPATH_W) 'PeerConnection.cc'; else $(CYGPATH_W) '$(srcdir)/PeerConnection.cc'; fi`
+
+libaria2c_a-PeerMessageUtil.o: PeerMessageUtil.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerMessageUtil.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Tpo" -c -o libaria2c_a-PeerMessageUtil.o `test -f 'PeerMessageUtil.cc' || echo '$(srcdir)/'`PeerMessageUtil.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Tpo" "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerMessageUtil.cc' object='libaria2c_a-PeerMessageUtil.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerMessageUtil.o `test -f 'PeerMessageUtil.cc' || echo '$(srcdir)/'`PeerMessageUtil.cc
+
+libaria2c_a-PeerMessageUtil.obj: PeerMessageUtil.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerMessageUtil.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Tpo" -c -o libaria2c_a-PeerMessageUtil.obj `if test -f 'PeerMessageUtil.cc'; then $(CYGPATH_W) 'PeerMessageUtil.cc'; else $(CYGPATH_W) '$(srcdir)/PeerMessageUtil.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Tpo" "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerMessageUtil.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerMessageUtil.cc' object='libaria2c_a-PeerMessageUtil.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerMessageUtil.obj `if test -f 'PeerMessageUtil.cc'; then $(CYGPATH_W) 'PeerMessageUtil.cc'; else $(CYGPATH_W) '$(srcdir)/PeerMessageUtil.cc'; fi`
+
+libaria2c_a-PeerAbstractCommand.o: PeerAbstractCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerAbstractCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Tpo" -c -o libaria2c_a-PeerAbstractCommand.o `test -f 'PeerAbstractCommand.cc' || echo '$(srcdir)/'`PeerAbstractCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerAbstractCommand.cc' object='libaria2c_a-PeerAbstractCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerAbstractCommand.o `test -f 'PeerAbstractCommand.cc' || echo '$(srcdir)/'`PeerAbstractCommand.cc
+
+libaria2c_a-PeerAbstractCommand.obj: PeerAbstractCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerAbstractCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Tpo" -c -o libaria2c_a-PeerAbstractCommand.obj `if test -f 'PeerAbstractCommand.cc'; then $(CYGPATH_W) 'PeerAbstractCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerAbstractCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerAbstractCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerAbstractCommand.cc' object='libaria2c_a-PeerAbstractCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerAbstractCommand.obj `if test -f 'PeerAbstractCommand.cc'; then $(CYGPATH_W) 'PeerAbstractCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerAbstractCommand.cc'; fi`
+
+libaria2c_a-PeerInitiateConnectionCommand.o: PeerInitiateConnectionCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerInitiateConnectionCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Tpo" -c -o libaria2c_a-PeerInitiateConnectionCommand.o `test -f 'PeerInitiateConnectionCommand.cc' || echo '$(srcdir)/'`PeerInitiateConnectionCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerInitiateConnectionCommand.cc' object='libaria2c_a-PeerInitiateConnectionCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerInitiateConnectionCommand.o `test -f 'PeerInitiateConnectionCommand.cc' || echo '$(srcdir)/'`PeerInitiateConnectionCommand.cc
+
+libaria2c_a-PeerInitiateConnectionCommand.obj: PeerInitiateConnectionCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerInitiateConnectionCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Tpo" -c -o libaria2c_a-PeerInitiateConnectionCommand.obj `if test -f 'PeerInitiateConnectionCommand.cc'; then $(CYGPATH_W) 'PeerInitiateConnectionCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerInitiateConnectionCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerInitiateConnectionCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerInitiateConnectionCommand.cc' object='libaria2c_a-PeerInitiateConnectionCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerInitiateConnectionCommand.obj `if test -f 'PeerInitiateConnectionCommand.cc'; then $(CYGPATH_W) 'PeerInitiateConnectionCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerInitiateConnectionCommand.cc'; fi`
+
+libaria2c_a-PeerInteractionCommand.o: PeerInteractionCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerInteractionCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Tpo" -c -o libaria2c_a-PeerInteractionCommand.o `test -f 'PeerInteractionCommand.cc' || echo '$(srcdir)/'`PeerInteractionCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerInteractionCommand.cc' object='libaria2c_a-PeerInteractionCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerInteractionCommand.o `test -f 'PeerInteractionCommand.cc' || echo '$(srcdir)/'`PeerInteractionCommand.cc
+
+libaria2c_a-PeerInteractionCommand.obj: PeerInteractionCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerInteractionCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Tpo" -c -o libaria2c_a-PeerInteractionCommand.obj `if test -f 'PeerInteractionCommand.cc'; then $(CYGPATH_W) 'PeerInteractionCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerInteractionCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerInteractionCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerInteractionCommand.cc' object='libaria2c_a-PeerInteractionCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerInteractionCommand.obj `if test -f 'PeerInteractionCommand.cc'; then $(CYGPATH_W) 'PeerInteractionCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerInteractionCommand.cc'; fi`
+
+libaria2c_a-Peer.o: Peer.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Peer.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-Peer.Tpo" -c -o libaria2c_a-Peer.o `test -f 'Peer.cc' || echo '$(srcdir)/'`Peer.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Peer.Tpo" "$(DEPDIR)/libaria2c_a-Peer.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Peer.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Peer.cc' object='libaria2c_a-Peer.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Peer.o `test -f 'Peer.cc' || echo '$(srcdir)/'`Peer.cc
+
+libaria2c_a-Peer.obj: Peer.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Peer.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-Peer.Tpo" -c -o libaria2c_a-Peer.obj `if test -f 'Peer.cc'; then $(CYGPATH_W) 'Peer.cc'; else $(CYGPATH_W) '$(srcdir)/Peer.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Peer.Tpo" "$(DEPDIR)/libaria2c_a-Peer.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Peer.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Peer.cc' object='libaria2c_a-Peer.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Peer.obj `if test -f 'Peer.cc'; then $(CYGPATH_W) 'Peer.cc'; else $(CYGPATH_W) '$(srcdir)/Peer.cc'; fi`
+
+libaria2c_a-BitfieldMan.o: BitfieldMan.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-BitfieldMan.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-BitfieldMan.Tpo" -c -o libaria2c_a-BitfieldMan.o `test -f 'BitfieldMan.cc' || echo '$(srcdir)/'`BitfieldMan.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-BitfieldMan.Tpo" "$(DEPDIR)/libaria2c_a-BitfieldMan.Po"; else rm -f "$(DEPDIR)/libaria2c_a-BitfieldMan.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='BitfieldMan.cc' object='libaria2c_a-BitfieldMan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-BitfieldMan.o `test -f 'BitfieldMan.cc' || echo '$(srcdir)/'`BitfieldMan.cc
+
+libaria2c_a-BitfieldMan.obj: BitfieldMan.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-BitfieldMan.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-BitfieldMan.Tpo" -c -o libaria2c_a-BitfieldMan.obj `if test -f 'BitfieldMan.cc'; then $(CYGPATH_W) 'BitfieldMan.cc'; else $(CYGPATH_W) '$(srcdir)/BitfieldMan.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-BitfieldMan.Tpo" "$(DEPDIR)/libaria2c_a-BitfieldMan.Po"; else rm -f "$(DEPDIR)/libaria2c_a-BitfieldMan.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='BitfieldMan.cc' object='libaria2c_a-BitfieldMan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-BitfieldMan.obj `if test -f 'BitfieldMan.cc'; then $(CYGPATH_W) 'BitfieldMan.cc'; else $(CYGPATH_W) '$(srcdir)/BitfieldMan.cc'; fi`
+
+libaria2c_a-TorrentDownloadEngine.o: TorrentDownloadEngine.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentDownloadEngine.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Tpo" -c -o libaria2c_a-TorrentDownloadEngine.o `test -f 'TorrentDownloadEngine.cc' || echo '$(srcdir)/'`TorrentDownloadEngine.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Tpo" "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentDownloadEngine.cc' object='libaria2c_a-TorrentDownloadEngine.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentDownloadEngine.o `test -f 'TorrentDownloadEngine.cc' || echo '$(srcdir)/'`TorrentDownloadEngine.cc
+
+libaria2c_a-TorrentDownloadEngine.obj: TorrentDownloadEngine.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentDownloadEngine.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Tpo" -c -o libaria2c_a-TorrentDownloadEngine.obj `if test -f 'TorrentDownloadEngine.cc'; then $(CYGPATH_W) 'TorrentDownloadEngine.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentDownloadEngine.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Tpo" "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentDownloadEngine.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentDownloadEngine.cc' object='libaria2c_a-TorrentDownloadEngine.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentDownloadEngine.obj `if test -f 'TorrentDownloadEngine.cc'; then $(CYGPATH_W) 'TorrentDownloadEngine.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentDownloadEngine.cc'; fi`
+
+libaria2c_a-TorrentConsoleDownloadEngine.o: TorrentConsoleDownloadEngine.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentConsoleDownloadEngine.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Tpo" -c -o libaria2c_a-TorrentConsoleDownloadEngine.o `test -f 'TorrentConsoleDownloadEngine.cc' || echo '$(srcdir)/'`TorrentConsoleDownloadEngine.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Tpo" "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentConsoleDownloadEngine.cc' object='libaria2c_a-TorrentConsoleDownloadEngine.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentConsoleDownloadEngine.o `test -f 'TorrentConsoleDownloadEngine.cc' || echo '$(srcdir)/'`TorrentConsoleDownloadEngine.cc
+
+libaria2c_a-TorrentConsoleDownloadEngine.obj: TorrentConsoleDownloadEngine.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentConsoleDownloadEngine.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Tpo" -c -o libaria2c_a-TorrentConsoleDownloadEngine.obj `if test -f 'TorrentConsoleDownloadEngine.cc'; then $(CYGPATH_W) 'TorrentConsoleDownloadEngine.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentConsoleDownloadEngine.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Tpo" "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentConsoleDownloadEngine.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentConsoleDownloadEngine.cc' object='libaria2c_a-TorrentConsoleDownloadEngine.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentConsoleDownloadEngine.obj `if test -f 'TorrentConsoleDownloadEngine.cc'; then $(CYGPATH_W) 'TorrentConsoleDownloadEngine.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentConsoleDownloadEngine.cc'; fi`
+
+libaria2c_a-PeerListenCommand.o: PeerListenCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerListenCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerListenCommand.Tpo" -c -o libaria2c_a-PeerListenCommand.o `test -f 'PeerListenCommand.cc' || echo '$(srcdir)/'`PeerListenCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerListenCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerListenCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerListenCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerListenCommand.cc' object='libaria2c_a-PeerListenCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerListenCommand.o `test -f 'PeerListenCommand.cc' || echo '$(srcdir)/'`PeerListenCommand.cc
+
+libaria2c_a-PeerListenCommand.obj: PeerListenCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerListenCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerListenCommand.Tpo" -c -o libaria2c_a-PeerListenCommand.obj `if test -f 'PeerListenCommand.cc'; then $(CYGPATH_W) 'PeerListenCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerListenCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerListenCommand.Tpo" "$(DEPDIR)/libaria2c_a-PeerListenCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerListenCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerListenCommand.cc' object='libaria2c_a-PeerListenCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerListenCommand.obj `if test -f 'PeerListenCommand.cc'; then $(CYGPATH_W) 'PeerListenCommand.cc'; else $(CYGPATH_W) '$(srcdir)/PeerListenCommand.cc'; fi`
+
+libaria2c_a-PendingMessage.o: PendingMessage.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PendingMessage.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PendingMessage.Tpo" -c -o libaria2c_a-PendingMessage.o `test -f 'PendingMessage.cc' || echo '$(srcdir)/'`PendingMessage.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PendingMessage.Tpo" "$(DEPDIR)/libaria2c_a-PendingMessage.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PendingMessage.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PendingMessage.cc' object='libaria2c_a-PendingMessage.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PendingMessage.o `test -f 'PendingMessage.cc' || echo '$(srcdir)/'`PendingMessage.cc
+
+libaria2c_a-PendingMessage.obj: PendingMessage.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PendingMessage.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PendingMessage.Tpo" -c -o libaria2c_a-PendingMessage.obj `if test -f 'PendingMessage.cc'; then $(CYGPATH_W) 'PendingMessage.cc'; else $(CYGPATH_W) '$(srcdir)/PendingMessage.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PendingMessage.Tpo" "$(DEPDIR)/libaria2c_a-PendingMessage.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PendingMessage.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PendingMessage.cc' object='libaria2c_a-PendingMessage.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PendingMessage.obj `if test -f 'PendingMessage.cc'; then $(CYGPATH_W) 'PendingMessage.cc'; else $(CYGPATH_W) '$(srcdir)/PendingMessage.cc'; fi`
+
+libaria2c_a-PeerMessage.o: PeerMessage.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerMessage.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerMessage.Tpo" -c -o libaria2c_a-PeerMessage.o `test -f 'PeerMessage.cc' || echo '$(srcdir)/'`PeerMessage.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerMessage.Tpo" "$(DEPDIR)/libaria2c_a-PeerMessage.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerMessage.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerMessage.cc' object='libaria2c_a-PeerMessage.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerMessage.o `test -f 'PeerMessage.cc' || echo '$(srcdir)/'`PeerMessage.cc
+
+libaria2c_a-PeerMessage.obj: PeerMessage.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-PeerMessage.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-PeerMessage.Tpo" -c -o libaria2c_a-PeerMessage.obj `if test -f 'PeerMessage.cc'; then $(CYGPATH_W) 'PeerMessage.cc'; else $(CYGPATH_W) '$(srcdir)/PeerMessage.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-PeerMessage.Tpo" "$(DEPDIR)/libaria2c_a-PeerMessage.Po"; else rm -f "$(DEPDIR)/libaria2c_a-PeerMessage.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerMessage.cc' object='libaria2c_a-PeerMessage.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-PeerMessage.obj `if test -f 'PeerMessage.cc'; then $(CYGPATH_W) 'PeerMessage.cc'; else $(CYGPATH_W) '$(srcdir)/PeerMessage.cc'; fi`
+
+libaria2c_a-Piece.o: Piece.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Piece.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-Piece.Tpo" -c -o libaria2c_a-Piece.o `test -f 'Piece.cc' || echo '$(srcdir)/'`Piece.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Piece.Tpo" "$(DEPDIR)/libaria2c_a-Piece.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Piece.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Piece.cc' object='libaria2c_a-Piece.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Piece.o `test -f 'Piece.cc' || echo '$(srcdir)/'`Piece.cc
+
+libaria2c_a-Piece.obj: Piece.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Piece.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-Piece.Tpo" -c -o libaria2c_a-Piece.obj `if test -f 'Piece.cc'; then $(CYGPATH_W) 'Piece.cc'; else $(CYGPATH_W) '$(srcdir)/Piece.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Piece.Tpo" "$(DEPDIR)/libaria2c_a-Piece.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Piece.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Piece.cc' object='libaria2c_a-Piece.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Piece.obj `if test -f 'Piece.cc'; then $(CYGPATH_W) 'Piece.cc'; else $(CYGPATH_W) '$(srcdir)/Piece.cc'; fi`
+
+libaria2c_a-RequestSlot.o: RequestSlot.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-RequestSlot.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-RequestSlot.Tpo" -c -o libaria2c_a-RequestSlot.o `test -f 'RequestSlot.cc' || echo '$(srcdir)/'`RequestSlot.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-RequestSlot.Tpo" "$(DEPDIR)/libaria2c_a-RequestSlot.Po"; else rm -f "$(DEPDIR)/libaria2c_a-RequestSlot.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='RequestSlot.cc' object='libaria2c_a-RequestSlot.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-RequestSlot.o `test -f 'RequestSlot.cc' || echo '$(srcdir)/'`RequestSlot.cc
+
+libaria2c_a-RequestSlot.obj: RequestSlot.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-RequestSlot.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-RequestSlot.Tpo" -c -o libaria2c_a-RequestSlot.obj `if test -f 'RequestSlot.cc'; then $(CYGPATH_W) 'RequestSlot.cc'; else $(CYGPATH_W) '$(srcdir)/RequestSlot.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-RequestSlot.Tpo" "$(DEPDIR)/libaria2c_a-RequestSlot.Po"; else rm -f "$(DEPDIR)/libaria2c_a-RequestSlot.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='RequestSlot.cc' object='libaria2c_a-RequestSlot.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-RequestSlot.obj `if test -f 'RequestSlot.cc'; then $(CYGPATH_W) 'RequestSlot.cc'; else $(CYGPATH_W) '$(srcdir)/RequestSlot.cc'; fi`
+
+libaria2c_a-RequestSlotMan.o: RequestSlotMan.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-RequestSlotMan.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-RequestSlotMan.Tpo" -c -o libaria2c_a-RequestSlotMan.o `test -f 'RequestSlotMan.cc' || echo '$(srcdir)/'`RequestSlotMan.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-RequestSlotMan.Tpo" "$(DEPDIR)/libaria2c_a-RequestSlotMan.Po"; else rm -f "$(DEPDIR)/libaria2c_a-RequestSlotMan.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='RequestSlotMan.cc' object='libaria2c_a-RequestSlotMan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-RequestSlotMan.o `test -f 'RequestSlotMan.cc' || echo '$(srcdir)/'`RequestSlotMan.cc
+
+libaria2c_a-RequestSlotMan.obj: RequestSlotMan.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-RequestSlotMan.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-RequestSlotMan.Tpo" -c -o libaria2c_a-RequestSlotMan.obj `if test -f 'RequestSlotMan.cc'; then $(CYGPATH_W) 'RequestSlotMan.cc'; else $(CYGPATH_W) '$(srcdir)/RequestSlotMan.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-RequestSlotMan.Tpo" "$(DEPDIR)/libaria2c_a-RequestSlotMan.Po"; else rm -f "$(DEPDIR)/libaria2c_a-RequestSlotMan.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='RequestSlotMan.cc' object='libaria2c_a-RequestSlotMan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-RequestSlotMan.obj `if test -f 'RequestSlotMan.cc'; then $(CYGPATH_W) 'RequestSlotMan.cc'; else $(CYGPATH_W) '$(srcdir)/RequestSlotMan.cc'; fi`
+
+libaria2c_a-TorrentAutoSaveCommand.o: TorrentAutoSaveCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentAutoSaveCommand.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Tpo" -c -o libaria2c_a-TorrentAutoSaveCommand.o `test -f 'TorrentAutoSaveCommand.cc' || echo '$(srcdir)/'`TorrentAutoSaveCommand.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Tpo" "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentAutoSaveCommand.cc' object='libaria2c_a-TorrentAutoSaveCommand.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentAutoSaveCommand.o `test -f 'TorrentAutoSaveCommand.cc' || echo '$(srcdir)/'`TorrentAutoSaveCommand.cc
+
+libaria2c_a-TorrentAutoSaveCommand.obj: TorrentAutoSaveCommand.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-TorrentAutoSaveCommand.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Tpo" -c -o libaria2c_a-TorrentAutoSaveCommand.obj `if test -f 'TorrentAutoSaveCommand.cc'; then $(CYGPATH_W) 'TorrentAutoSaveCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentAutoSaveCommand.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Tpo" "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Po"; else rm -f "$(DEPDIR)/libaria2c_a-TorrentAutoSaveCommand.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentAutoSaveCommand.cc' object='libaria2c_a-TorrentAutoSaveCommand.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-TorrentAutoSaveCommand.obj `if test -f 'TorrentAutoSaveCommand.cc'; then $(CYGPATH_W) 'TorrentAutoSaveCommand.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentAutoSaveCommand.cc'; fi`
+
+libaria2c_a-Directory.o: Directory.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Directory.o -MD -MP -MF "$(DEPDIR)/libaria2c_a-Directory.Tpo" -c -o libaria2c_a-Directory.o `test -f 'Directory.cc' || echo '$(srcdir)/'`Directory.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Directory.Tpo" "$(DEPDIR)/libaria2c_a-Directory.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Directory.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Directory.cc' object='libaria2c_a-Directory.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Directory.o `test -f 'Directory.cc' || echo '$(srcdir)/'`Directory.cc
+
+libaria2c_a-Directory.obj: Directory.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -MT libaria2c_a-Directory.obj -MD -MP -MF "$(DEPDIR)/libaria2c_a-Directory.Tpo" -c -o libaria2c_a-Directory.obj `if test -f 'Directory.cc'; then $(CYGPATH_W) 'Directory.cc'; else $(CYGPATH_W) '$(srcdir)/Directory.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/libaria2c_a-Directory.Tpo" "$(DEPDIR)/libaria2c_a-Directory.Po"; else rm -f "$(DEPDIR)/libaria2c_a-Directory.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='Directory.cc' object='libaria2c_a-Directory.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libaria2c_a_CXXFLAGS) $(CXXFLAGS) -c -o libaria2c_a-Directory.obj `if test -f 'Directory.cc'; then $(CYGPATH_W) 'Directory.cc'; else $(CYGPATH_W) '$(srcdir)/Directory.cc'; fi`
+
 aria2c-main.o: main.cc
 @am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-main.o -MD -MP -MF "$(DEPDIR)/aria2c-main.Tpo" -c -o aria2c-main.o `test -f 'main.cc' || echo '$(srcdir)/'`main.cc; \
 @am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-main.Tpo" "$(DEPDIR)/aria2c-main.Po"; else rm -f "$(DEPDIR)/aria2c-main.Tpo"; exit 1; fi

+ 40 - 0
src/MetaEntry.h

@@ -0,0 +1,40 @@
+/* <!-- 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_META_ENTRY_H_
+#define _D_META_ENTRY_H_
+
+//#include "MetaEntryVisitor.h"
+#include "common.h"
+
+class MetaEntryVisitor;
+
+class MetaEntry {
+protected:
+  MetaEntry() {}
+public:
+  virtual ~MetaEntry() {}
+
+  virtual void accept(MetaEntryVisitor* v) const = 0;
+
+};
+
+#endif // _D_META_ENTRY_H_

+ 34 - 0
src/MetaEntryVisitor.h

@@ -0,0 +1,34 @@
+/* <!-- 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_META_ENTRY_VISITOR_H_
+#define _D_META_ENTRY_VISITOR_H_
+
+#include "MetaEntry.h"
+
+class MetaEntryVisitor {
+public:
+  virtual ~MetaEntryVisitor() {}
+
+  virtual void visit(const MetaEntry* e) = 0;
+};
+
+#endif // _D_META_ENTRY_VISITOR_H_

+ 170 - 0
src/MetaFileUtil.cc

@@ -0,0 +1,170 @@
+/* <!-- 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 "MetaFileUtil.h"
+#include "File.h"
+#include "DlAbortEx.h"
+#include "message.h"
+#include <string.h>
+#include <stdlib.h>
+
+MetaEntry* MetaFileUtil::parseMetaFile(string file) {
+  File f(file);
+  int len = f.size();
+  char* buf = new char[len];
+  FILE* fp = fopen(file.c_str(), "r+");
+  if(fp == NULL) {
+    throw new DlAbortEx("cannot open metainfo file");
+  }
+  if(fread(buf, len, 1, fp) != 1) {
+    fclose(fp);
+    throw new DlAbortEx("cannot read metainfo");
+  }
+  fclose(fp);
+  MetaEntry* entry = bdecoding(buf, len);
+  delete [] buf;
+  return entry;
+}
+
+MetaEntry* MetaFileUtil::bdecoding(const char* buf, int len) {
+  MetaEntry* entry = NULL;
+  try{
+    const char* p = buf;
+    const char* end = buf+len;
+    entry = bdecodingR(&p, end);
+    return entry;
+  } catch(DlAbortEx* ex) {
+    if(entry != NULL) {
+      delete entry;
+    }
+    throw;
+  }
+}
+
+MetaEntry* MetaFileUtil::bdecodingR(const char** pp, const char* end) {
+  if(*pp >= end) {
+    throw new DlAbortEx("mulformed metainfo");
+  }
+  MetaEntry* e;
+  switch(**pp) {
+  case 'd':
+    (*pp)++;
+    e = parseDictionaryTree(pp, end);
+    break;
+  case 'l':
+    (*pp)++;
+    e = parseListTree(pp, end);
+    break;
+  case 'i':
+    (*pp)++;
+    e = decodeInt(pp, end);
+    break;
+  default:
+    e = decodeWord(pp, end);
+  }
+  return e;
+}
+
+Dictionary* MetaFileUtil::parseDictionaryTree(const char** pp, const char* end) {
+  if(*pp >= end) {
+    throw new DlAbortEx("mulformed metainfo");
+  }
+  Dictionary* dic = new Dictionary();
+  while(1) {
+    if(**pp == 'e') {
+      (*pp)++;
+      break;
+    }
+    string name = decodeWordAsString(pp, end);
+    MetaEntry* e = bdecodingR(pp, end);
+    dic->put(name, e);
+  }
+  return dic;
+}
+
+List* MetaFileUtil::parseListTree(const char** pp, const char* end) {
+  if(*pp >= end) {
+    throw new DlAbortEx("mulformed metainfo");
+  }
+  List* lis = new List();
+  while(1) {
+    if(**pp == 'e') {
+      (*pp)++;
+      break;
+    }
+    MetaEntry* e = bdecodingR(pp, end);
+    lis->add(e);
+  }
+  return lis;
+}
+
+Data* MetaFileUtil::decodeInt(const char** pp, const char* end) {
+  if(*pp >= end) {
+    throw new DlAbortEx(EX_MULFORMED_META_INFO);
+  }
+  char* endTerm = (char*)memchr(*pp, 'e', end-*pp);
+  // TODO if endTerm is null
+  if(endTerm == NULL) {
+    throw new DlAbortEx(EX_MULFORMED_META_INFO);
+  }
+  int numSize = endTerm-*pp;
+
+  Data* data = new Data(*pp, numSize, true);
+  *pp += numSize+1;
+  return data;
+}
+
+Data* MetaFileUtil::decodeWord(const char** pp, const char* end) {
+  if(*pp >= end) {
+    throw new DlAbortEx("mulformed metainfo");
+  }
+  char* delim = (char*)memchr(*pp, ':', end-*pp);
+  // TODO if delim is null
+  if(delim == *pp || delim == NULL) {
+    throw new DlAbortEx(EX_MULFORMED_META_INFO);
+  }
+  int numSize = delim-*pp;
+  char* temp = new char[numSize+1];
+  memcpy(temp, *pp, numSize);
+  temp[numSize] = '\0';
+  char* endptr;
+  int size = strtol(temp, &endptr, 10);
+  if(*endptr != '\0') {
+    delete [] temp;
+    throw new DlAbortEx(EX_MULFORMED_META_INFO);
+  }    
+  delete [] temp;
+
+  if(delim+1+size > end) {
+    throw new DlAbortEx(EX_MULFORMED_META_INFO);
+  }
+
+  Data* data = new Data(delim+1, size);
+  *pp = delim+1+size;
+  return data;
+}
+
+string MetaFileUtil::decodeWordAsString(const char** pp, const char* end) {
+  Data* data = decodeWord(pp, end);
+  string str = data->toString();
+  delete data;
+  return str;
+}

+ 50 - 0
src/MetaFileUtil.h

@@ -0,0 +1,50 @@
+/* <!-- 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_META_FILE_UTIL_H_
+#define _D_META_FILE_UTIL_H_
+
+#include "MetaEntry.h"
+#include "Dictionary.h"
+#include "List.h"
+#include "Data.h"
+#include "common.h"
+#include <string>
+
+using namespace std;
+
+class MetaFileUtil {
+private:
+  MetaFileUtil() {}
+
+  static MetaEntry* bdecodingR(const char** pp, const char* end);
+  static Dictionary* parseDictionaryTree(const char** pp, const char* end);
+  static List* parseListTree(const char** pp, const char* end);
+  static Data* decodeWord(const char** pp, const char* end);
+  static Data* decodeInt(const char** pp, const char* end);
+  static string decodeWordAsString(const char** pp, const char* end);
+
+public:
+  static MetaEntry* parseMetaFile(string file);
+  static MetaEntry* bdecoding(const char* buf, int len);
+};
+
+#endif // _D_META_FILE_UTIL_H_

+ 48 - 0
src/Peer.cc

@@ -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 --> */
+#include "Peer.h"
+
+Peer* Peer::nullPeer = new Peer("", 0, 0, 0);
+
+void Peer::updateBitfield(int index, int operation) {
+  if(operation == 1) {
+    bitfield->setBit(index);
+  } else if(operation == 0) {
+    bitfield->unsetBit(index);
+  }
+}
+
+#define THRESHOLD 1024*1024*2
+
+bool Peer::shouldChoke() const {
+  if(bitfield->countBlock()*0.8 < bitfield->countMissingBlock()) {
+    return false;
+  }
+  if(peerDownload < pieceLength*4 && peerUpload < pieceLength*4) {
+    return false;
+  }
+  if(amChocking) {
+    return !(peerDownload+pieceLength*4 < peerUpload);
+  } else {
+    return peerDownload >= peerUpload+pieceLength*4;
+  }
+}

+ 115 - 0
src/Peer.h

@@ -0,0 +1,115 @@
+/* <!-- 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_H_
+#define _D_PEER_H_
+
+#include "common.h"
+#include "BitfieldMan.h"
+#include <string.h>
+#include <string>
+
+using namespace std;
+
+#define PEER_ID_LENGTH 20
+
+class Peer {
+public:
+  int entryId;
+  string ipaddr;
+  int port;
+  bool amChocking;
+  bool amInterested;
+  bool peerChoking;
+  bool peerInterested;
+  int tryCount;
+  int error;
+  int cuid;
+private:
+  char peerId[PEER_ID_LENGTH];
+  //unsigned char* bitfield;
+  BitfieldMan* bitfield;
+  //int bitfieldLength;
+  long long int peerUpload;
+  long long int peerDownload;
+  int pieceLength;
+  long long int totalLength;
+public:
+  Peer(string ipaddr, int port, int pieceLength, long long int totalLength):
+    entryId(0), ipaddr(ipaddr), port(port),
+    amChocking(true), amInterested(false),
+    peerChoking(true), peerInterested(false),
+    tryCount(0), error(0), cuid(0),
+    bitfield(NULL),// bitfieldLength(0),
+    peerUpload(0), peerDownload(0),
+    pieceLength(pieceLength), totalLength(totalLength) {
+    this->bitfield = new BitfieldMan(pieceLength, totalLength);
+  }
+
+  ~Peer() {
+    if(bitfield != NULL) {
+      delete /*[]*/ bitfield;
+    }
+  }
+
+  void setPeerId(const char* peerId) {
+    memcpy(this->peerId, peerId, PEER_ID_LENGTH);
+  }
+  const char* getPeerId() const { return this->peerId; }
+  
+  void setBitfield(const unsigned char* bitfield, int bitfieldLength) {
+    this->bitfield->setBitfield(bitfield, bitfieldLength);
+    /*
+    if(this->bitfield != NULL) {
+      delete [] this->bitfield;
+    }
+    this->bitfieldLength = bitfieldLength;
+    this->bitfield = new unsigned char[this->bitfieldLength];
+    memcpy(this->bitfield, bitfield, this->bitfieldLength);
+    */
+  }
+  const unsigned char* getBitfield() const { return bitfield->getBitfield(); }
+  int getBitfieldLength() const { return bitfield->getBitfieldLength(); }
+
+  /*
+  void initBitfield(int pieces);
+  */
+
+  /**
+   * operation = 1: set index-th bit 1
+   * operation = 0: set index-th bit 0
+   */
+  void updateBitfield(int index, int operation);
+
+  void addPeerUpload(int size) { peerUpload += size; }
+  void setPeerUpload(long long int size) { peerUpload = size; }
+  long long int getPeerUpload() const { return peerUpload; }
+
+  void addPeerDownload(int size) { peerDownload += size; }
+  void setPeerDownload(long long int size) { peerDownload = size; }
+  long long int getPeerDownload() const { return peerDownload; }
+
+  bool shouldChoke() const;
+
+  static Peer* nullPeer;
+};
+
+#endif // _D_PEER_H_

+ 181 - 0
src/PeerAbstractCommand.cc

@@ -0,0 +1,181 @@
+/* <!-- 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 "PeerAbstractCommand.h"
+#include "DlAbortEx.h"
+#include "DlRetryEx.h"
+#include <sys/time.h>
+#include "Util.h"
+#include "message.h"
+#include "prefs.h"
+
+PeerAbstractCommand::PeerAbstractCommand(int cuid, Peer* peer, TorrentDownloadEngine* e, Socket* s):
+  Command(cuid), e(e), peer(peer), checkSocketIsReadable(false), checkSocketIsWritable(false) {
+
+  if(s != NULL) {
+    socket = new Socket(*s);
+    setReadCheckSocket(socket);
+  } else {
+    socket = NULL;
+  }
+  this->checkPoint.tv_sec = 0;
+  this->checkPoint.tv_usec = 0;
+
+  e->torrentMan->connections++;
+}
+
+PeerAbstractCommand::~PeerAbstractCommand() {
+  setReadCheckSocket(NULL);
+  setWriteCheckSocket(NULL);
+  if(socket != NULL) {
+    delete(socket);
+  }
+  e->torrentMan->connections--;
+}
+
+void PeerAbstractCommand::updateCheckPoint() {
+  gettimeofday(&checkPoint, NULL);
+}
+
+bool PeerAbstractCommand::isTimeoutDetected() {
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  if(checkPoint.tv_sec == 0 && checkPoint.tv_usec == 0) {
+    checkPoint = now;
+    return false;
+  } else {
+    long long int elapsed = Util::difftv(now, checkPoint);
+    if(elapsed >= e->option->getAsInt(PREF_TIMEOUT)*1000000) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+}
+
+bool PeerAbstractCommand::execute() {
+  try {
+    if(e->torrentMan->downloadComplete()) {
+      return true;
+    }
+    beforeSocketCheck();
+    if(checkSocketIsReadable && !readCheckTarget->isReadable(0)
+       || checkSocketIsWritable && !writeCheckTarget->isWritable(0)) {
+      if(isTimeoutDetected()) {
+	// TODO
+	checkPoint.tv_sec = 0;
+	checkPoint.tv_usec = 0;
+	throw new DlRetryEx(EX_TIME_OUT);
+      }
+      e->commands.push(this);
+      return false;
+    }
+    updateCheckPoint();
+    bool returnValue =  executeInternal();
+    //e->torrentMan->updatePeer(peer);
+    return returnValue;
+  } catch(Exception* err) {
+    e->logger->error(MSG_DOWNLOAD_ABORTED, err, cuid);
+    onAbort(err);
+    delete(err);
+    return prepareForNextPeer(0);
+  } catch(DlRetryEx* err) {
+    e->logger->error(MSG_RESTARTING_DOWNLOAD, err, cuid);
+    peer->tryCount++;
+    bool isAbort = e->option->getAsInt(PREF_MAX_TRIES) != 0 &&
+      peer->tryCount >= e->option->getAsInt(PREF_MAX_TRIES);
+    int tryCount = peer->tryCount;
+    if(isAbort) {
+      onAbort(err);
+    }
+    delete(err);
+    if(isAbort) {
+      e->logger->error(MSG_MAX_TRY, cuid, tryCount);
+      return true;
+    } else {
+      return prepareForRetry(e->option->getAsInt(PREF_RETRY_WAIT));
+    }
+  }
+}
+
+// TODO this method removed when PeerBalancerCommand is implemented
+bool PeerAbstractCommand::prepareForNextPeer(int wait) {
+  return true;
+}
+
+bool PeerAbstractCommand::prepareForRetry(int wait) {
+  return true;
+}
+
+void PeerAbstractCommand::onAbort(Exception* ex) {
+  peer->error = 1;
+  peer->tryCount = 0;
+  peer->cuid = 0;
+  peer->amChocking = true;
+  peer->amInterested = false;
+  peer->peerChoking = true;
+  peer->peerInterested = false;
+  e->logger->debug("CUID#%d - peer %s:%d banned.", cuid, peer->ipaddr.c_str(), peer->port);
+}
+
+void PeerAbstractCommand::setReadCheckSocket(Socket* socket) {
+  if(socket == NULL) {
+    if(checkSocketIsReadable) {
+      e->deleteSocketForReadCheck(readCheckTarget);
+      checkSocketIsReadable = false;
+      readCheckTarget = NULL;
+    }
+  } else {
+    if(checkSocketIsReadable) {
+      if(readCheckTarget != socket) {
+	e->deleteSocketForReadCheck(readCheckTarget);
+	e->addSocketForReadCheck(socket);
+	readCheckTarget = socket;
+      }
+    } else {
+      e->addSocketForReadCheck(socket);
+      checkSocketIsReadable = true;
+      readCheckTarget = socket;
+    }
+  }
+}
+
+void PeerAbstractCommand::setWriteCheckSocket(Socket* socket) {
+  if(socket == NULL) {
+    if(checkSocketIsWritable) {
+      e->deleteSocketForWriteCheck(writeCheckTarget);
+      checkSocketIsWritable = false;
+      writeCheckTarget = NULL;
+    }
+  } else {
+    if(checkSocketIsWritable) {
+      if(writeCheckTarget != socket) {
+	e->deleteSocketForWriteCheck(writeCheckTarget);
+	e->addSocketForWriteCheck(socket);
+	writeCheckTarget = socket;
+      }
+    } else {
+      e->addSocketForWriteCheck(socket);
+      checkSocketIsWritable = true;
+      writeCheckTarget = socket;
+    }
+  }
+}

+ 58 - 0
src/PeerAbstractCommand.h

@@ -0,0 +1,58 @@
+/* <!-- 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_ABSTRACT_COMMAND_H_
+#define _D_PEER_ABSTRACT_COMMAND_H_
+
+#include "Command.h"
+#include "Request.h"
+#include "TorrentDownloadEngine.h"
+#include <sys/time.h>
+
+class PeerAbstractCommand : public Command {
+private:
+  void updateCheckPoint();
+  bool isTimeoutDetected();
+  struct timeval checkPoint;
+protected:
+  TorrentDownloadEngine* e;
+  Socket* socket;
+  Peer* peer;
+
+  virtual bool prepareForNextPeer(int wait);
+  virtual bool prepareForRetry(int wait);
+  virtual void onAbort(Exception* ex);
+  virtual bool executeInternal() = 0;
+  virtual void beforeSocketCheck() {}
+  void setReadCheckSocket(Socket* socket);
+  void setWriteCheckSocket(Socket* socket);
+private:
+  bool checkSocketIsReadable;
+  bool checkSocketIsWritable;
+  Socket* readCheckTarget;
+  Socket* writeCheckTarget;
+public:
+  PeerAbstractCommand(int cuid, Peer* peer, TorrentDownloadEngine* e, Socket* s = NULL);
+  virtual ~PeerAbstractCommand();
+  bool execute();
+};
+
+#endif // _D_PEER_ABSTRACT_COMMAND_H_

+ 378 - 0
src/PeerConnection.cc

@@ -0,0 +1,378 @@
+/* <!-- 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 "PeerConnection.h"
+#include "message.h"
+#include "DlAbortEx.h"
+#include "PeerMessageUtil.h"
+#include "Util.h"
+#include <netinet/in.h>
+
+PeerConnection::PeerConnection(int cuid, const Socket* socket,
+			       const Option* op, const Logger* logger,
+			       Peer* peer, TorrentMan* torrentMan)
+  :cuid(cuid), socket(socket), option(op), logger(logger), peer(peer),
+   torrentMan(torrentMan),
+   resbufLength(0), currentPayloadLength(0), lenbufLength(0) {}
+
+PeerConnection::~PeerConnection() {}
+
+void PeerConnection::sendHandshake() const {
+  /**
+   * pstrlen --- '19', 1byte
+   * pstr    --- "BitTorrent protocol", 19bytes
+   * reserved --- \0 * 8, 8bytes
+   * info_hash --- info_hash, 20bytes
+   * peer_id --- peer_id, 20bytes
+   * total: 68bytes
+   */
+  char msg[HANDSHAKE_MESSAGE_LENGTH];
+  memset(msg, 0, sizeof(msg));
+  msg[0] = 19;
+  memcpy(&msg[1], PSTR, strlen(PSTR));
+  memcpy(&msg[28], torrentMan->getInfoHash(), 20);
+  memcpy(&msg[48], torrentMan->peerId.c_str(), 20);
+  writeOutgoingMessageLog("handshake");
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendKeepAlive() const {
+  /**
+   * len --- 0, 4bytes
+   * total: 4bytes
+   */
+  char msg[4];
+  memset(msg, 0, sizeof(msg));
+  writeOutgoingMessageLog("keep-alive");
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::createNLengthMessage(char* msg, int msgLen, int payloadLen, int id) const {
+  assert(msgLen >= 5);
+  memset(msg, 0, msgLen);
+  setIntParam(msg, payloadLen);
+  msg[4] = (char)id;
+}
+
+void PeerConnection::setIntParam(char* dest, int param) const {
+  int nParam = htonl(param);
+  memcpy(dest, &nParam, 4);
+}
+
+void PeerConnection::writeOutgoingMessageLog(const char* msg) const {
+  logger->info(MSG_SEND_PEER_MESSAGE, cuid, peer->ipaddr.c_str(), peer->port, msg);
+}
+
+void PeerConnection::writeOutgoingMessageLog(const char* msg, int index) const {
+  logger->info(MSG_SEND_PEER_MESSAGE_WITH_INDEX, cuid, peer->ipaddr.c_str(), peer->port, msg, index);
+}
+
+void PeerConnection::writeOutgoingMessageLog(const char* msg, const unsigned char* bitfield, int bitfieldLength) const {
+  logger->info(MSG_SEND_PEER_MESSAGE_WITH_BITFIELD, cuid, peer->ipaddr.c_str(), peer->port, msg, Util::toHex(bitfield, bitfieldLength).c_str());
+}
+
+void PeerConnection::writeOutgoingMessageLog(const char* msg, int index, int begin, int length) const {
+  logger->info(MSG_SEND_PEER_MESSAGE_WITH_INDEX_BEGIN_LENGTH, cuid, peer->ipaddr.c_str(), peer->port, msg, index, begin, length);
+}
+
+void PeerConnection::sendChoke() const {
+  /**
+   * len --- 1, 4bytes
+   * id --- 0, 1byte
+   * total: 5bytes
+   */
+  char msg[5];
+  createNLengthMessage(msg, sizeof(msg), 1, 0);
+  writeOutgoingMessageLog("choke");
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendUnchoke() const {
+  /**
+   * len --- 1, 4bytes
+   * id --- 1, 1byte
+   * total: 5bytes
+   */
+  char msg[5];
+  createNLengthMessage(msg, sizeof(msg), 1, 1);
+  writeOutgoingMessageLog("unchoke");
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendInterested() const {
+  /**
+   * len --- 1, 4bytes
+   * id --- 2, 1byte
+   * total: 5bytes
+   */
+  char msg[5];
+  createNLengthMessage(msg, sizeof(msg), 1, 2);
+  writeOutgoingMessageLog("interested");
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendNotInterested() const {
+  /**
+   * len --- 1, 4bytes
+   * id --- 3, 1byte
+   * total: 5bytes
+   */
+  char msg[5];
+  createNLengthMessage(msg, sizeof(msg), 1, 3);
+  writeOutgoingMessageLog("not interested");
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendHave(int index) const {
+  /**
+   * len --- 5, 4bytes
+   * id --- 4, 1byte
+   * piece index --- index, 4bytes
+   * total: 9bytes
+   */
+  char msg[9];
+  createNLengthMessage(msg, sizeof(msg), 5, 4);
+  setIntParam(&msg[5], index);
+  writeOutgoingMessageLog("have", index);
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendBitfield() const {
+  int len = torrentMan->getBitfieldLength();
+  const unsigned char* bitfield = torrentMan->getBitfield();
+  /**
+   * len --- 1+len, 4bytes
+   * id --- 5, 1byte
+   * bitfield --- bitfield, len bytes
+   * total: 5+len bytes
+   */
+  int msgLen = 5+len;
+  char* msg = new char[msgLen];
+  try {
+    createNLengthMessage(msg, msgLen, 1+len, 5);
+    writeOutgoingMessageLog("bitfield", bitfield, len);
+    socket->writeData(msg, msgLen);
+    delete [] msg;
+  } catch(Exception* ex) {
+    delete [] msg;
+    throw;
+  }
+}
+    
+void PeerConnection::sendRequest(int index, int begin, int length) const {
+  /**
+   * len --- 13, 4bytes
+   * id --- 6, 1byte
+   * index --- index, 4bytes
+   * begin --- begin, 4bytes
+   * length --- length, 4bytes
+   * total: 17bytes
+   */
+  char msg[17];
+  createNLengthMessage(msg, sizeof(msg), 13, 6);
+  setIntParam(&msg[5], index);
+  setIntParam(&msg[9], begin);
+  setIntParam(&msg[13], length);
+  writeOutgoingMessageLog("request", index, begin, length);
+  socket->writeData(msg, sizeof(msg));
+}
+
+void PeerConnection::sendPiece(int index, int begin, int length) const {
+  /**
+   * len --- 9+length, 4bytes
+   * id --- 7, 1byte
+   * index --- index, 4bytes
+   * begin --- begin, 4bytes
+   * sub total: 13bytes
+   * additionally, 
+   * block --- data, X bytes
+   */
+  char msg[13];
+  createNLengthMessage(msg, sizeof(msg), 9+length, 7);
+  setIntParam(&msg[5], index);
+  setIntParam(&msg[9], begin);
+  writeOutgoingMessageLog("piece", index, begin, length);
+  socket->writeData(msg, sizeof(msg));
+  int BUF_SIZE = 4096;
+  char buf[BUF_SIZE];
+  int iteration = length/BUF_SIZE;
+  long long int pieceOffset = ((long long int)index*torrentMan->pieceLength)+begin;
+  for(int i = 0; i < iteration; i++) {
+    if(torrentMan->diskWriter->readData(buf, BUF_SIZE, pieceOffset+i*BUF_SIZE) < BUF_SIZE) {
+      throw new DlAbortEx("piece reading failed.");
+    }
+    socket->writeData(buf, BUF_SIZE);
+  }
+  int rem = length%BUF_SIZE;
+  if(rem > 0) {
+    if(torrentMan->diskWriter->readData(buf, rem, pieceOffset+iteration*BUF_SIZE) < rem) {
+      throw new DlAbortEx("piece reading failed.");
+    }
+    socket->writeData(buf, rem);
+  }
+}
+
+void PeerConnection::sendPieceHeader(int index, int begin, int length) const {
+  /**
+   * len --- 9+length, 4bytes
+   * id --- 7, 1byte
+   * index --- index, 4bytes
+   * begin --- begin, 4bytes
+   * sub total: 13bytes
+   * additionally, 
+   * block --- data, X bytes
+   */
+  char msg[13];
+  createNLengthMessage(msg, sizeof(msg), 9+length, 7);
+  setIntParam(&msg[5], index);
+  setIntParam(&msg[9], begin);
+  writeOutgoingMessageLog("piece", index, begin, length);
+  socket->writeData(msg, sizeof(msg));
+}
+
+int PeerConnection::sendPieceData(long long int offset, int length) const {
+  int BUF_SIZE = 256;
+  char buf[BUF_SIZE];
+  int iteration = length/BUF_SIZE;
+  int writtenLength = 0;
+  bool isWritable = true;
+  for(int i = 0; i < iteration; i++) {
+    isWritable = socket->isWritable(0);
+    if(!isWritable) {
+      return writtenLength;
+    }
+    if(torrentMan->diskWriter->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
+      throw new DlAbortEx("piece reading failed.");
+    }
+    socket->writeData(buf, BUF_SIZE);
+    writtenLength += BUF_SIZE;
+  }
+  if(socket->isWritable(0)) {
+    int rem = length%BUF_SIZE;
+    if(rem > 0) {
+      if(torrentMan->diskWriter->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
+	throw new DlAbortEx("piece reading failed.");
+      }
+      socket->writeData(buf, rem);
+      writtenLength += rem;
+    }
+  }
+  return writtenLength;
+}
+
+
+void PeerConnection::sendCancel(int index, int begin, int length) const {
+  /**
+   * len --- 13, 4bytes
+   * id --- 8, 1byte
+   * index --- index, 4bytes
+   * begin --- begin, 4bytes
+   * length -- length, 4bytes
+   * total: 17bytes
+   */
+  char msg[17];
+  createNLengthMessage(msg, sizeof(msg), 13, 8);
+  setIntParam(&msg[5], index);
+  setIntParam(&msg[9], begin);
+  setIntParam(&msg[13], length);
+  writeOutgoingMessageLog("cancel", index, begin, length);
+  socket->writeData(msg, sizeof(msg));
+}
+
+PeerMessage* PeerConnection::receiveMessage() {
+  if(!socket->isReadable(0)) {
+    return NULL;
+  }
+  if(resbufLength == 0 && lenbufLength != 4) {
+    // read payload size, 4-byte integer
+    int remain = 4-lenbufLength;
+    int temp = remain;
+    socket->readData(lenbuf+lenbufLength, temp);
+    if(temp == 0) {
+      // we got EOF
+      throw new DlAbortEx(EX_EOF_FROM_PEER);
+    }
+    if(remain != temp) {
+      // still 4-temp bytes to go
+      lenbufLength += temp;
+      return NULL;
+    }
+    //payloadLen = ntohl(nPayloadLen);
+    int payloadLength = ntohl(*((int*)lenbuf));
+    if(payloadLength > MAX_PAYLOAD_LEN) {
+      throw new DlAbortEx("max payload length exceeded. length = %d",
+			  payloadLength);
+    }
+    currentPayloadLength = payloadLength;
+  }
+  // we have currentPayloadLen-resbufLen bytes to read
+  int remaining = currentPayloadLength-resbufLength;
+  if(remaining > 0) {
+    socket->readData(resbuf+resbufLength, remaining);
+    if(remaining == 0) {
+      // we got EOF
+      throw new DlAbortEx(EX_EOF_FROM_PEER);
+    }
+    resbufLength += remaining;
+    if(currentPayloadLength != resbufLength) {
+      return NULL;
+    }
+  }
+  // we got whole payload.
+  resbufLength = 0;
+  lenbufLength = 0;
+  PeerMessage* peerMessage = PeerMessageUtil::createPeerMessage(resbuf,	currentPayloadLength);
+  try {
+    PeerMessageUtil::checkIntegrity(peerMessage, torrentMan->pieceLength,
+				    torrentMan->pieces, torrentMan->totalSize);
+  } catch(Exception* e) {
+    delete peerMessage;
+    throw;
+  }
+  return peerMessage;
+}
+
+HandshakeMessage* PeerConnection::receiveHandshake() {
+  if(!socket->isReadable(0)) {
+    return NULL;
+  }
+  int remain = HANDSHAKE_MESSAGE_LENGTH-resbufLength;
+  int temp = remain;
+  socket->readData(resbuf+resbufLength, temp);
+  if(temp == 0) {
+    // we got EOF
+    throw new DlAbortEx(EX_EOF_FROM_PEER);
+  }
+  if(remain != temp) {
+    resbufLength += temp;
+    return NULL;
+  }
+  // we got whole handshake payload
+  resbufLength = 0;
+  HandshakeMessage* handshakeMessage = PeerMessageUtil::createHandshakeMessage(resbuf);
+  try {
+    PeerMessageUtil::checkHandshake(handshakeMessage, torrentMan->getInfoHash());
+  } catch(Exception* e) {
+    delete handshakeMessage;
+    throw;
+  }
+  return handshakeMessage;
+}

+ 82 - 0
src/PeerConnection.h

@@ -0,0 +1,82 @@
+/* <!-- 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_CONNECTION_H_
+#define _D_PEER_CONNECTION_H_
+
+#include "Option.h"
+#include "Socket.h"
+#include "Logger.h"
+#include "TorrentMan.h"
+#include "PeerMessage.h"
+#include "HandshakeMessage.h"
+
+// we assume maximum length of incoming message is "piece" message with 16KB
+// data. Messages beyond that size are dropped.
+#define MAX_PAYLOAD_LEN (9+16*1024)
+
+class PeerConnection {
+private:
+  int cuid;
+  const Socket* socket;
+  const Option* option;
+  const Logger* logger;
+  Peer* peer;
+  TorrentMan* torrentMan;
+
+  char resbuf[MAX_PAYLOAD_LEN];
+  int resbufLength;
+  int currentPayloadLength;
+  char lenbuf[4];
+  int lenbufLength;
+
+  void createNLengthMessage(char* msg, int msgLen, int payloadLen, int id) const;
+  void setIntParam(char* dest, int param) const;
+
+  void writeOutgoingMessageLog(const char* msg) const;
+  void writeOutgoingMessageLog(const char* msg, int index) const;
+  void writeOutgoingMessageLog(const char* msg, const unsigned char* bitfield, int bitfieldLength) const;
+  void writeOutgoingMessageLog(const char* msg, int index, int begin, int length) const;
+public:
+  PeerConnection(int cuid, const Socket* socket, const Option* op,
+		 const Logger* logger, Peer* peer, TorrentMan* torrenMan);
+  ~PeerConnection();
+
+  void sendHandshake() const;
+  void sendKeepAlive() const;
+  void sendChoke() const;
+  void sendUnchoke() const;
+  void sendInterested() const;
+  void sendNotInterested() const;
+  void sendHave(int index) const;
+  void sendBitfield() const;
+  void sendRequest(int index, int begin, int length) const;
+  void sendPiece(int index, int begin, int length) const;
+  void sendPieceHeader(int index, int begin, int length) const;
+  int sendPieceData(long long int offset, int length) const;
+  void sendCancel(int index, int begin, int length) const;
+  PeerMessage* receiveMessage();
+  HandshakeMessage* receiveHandshake();
+
+  Peer* getPeer() const { return peer; }
+};
+
+#endif // _D_PEER_CONNECTION_H_

+ 74 - 0
src/PeerInitiateConnectionCommand.cc

@@ -0,0 +1,74 @@
+/* <!-- 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 "PeerInitiateConnectionCommand.h"
+#include "PeerInteractionCommand.h"
+#include "Util.h"
+#include "DlAbortEx.h"
+#include "message.h"
+#include "prefs.h"
+
+PeerInitiateConnectionCommand::PeerInitiateConnectionCommand(int cuid,
+							     Peer* peer,
+							     TorrentDownloadEngine* e)
+  :PeerAbstractCommand(cuid, peer, e) {}
+
+PeerInitiateConnectionCommand::~PeerInitiateConnectionCommand() {}
+
+bool PeerInitiateConnectionCommand::executeInternal() {
+  socket = new Socket();
+  // socket->establishConnection(...);
+
+  Command* command;
+  e->logger->info(MSG_CONNECTING_TO_SERVER, cuid, peer->ipaddr.c_str(),
+		  peer->port);
+  socket->establishConnection(peer->ipaddr, peer->port);
+  command = new PeerInteractionCommand(cuid, peer, e, socket, PeerInteractionCommand::INITIATOR_SEND_HANDSHAKE);
+
+  e->commands.push(command);
+  return true;
+}
+
+// TODO this method removed when PeerBalancerCommand is implemented
+bool PeerInitiateConnectionCommand::prepareForNextPeer(int wait) {
+  if(e->torrentMan->isPeerAvailable()) {
+    Peer* peer = e->torrentMan->getPeer();
+    int newCuid = e->torrentMan->getNewCuid();
+    peer->cuid = newCuid;
+    PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e);
+    e->commands.push(command);
+  }
+  return true;
+}
+
+bool PeerInitiateConnectionCommand::prepareForRetry(int wait) {
+  PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(cuid, peer, e);
+  e->commands.push(command);
+  return true;
+}
+
+bool PeerInitiateConnectionCommand::useProxy() {
+  return e->option->get(PREF_HTTP_PROXY_ENABLED) == V_TRUE;
+}
+
+bool PeerInitiateConnectionCommand::useProxyTunnel() {
+  return e->option->get(PREF_HTTP_PROXY_METHOD) == V_TUNNEL;
+}

+ 40 - 0
src/PeerInitiateConnectionCommand.h

@@ -0,0 +1,40 @@
+/* <!-- 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_INITIATE_CONNECTION_H_
+#define _D_PEER_INITIATE_CONNECTION_H_
+
+#include "PeerAbstractCommand.h"
+
+class PeerInitiateConnectionCommand : public PeerAbstractCommand {
+private:
+  bool useProxy();
+  bool useProxyTunnel();
+protected:
+  bool executeInternal();
+  bool prepareForRetry(int wait);
+  bool prepareForNextPeer(int wait);
+public:
+  PeerInitiateConnectionCommand(int cuid,  Peer* peer, TorrentDownloadEngine* e);
+  ~PeerInitiateConnectionCommand();
+};
+
+#endif // _D_PEER_INITIATE_CONNECTION_H_

+ 477 - 0
src/PeerInteractionCommand.cc

@@ -0,0 +1,477 @@
+/* <!-- 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 "PeerInteractionCommand.h"
+#include "PeerInitiateConnectionCommand.h"
+#include "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+#include "Util.h"
+#include "message.h"
+
+PeerInteractionCommand::PeerInteractionCommand(int cuid, Peer* peer,
+					       TorrentDownloadEngine* e,
+					       Socket* s, int sequence)
+  :PeerAbstractCommand(cuid, peer, e, s), sequence(sequence) {
+  if(sequence == INITIATOR_SEND_HANDSHAKE) {
+    setReadCheckSocket(NULL);
+    setWriteCheckSocket(socket);
+  }
+  peerConnection = new PeerConnection(cuid, socket, e->option, e->logger,
+				      peer, e->torrentMan);
+  requestSlotMan = new RequestSlotMan(cuid, &pendingMessages, peerConnection,
+				      e->torrentMan, e->logger);
+  piece = Piece::nullPiece;
+  keepAliveCheckPoint.tv_sec = 0;
+  keepAliveCheckPoint.tv_usec = 0;
+}
+
+PeerInteractionCommand::~PeerInteractionCommand() {
+  delete peerConnection;
+  delete requestSlotMan;
+}
+
+bool PeerInteractionCommand::executeInternal() {
+  if(sequence == INITIATOR_SEND_HANDSHAKE) {
+    socket->setBlockingMode();
+    setReadCheckSocket(socket);
+  }
+  setWriteCheckSocket(NULL);
+
+  switch(sequence) {
+  case INITIATOR_SEND_HANDSHAKE:
+    peerConnection->sendHandshake();
+    sequence = INITIATOR_WAIT_HANDSHAKE;
+    break;
+  case INITIATOR_WAIT_HANDSHAKE: {
+    HandshakeMessage* handshakeMessage = peerConnection->receiveHandshake();
+    if(handshakeMessage == NULL) {
+      break;
+    }
+    peer->setPeerId(handshakeMessage->peerId);
+    e->logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid,
+		    peer->ipaddr.c_str(), peer->port,
+		    handshakeMessage->toString().c_str());
+    delete handshakeMessage;
+    if(e->torrentMan->getDownloadedSize() > 0) {
+      peerConnection->sendBitfield();
+    }
+    sequence = WIRED;
+    break;
+  }
+  case RECEIVER_WAIT_HANDSHAKE: {
+    HandshakeMessage* handshakeMessage = peerConnection->receiveHandshake();
+    if(handshakeMessage == NULL) {
+      break;
+    }
+    peer->setPeerId(handshakeMessage->peerId);
+    e->logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid,
+		    peer->ipaddr.c_str(), peer->port,
+		    handshakeMessage->toString().c_str());
+    delete handshakeMessage;
+    peerConnection->sendHandshake();
+    if(e->torrentMan->getDownloadedSize() > 0) {
+      peerConnection->sendBitfield();
+    }
+    sequence = WIRED;    
+    break;
+  }
+  case WIRED:
+    syncPiece();
+    decideChoking();
+    for(int i = 0; i < 10; i++) {
+      if(!socket->isReadable(0)) {
+	break;
+      }
+      receiveMessage();
+    }
+    //detectTimeoutAndDuplicateBlock();
+    requestSlotMan->deleteTimedoutRequestSlot(piece);
+    requestSlotMan->deleteCompletedRequestSlot(piece);
+    sendInterest();
+    sendMessages();
+    break;
+  }
+  if(pendingMessages.size() > 0) {
+    setWriteCheckSocket(socket);
+  }
+  e->commands.push(this);
+  return false;
+}
+
+void PeerInteractionCommand::syncPiece() {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  e->torrentMan->syncPiece(piece);
+}
+
+void PeerInteractionCommand::decideChoking() {
+  if(peer->shouldChoke()) {
+    if(!peer->amChocking) {
+      PendingMessage pendingMessage(PeerMessage::CHOKE, peerConnection);
+      pendingMessages.push_back(pendingMessage);
+    }
+  } else if(peer->amChocking && peer->peerInterested) {
+    PendingMessage pendingMessage(PeerMessage::UNCHOKE, peerConnection);
+    pendingMessages.push_back(pendingMessage);
+  } else if(!peer->peerInterested) {
+    PendingMessage pendingMessage(PeerMessage::CHOKE, peerConnection);
+    pendingMessages.push_back(pendingMessage);
+  }
+}
+
+void PeerInteractionCommand::receiveMessage() {
+  PeerMessage* message = peerConnection->receiveMessage();
+  if(message == NULL) {
+    return;
+  }
+  e->logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid,
+		  peer->ipaddr.c_str(), peer->port,
+		  message->toString().c_str());
+  try {
+    switch(message->getId()) {
+    case PeerMessage::KEEP_ALIVE:
+      break;
+    case PeerMessage::CHOKE:
+      peer->peerChoking = true;
+      requestSlotMan->deleteAllRequestSlot(piece);
+      break;
+    case PeerMessage::UNCHOKE:
+      peer->peerChoking = false;
+      break;
+    case PeerMessage::INTERESTED:
+      peer->peerInterested = true;
+      break;
+    case PeerMessage::NOT_INTERESTED:
+      peer->peerInterested = false;
+      break;
+    case PeerMessage::HAVE:
+      peer->updateBitfield(message->getIndex(), 1);
+      break;
+    case PeerMessage::BITFIELD:
+      peer->setBitfield(message->getBitfield(), message->getBitfieldLength());
+      break;
+    case PeerMessage::REQUEST:
+      if(e->torrentMan->hasPiece(message->getIndex())) {
+	PendingMessage pendingMessage
+	  = PendingMessage::createPieceMessage(message->getIndex(),
+					       message->getBegin(),
+					       message->getLength(),
+					       e->torrentMan->pieceLength,
+					       peerConnection);
+	pendingMessages.push_back(pendingMessage);
+	e->torrentMan->addUploadedSize(message->getLength());
+	e->torrentMan->addDeltaUpload(message->getLength());
+      }
+      break;
+    case PeerMessage::CANCEL:
+      deletePendingMessage(message);
+      break;
+    case PeerMessage::PIECE: {
+      RequestSlot slot = requestSlotMan->getCorrespoindingRequestSlot(message);
+      peer->addPeerUpload(message->getBlockLength());
+      if(!Piece::isNull(piece) && !RequestSlot::isNull(slot)) {
+	long long int offset =
+	  ((long long int)message->getIndex())*e->torrentMan->pieceLength+message->getBegin();
+	e->logger->debug("CUID#%d - write block length = %d, offset=%lld",
+			 cuid, message->getBlockLength(), offset);      
+	e->torrentMan->diskWriter->writeData(message->getBlock(),
+					     message->getBlockLength(),
+					     offset);
+	piece.completeBlock(slot.getBlockIndex());
+	requestSlotMan->deleteRequestSlot(slot);
+	e->torrentMan->updatePiece(piece);
+	e->logger->debug("CUID#%d - setting piece bit index=%d", cuid,
+			 slot.getBlockIndex());
+	e->torrentMan->addDeltaDownload(message->getBlockLength());
+	if(piece.pieceComplete()) {
+	  if(checkPieceHash(piece)) {
+	    onGotNewPiece();
+	  } else {
+	    onGotWrongPiece();
+	  }
+	}
+      }
+      break;
+    }
+    }
+    delete message;
+  } catch(Exception* ex) {
+    delete message;
+    throw;
+  }
+}
+
+void PeerInteractionCommand::deletePendingMessage(PeerMessage* cancelMessage) {
+  for(PendingMessages::iterator itr = pendingMessages.begin();
+      itr != pendingMessages.end();) {
+    PendingMessage& pendingMessage = *itr;
+    if(pendingMessage.getPeerMessageId() == PeerMessage::PIECE &&
+       pendingMessage.getIndex() == cancelMessage->getIndex() &&
+       pendingMessage.getBegin() == cancelMessage->getBegin() &&
+       pendingMessage.getLength() == cancelMessage->getLength() &&
+       !pendingMessage.isInProgress()) {
+      e->logger->debug("CUID#%d - deleting pending piece message because cancel message received. index=%d, begin=%d, length=%d",
+		       cuid,
+		       pendingMessage.getIndex(),
+		       pendingMessage.getBegin(),
+		       pendingMessage.getLength());
+      itr = pendingMessages.erase(itr);
+    } else {
+      itr++;
+    }
+  }
+}
+
+void PeerInteractionCommand::onGotNewPiece() {
+  e->logger->info(MSG_GOT_NEW_PIECE, cuid, piece.getIndex());
+  e->torrentMan->completePiece(piece);
+  e->torrentMan->advertisePiece(cuid, piece.getIndex());
+  piece = Piece::nullPiece;
+}
+
+void PeerInteractionCommand::onGotWrongPiece() {
+  e->logger->error(MSG_GOT_WRONG_PIECE, cuid, piece.getIndex());
+  erasePieceOnDisk(piece);
+  piece.clearAllBlock();
+  e->torrentMan->updatePiece(piece);
+}
+
+/*
+const RequestSlot& PeerInteractionCommand::getRequestSlot(int index, int begin, int length) const {
+  for(RequestSlots::const_iterator itr = requestSlots.begin(); itr != requestSlots.end(); itr++) {
+    const RequestSlot& slot = *itr;
+    if(slot.index == index && slot.begin == begin && slot.length == length) {
+      return slot;
+    }
+  }
+  return RequestSlot::nullSlot;
+}
+*/
+/*
+bool PeerInteractionCommand::deleteRequestSlot(const RequestSlot& slot) {
+  for(RequestSlots::iterator itr = requestSlots.begin(); itr != requestSlots.end(); itr++) {
+    if(slot.index == itr->index && slot.begin == itr->begin && slot.length == itr->length) {
+      requestSlots.erase(itr);
+      return true;
+    }
+  }
+  return false;  
+}
+*/
+/*
+void PeerInteractionCommand::deleteAllRequestSlot() {
+  if(!Piece::isNull(piece)) {
+    for(RequestSlots::const_iterator itr = requestSlots.begin(); itr != requestSlots.end(); itr++) {
+      if(itr->index == piece.getIndex()) {
+	piece.cancelBlock(itr->blockIndex);
+      }
+    }
+    e->torrentMan->updatePiece(piece);
+  }
+  requestSlots.clear();
+}
+*/
+// TODO this method removed when PeerBalancerCommand is implemented
+bool PeerInteractionCommand::prepareForNextPeer(int wait) {
+  if(e->torrentMan->isPeerAvailable()) {
+    Peer* peer = e->torrentMan->getPeer();
+    int newCuid = e->torrentMan->getNewCuid();
+    peer->cuid = newCuid;
+    PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e);
+    e->commands.push(command);
+  }
+  return true;
+}
+
+bool PeerInteractionCommand::prepareForRetry(int wait) {
+  e->commands.push(this);
+  return false;
+}
+/*
+void PeerInteractionCommand::detectTimeoutAndDuplicateBlock() {
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  for(RequestSlots::iterator itr = requestSlots.begin(); itr != requestSlots.end();) {
+    const RequestSlot& slot = *itr;
+    if(slot.isTimeout(120) || piece.hasBlock(slot.blockIndex)) {
+      e->logger->debug("CUID#%d - deleting requestslot blockIndex %d", cuid, slot.blockIndex);
+      if(slot.isTimeout(120)) {
+	e->logger->debug("CUID#%d - because of timeout", cuid);
+      } else {
+	e->logger->debug("CUID#%d - because of duplicate block", cuid);
+      }
+      piece.cancelBlock(slot.blockIndex);
+      e->torrentMan->updatePiece(piece);
+      // send cancel message
+      PendingMessage pendingMessage =
+	PendingMessage::createCancelMessage(piece.getIndex(),
+					    slot.blockIndex*piece.getBlockLength(),
+					    piece.getBlockLength(slot.blockIndex),
+					    peerConnection);
+      pendingMessages.push_back(pendingMessage);
+      itr = requestSlots.erase(itr);
+    } else {
+      itr++;
+    }
+  }
+}
+*/
+Piece PeerInteractionCommand::getNewPieceAndSendInterest() {
+  Piece piece = e->torrentMan->getMissingPiece(peer->getBitfield(),
+					 peer->getBitfieldLength());
+  if(Piece::isNull(piece)) {
+    e->logger->debug("CUID#%d - try to send not-interested", cuid);
+    PendingMessage pendingMessage(PeerMessage::NOT_INTERESTED, peerConnection);
+    pendingMessages.push_back(pendingMessage);
+  } else {
+    e->logger->debug("CUID#%d - try to send interested", cuid);
+    PendingMessage pendingMessage(PeerMessage::INTERESTED, peerConnection);
+    pendingMessages.push_back(pendingMessage);
+    //piecefield = new BitfieldMan(16*1024, piece.length);
+  }
+  return piece;
+}
+
+void PeerInteractionCommand::sendInterest() {
+  if(Piece::isNull(piece)) {
+    // retrive new piece from TorrentMan
+    piece = getNewPieceAndSendInterest();
+  } else if(peer->peerChoking) {
+    // TODO separate method is better
+    requestSlotMan->deleteAllRequestSlot(piece);
+    e->torrentMan->cancelPiece(piece);
+    piece = Piece::nullPiece;
+  } else if(piece.pieceComplete()) {
+    piece = getNewPieceAndSendInterest();
+  }
+}
+
+void PeerInteractionCommand::createRequestPendingMessage(int blockIndex) {
+  PendingMessage pendingMessage =
+    PendingMessage::createRequestMessage(piece.getIndex(),
+					 blockIndex*piece.getBlockLength(),
+					 piece.getBlockLength(blockIndex),
+					 peerConnection);
+  pendingMessages.push_back(pendingMessage);
+  RequestSlot requestSlot(piece.getIndex(),
+			  blockIndex*piece.getBlockLength(),
+			  piece.getBlockLength(blockIndex),
+			  blockIndex);
+  requestSlotMan->addRequestSlot(requestSlot);
+}
+
+void PeerInteractionCommand::sendMessages() {
+  if(!Piece::isNull(piece) && !peer->peerChoking) {
+    if(e->torrentMan->isEndGame()) {
+      vector<int> missingBlockIndexes = piece.getAllMissingBlockIndexes();
+      if(requestSlotMan->isEmpty()) {
+	for(vector<int>::const_iterator itr = missingBlockIndexes.begin();
+	    itr != missingBlockIndexes.end(); itr++) {
+	  createRequestPendingMessage(*itr);
+	}
+      }
+    } else {
+      for(int i = requestSlotMan->countRequestSlot(); i <= 5; i++) {
+	int blockIndex = piece.getMissingUnusedBlockIndex();
+	if(blockIndex == -1) {
+	  if(requestSlotMan->isEmpty()) {
+	    piece = Piece::nullPiece;
+	  }
+	  break;
+	}
+	e->torrentMan->updatePiece(piece);
+	createRequestPendingMessage(blockIndex);
+      }
+    }
+  }
+
+  for(PendingMessages::iterator itr = pendingMessages.begin(); itr != pendingMessages.end();) {
+    if(itr->processMessage()) {
+      itr = pendingMessages.erase(itr);
+    } else {
+      //setWriteCheckSocket(socket);
+      break;
+    }
+  }
+}
+
+void PeerInteractionCommand::onAbort(Exception* ex) {
+  requestSlotMan->deleteAllRequestSlot(piece);
+  e->torrentMan->cancelPiece(piece);
+  PeerAbstractCommand::onAbort(ex);
+}
+
+void PeerInteractionCommand::keepAlive() {
+  if(keepAliveCheckPoint.tv_sec == 0 && keepAliveCheckPoint.tv_usec == 0) {
+    gettimeofday(&keepAliveCheckPoint, NULL);
+  } else {
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    if(Util::difftv(now, keepAliveCheckPoint) >= 120*1000000) {
+      if(pendingMessages.empty()) {
+	peerConnection->sendKeepAlive();
+      }
+      keepAliveCheckPoint = now;
+    }
+  }
+}
+
+void PeerInteractionCommand::beforeSocketCheck() {
+  if(sequence == WIRED) {
+    e->torrentMan->unadvertisePiece(cuid);
+
+    vector<int> indexes = e->torrentMan->getAdvertisedPieceIndexes(cuid);
+    if(indexes.size() >= 20) {
+      PendingMessage pendingMessage(PeerMessage::BITFIELD, peerConnection);
+      pendingMessages.push_back(pendingMessage);
+    } else {
+      for(vector<int>::iterator itr = indexes.begin(); itr != indexes.end(); itr++) {
+	PendingMessage pendingMessage = PendingMessage::createHaveMessage(*itr, peerConnection);
+	pendingMessages.push_back(pendingMessage);
+      }
+    }
+    if(indexes.size() == 0) {
+      keepAlive();
+    }
+  }
+}
+
+bool PeerInteractionCommand::checkPieceHash(const Piece& piece) {
+  long long int offset = ((long long int)piece.getIndex())*e->torrentMan->pieceLength;
+  return e->torrentMan->diskWriter->sha1Sum(offset, piece.getLength()) ==
+    e->torrentMan->getPieceHash(piece.getIndex());
+}
+
+void PeerInteractionCommand::erasePieceOnDisk(const Piece& piece) {
+  int BUFSIZE = 4096;
+  char buf[BUFSIZE];
+  memset(buf, 0, BUFSIZE);
+  long long int offset = ((long long int)piece.getIndex())*e->torrentMan->pieceLength;
+  for(int i = 0; i < piece.getLength()/BUFSIZE; i++) {
+    e->torrentMan->diskWriter->writeData(buf, BUFSIZE, offset);
+    offset += BUFSIZE;
+  }
+  int r = piece.getLength()%BUFSIZE;
+  if(r > 0) {
+    e->torrentMan->diskWriter->writeData(buf, r, offset);
+  }
+}

+ 76 - 0
src/PeerInteractionCommand.h

@@ -0,0 +1,76 @@
+/* <!-- 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_INTERACTION_COMMAND_H_
+#define _D_PEER_INTERACTION_COMMAND_H_
+
+#include "PeerAbstractCommand.h"
+#include "PeerConnection.h"
+#include "PendingMessage.h"
+#include "RequestSlotMan.h"
+#include <vector>
+
+using namespace std;
+
+class PeerInteractionCommand : public PeerAbstractCommand {
+private:
+  int sequence;
+  PeerConnection* peerConnection;
+  RequestSlotMan* requestSlotMan;
+  PendingMessages pendingMessages;
+  Piece piece;
+  struct timeval keepAliveCheckPoint;
+  void receiveMessage();
+  void syncPiece();
+  void detectTimeoutAndDuplicateBlock();
+  void decideChoking();
+  void sendInterest();
+  void sendMessages();
+  void createRequestPendingMessage(int blockIndex);
+  void deletePendingMessage(PeerMessage* cancelMessage);
+  const RequestSlot& getRequestSlot(int index, int begin, int length) const;
+  bool deleteRequestSlot(const RequestSlot& slot);
+  void deleteAllRequestSlot();
+  bool checkPieceHash(const Piece& piece);
+  void erasePieceOnDisk(const Piece& piece);
+  void keepAlive();
+  Piece getNewPieceAndSendInterest();
+  void onGotNewPiece();
+  void onGotWrongPiece();
+protected:
+  bool executeInternal();
+  bool prepareForRetry(int wait);
+  bool prepareForNextPeer(int wait);
+  void onAbort(Exception* ex);
+  void beforeSocketCheck();
+public:
+  PeerInteractionCommand(int cuid, Peer* peer, TorrentDownloadEngine* e, Socket* s, int sequence);
+  ~PeerInteractionCommand();
+
+  enum Seq {
+    INITIATOR_SEND_HANDSHAKE,
+    INITIATOR_WAIT_HANDSHAKE,
+    RECEIVER_SEND_HANDSHAKE,
+    RECEIVER_WAIT_HANDSHAKE,
+    WIRED};
+};
+
+#endif // _D_PEER_INTERACTION_COMMAND_H_

+ 91 - 0
src/PeerListenCommand.cc

@@ -0,0 +1,91 @@
+/* <!-- 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 "PeerListenCommand.h"
+#include "PeerInteractionCommand.h"
+
+PeerListenCommand::PeerListenCommand(int cuid, TorrentDownloadEngine* e)
+  :Command(cuid), e(e), socket(NULL) {
+}
+
+PeerListenCommand::~PeerListenCommand() {
+  if(socket != NULL) {
+    delete socket;
+  }
+}
+
+int PeerListenCommand::bindPort(int portRangeStart, int portRangeEnd) {
+  if(portRangeStart > portRangeEnd) {
+    return -1;
+  }
+  for(int port = portRangeStart; port <= portRangeEnd; port++) {
+    try {
+      socket = new Socket();
+      socket->beginListen(port);
+      return port;
+    } catch(Exception* ex) {
+      e->logger->error("CUID#%d - an error occurred while binding port=%d",
+		       cuid, port);
+      delete socket;
+      socket = NULL;
+    }
+  }
+  return -1;
+}
+
+bool PeerListenCommand::execute() {
+  if(e->torrentMan->downloadComplete()) {
+    return true;
+  }
+  for(int i = 0; i < 3 && socket->isReadable(0); i++) {
+    Socket* peerSocket = NULL;
+    try {
+      peerSocket = socket->acceptConnection();
+      if(e->torrentMan->connections < MAX_PEERS) {
+	pair<string, int> peerInfo;
+	peerSocket->getPeerInfo(peerInfo);
+	Peer* peer = new Peer(peerInfo.first, peerInfo.second,
+			      e->torrentMan->pieceLength,
+			      e->torrentMan->totalSize);
+	if(e->torrentMan->addPeer(peer, true)) {
+	  int newCuid =  e->torrentMan->getNewCuid();
+	  peer->cuid = newCuid;
+	  PeerInteractionCommand* command =
+	    new PeerInteractionCommand(newCuid, peer, e, peerSocket,
+				       PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE);
+	  e->commands.push(command);
+	  e->logger->debug("CUID#%d - incoming connection, adding new command CUID#%d", cuid, newCuid);
+	} else {
+	  delete peer;
+	}
+      }
+      delete peerSocket;
+    } catch(Exception* ex) {
+      e->logger->error("CUID#%d - error in accepting connection", cuid, ex);
+      delete ex;
+      if(peerSocket != NULL) {
+	delete peerSocket;
+      }
+    }		    
+  }
+  e->commands.push(this);
+  return false;
+}

+ 42 - 0
src/PeerListenCommand.h

@@ -0,0 +1,42 @@
+/* <!-- 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_LISTEN_COMMAND_H_
+#define _D_PEER_LISTEN_COMMAND_H_
+
+#include "Command.h"
+#include "TorrentDownloadEngine.h"
+
+class PeerListenCommand : public Command {
+private:
+  TorrentDownloadEngine* e;
+  Socket* socket;
+
+public:
+  PeerListenCommand(int cuid, TorrentDownloadEngine* e);
+  ~PeerListenCommand();
+  
+  bool execute();
+
+  int bindPort(int portRangeStart, int portRangeEnd);
+};
+
+#endif // _D_PEER_LISTEN_COMMAND_H_

+ 72 - 0
src/PeerMessage.cc

@@ -0,0 +1,72 @@
+/* <!-- 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 "PeerMessage.h"
+#include "Util.h"
+
+void PeerMessage::setBitfield(const unsigned char* bitfield, int bitfieldLength) {
+  if(this->bitfield != NULL) {
+    delete [] bitfield;
+  }
+  this->bitfieldLength = bitfieldLength;
+  this->bitfield = new unsigned char[this->bitfieldLength];
+  memcpy(this->bitfield, bitfield, this->bitfieldLength);
+}
+
+void PeerMessage::setBlock(const char* block, int blockLength) {
+  if(this->block != NULL) {
+    delete [] block;
+  }
+  this->blockLength = blockLength;
+  this->block = new char[this->blockLength];
+  memcpy(this->block, block, this->blockLength);
+}
+
+string PeerMessage::toString() const {
+  switch(id) {
+  case CHOKE:
+    return "choke";
+  case UNCHOKE:
+    return "unchoke";
+  case INTERESTED:
+    return "interested";
+  case NOT_INTERESTED:
+    return "not interested";
+  case HAVE:
+    return "have index="+Util::itos(index);
+  case BITFIELD:
+    return "bitfield "+Util::toHex(bitfield, bitfieldLength);
+  case REQUEST:
+    return "request index="+Util::itos(index)+", begin="+Util::itos(begin)+
+      ", length="+Util::itos(length);
+  case PIECE:
+    return "piece index="+Util::itos(index)+", begin="+Util::itos(begin)+
+      ", length="+Util::itos(blockLength);
+  case CANCEL:
+    return "calcel index="+Util::itos(index)+", begin="+Util::itos(begin)+
+      ", length="+Util::itos(length);
+  case KEEP_ALIVE:
+    return "keep alive";
+  default:
+    return "unknown";
+  }
+}
+

+ 83 - 0
src/PeerMessage.h

@@ -0,0 +1,83 @@
+/* <!-- 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_MESSAGE_H_
+#define _D_PEER_MESSAGE_H_
+
+#include "common.h"
+#include <string>
+
+class PeerMessage {
+private:
+  int id;
+  int index;
+  int begin;
+  int length;
+  unsigned char* bitfield;
+  int bitfieldLength;
+  char* block;
+  int blockLength;
+public:
+  PeerMessage():bitfield(NULL), bitfieldLength(0),
+		block(NULL), blockLength(0) {}
+  ~PeerMessage() {
+    if(bitfield != NULL) {
+      delete [] bitfield;
+    }
+    if(block != NULL) {
+      delete [] block;
+    }
+  }
+
+  void setBitfield(const unsigned char* bitfield, int bitfieldLength);
+  const unsigned char* getBitfield() const { return bitfield; }
+  
+  void setBlock(const char* block, int blockLength);
+  const char* getBlock() const { return block; }
+  
+  int getBitfieldLength() const { return bitfieldLength; }
+  int getBlockLength() const { return blockLength; }
+
+  string toString() const;
+
+  int getId() const { return id; }
+  void setId(int id) { this->id = id; }
+  int getIndex() const { return index; }
+  void setIndex(int index) { this->index = index; }
+  int getBegin() const { return begin; }
+  void setBegin(int begin) { this->begin = begin; }
+  int getLength() const { return length; }
+  void setLength(int length) { this->length = length; }
+
+  enum ID {
+    CHOKE = 0,
+    UNCHOKE = 1,
+    INTERESTED = 2,
+    NOT_INTERESTED = 3,
+    HAVE = 4,
+    BITFIELD = 5,
+    REQUEST = 6,
+    PIECE = 7,
+    CANCEL = 8,
+    KEEP_ALIVE = 99};
+};
+
+#endif // _D_PEER_MESSAGE_H_

+ 231 - 0
src/PeerMessageUtil.cc

@@ -0,0 +1,231 @@
+/* <!-- 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 "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+#include "Util.h"
+#include <netinet/in.h>
+
+PeerMessage* PeerMessageUtil::createPeerMessage(const char* msg, int len) {
+  PeerMessage* peerMessage;
+  if(len == 0) {
+    // keep-alive
+    peerMessage = new PeerMessage();
+    peerMessage->setId(PeerMessage::KEEP_ALIVE);
+    return peerMessage;
+  }
+  int id = getId(msg);
+  switch(id) {
+  case PeerMessage::CHOKE:
+  case PeerMessage::UNCHOKE:
+  case PeerMessage::INTERESTED:
+  case PeerMessage::NOT_INTERESTED:
+    peerMessage = createBasicMessage(id, msg, len);
+    break;
+  case PeerMessage::HAVE:
+    peerMessage = createHaveMessage(id, msg, len);
+    break;
+  case PeerMessage::BITFIELD:
+    peerMessage = createBitfieldMessage(id, msg, len);
+    break;
+  case PeerMessage::REQUEST:
+  case PeerMessage::CANCEL:
+    peerMessage = createRequestCancelMessage(id, msg, len);
+    break;
+  case PeerMessage::PIECE:
+    peerMessage = createPieceMessage(id, msg, len);
+    break;
+  default:
+    throw new DlAbortEx("invalid message id. id = %d", id);
+  }
+  return peerMessage;
+}
+
+PeerMessage* PeerMessageUtil::createBasicMessage(int id, const char* msg, int len) {
+  if(len != 1) {
+    throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 1);
+  }
+  PeerMessage* peerMessage = new PeerMessage();
+  peerMessage->setId(id);
+  return peerMessage;
+}
+
+PeerMessage* PeerMessageUtil::createHaveMessage(int id, const char* msg, int len) {
+  if(len != 5) {
+    throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 5);
+  }
+  PeerMessage* peerMessage = new PeerMessage();
+  peerMessage->setId(id);
+  peerMessage->setIndex(getIntParam(msg, 1));
+  return peerMessage;
+}
+
+PeerMessage* PeerMessageUtil::createBitfieldMessage(int id, const char* msg, int len) {
+  if(len <= 1) {
+    throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be greater than %d", id, len, 1);
+  }
+  PeerMessage* peerMessage = new PeerMessage();
+  peerMessage->setId(id);
+  peerMessage->setBitfield((unsigned char*)msg+1, len-1);
+  return peerMessage;
+}
+
+PeerMessage* PeerMessageUtil::createRequestCancelMessage(int id, const char* msg, int len) {
+  if(len != 13) {
+    throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be %d", id, len, 13);
+  }
+  PeerMessage* peerMessage = new PeerMessage();
+  peerMessage->setId(id);
+  peerMessage->setIndex(getIntParam(msg, 1));
+  peerMessage->setBegin(getIntParam(msg, 5));
+  peerMessage->setLength(getIntParam(msg, 9));
+  return peerMessage;
+}
+
+PeerMessage* PeerMessageUtil::createPieceMessage(int id, const char* msg, int len) {
+  if(len <= 9) {
+    throw new DlAbortEx("invalid payload size for ID%d, size = %d. It should be greater than %d", id, len, 9);
+  }
+  PeerMessage* peerMessage = new PeerMessage();
+  peerMessage->setId(id);
+  peerMessage->setIndex(getIntParam(msg, 1));
+  peerMessage->setBegin(getIntParam(msg, 5));
+  peerMessage->setBlock(msg+9, len-9);
+  return peerMessage;
+}
+
+int PeerMessageUtil::getId(const char* msg) {
+  return (int)msg[0];
+}
+
+int PeerMessageUtil::getIntParam(const char* msg, int offset) {
+  int nParam;
+  memcpy(&nParam, msg+offset, 4);
+  return ntohl(nParam);
+}
+
+void PeerMessageUtil::checkIndex(const PeerMessage* message, int pieces) {
+  if(!(0 <= message->getIndex() && message->getIndex() < pieces)) {
+    throw new DlAbortEx("invalid index = %d", message->getIndex());
+  }
+}
+
+void PeerMessageUtil::checkBegin(const PeerMessage* message, int pieceLength) {
+  if(!(0 <= message->getBegin() && message->getBegin() < pieceLength)) {
+    throw new DlAbortEx("invalid begin = %d", message->getBegin());
+  }
+}
+
+void PeerMessageUtil::checkPieceOffset(const PeerMessage* message, int pieceLength, int pieces, long long int totalSize) {
+  if(!(0 <= message->getBegin() && 0 < message->getLength())) {
+    throw new DlAbortEx("invalid offset, begin = %d, length = %d", message->getBegin(), message->getLength());
+  }
+  int offset = message->getBegin()+message->getLength();
+  int currentPieceLength;
+  if(message->getIndex()+1 == pieces) {
+    currentPieceLength = pieceLength-(pieces*pieceLength-totalSize);
+  } else {
+    currentPieceLength = pieceLength;
+  }
+  if(!(0 < offset && offset <= currentPieceLength)) {
+    throw new DlAbortEx("invalid offset, begin = %d, length = %d", message->getBegin(), message->getLength());
+  }
+}
+
+void PeerMessageUtil::checkLength(const PeerMessage* message) {
+  if(message->getLength() > 128*1024) {
+    throw new DlAbortEx("too large length %d > 128KB", message->getLength());
+  }
+}
+
+void PeerMessageUtil::checkBitfield(const PeerMessage* message, int pieces) {
+  if(!(message->getBitfieldLength() == BITFIELD_LEN_FROM_PIECES(pieces))) {
+    throw new DlAbortEx("invalid bitfield length = %d", message->getBitfieldLength());
+  }
+  char lastbyte = message->getBitfield()[message->getBitfieldLength()-1];
+  for(int i = 0; i < 8-pieces%8 && pieces%8 != 0; i++) {
+    if(!(((lastbyte >> i) & 1) == 0)) {
+      throw new DlAbortEx("invalid bitfield");
+    }
+  }
+}
+
+void PeerMessageUtil::checkIntegrity(const PeerMessage* message, int pieceLength, int pieces, long long int totalSize) {
+  // 0 <= index < pieces
+  // 0 <= begin < pieceLength
+  // 0 < begin+length <= pieceLength
+  // len of bitfield == pieces/8+(pieces%8 ? 1 : 0)
+  // for(int i = 0; i < 8-pieces%8; i++) { ((lastbyteofbitfield >> i) & 1) == 0 }
+  switch(message->getId()) {
+  case PeerMessage::KEEP_ALIVE:
+  case PeerMessage::CHOKE:
+  case PeerMessage::UNCHOKE:
+  case PeerMessage::INTERESTED:
+  case PeerMessage::NOT_INTERESTED:
+    break;
+  case PeerMessage::HAVE:
+    checkIndex(message, pieces);
+    break;
+  case PeerMessage::BITFIELD:
+    checkBitfield(message, pieces);
+    break;
+  case PeerMessage::REQUEST:
+  case PeerMessage::CANCEL:
+    checkIndex(message, pieces);
+    checkBegin(message, pieceLength);
+    checkLength(message);
+    checkPieceOffset(message, pieceLength, pieces, totalSize);
+    break;
+  case PeerMessage::PIECE:
+    checkIndex(message, pieces);
+    checkBegin(message, pieceLength);
+    break;
+  default:
+    throw new DlAbortEx("invalid message id. id = %d", message->getId());
+  }
+}
+
+HandshakeMessage* PeerMessageUtil::createHandshakeMessage(const char* msg) {
+  HandshakeMessage* message = new HandshakeMessage();
+  message->pstrlen = msg[0];
+  char pstr[20];
+  memcpy(pstr, &msg[1], sizeof(pstr)-1);
+  pstr[sizeof(pstr)-1] = '\0';
+  message->pstr = pstr;
+  memcpy(message->infoHash, &msg[28], 20);
+  memcpy(message->peerId, &msg[48], 20);
+  return message;
+}
+
+void PeerMessageUtil::checkHandshake(const HandshakeMessage* message, const unsigned char* infoHash) {
+  if(message->pstrlen != 19) {
+    throw new DlAbortEx("invalid handshake pstrlen = %d", (int)message->pstrlen);
+  }
+  if(message->pstr != PSTR) {
+    throw new DlAbortEx("invalid handshake pstr");
+  }
+  string myInfoHash = Util::toHex(infoHash, 20);
+  string peerInfoHash = Util::toHex(message->infoHash, 20);
+  if(myInfoHash != peerInfoHash) {
+    throw new DlAbortEx("invalid handshake info hash: expected:%s, actual:%s",
+			myInfoHash.c_str(), peerInfoHash.c_str());
+  }
+}

+ 51 - 0
src/PeerMessageUtil.h

@@ -0,0 +1,51 @@
+/* <!-- 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_MESSAGE_UTIL_H_
+#define _D_PEER_MESSAGE_UTIL_H_
+
+#include "PeerConnection.h"
+
+class PeerMessageUtil {
+private:
+  PeerMessageUtil() {}
+
+  static PeerMessage* createBasicMessage(int id, const char* msg, int len);
+  static PeerMessage* createHaveMessage(int id, const char* msg, int len);
+  static PeerMessage* createBitfieldMessage(int id, const char* msg, int len);
+  static PeerMessage* createRequestCancelMessage(int id, const char* msg, int len);
+  static PeerMessage* createPieceMessage(int id, const char* msg, int len);
+  static int getId(const char* msg);
+  static int getIntParam(const char* msg, int offset);
+
+  static void checkIndex(const PeerMessage* message, int pieces);
+  static void checkBegin(const PeerMessage* message, int pieceLength);
+  static void checkLength(const PeerMessage* message);
+  static void checkPieceOffset(const PeerMessage* message, int pieceLength, int pieces, long long int totalSize);
+  static void checkBitfield(const PeerMessage* message, int pieces);
+public:
+  static PeerMessage* createPeerMessage(const char* msg, int len);
+  static void checkIntegrity(const PeerMessage* message, int pieceLength, int pieces, long long int totalSize);
+  static HandshakeMessage* createHandshakeMessage(const char* msg);
+  static void checkHandshake(const HandshakeMessage* message, const unsigned char* infoHash);
+};
+
+#endif // _D_PEER_MESSAGE_UTIL_H_

+ 115 - 0
src/PendingMessage.cc

@@ -0,0 +1,115 @@
+/* <!-- 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 "PendingMessage.h"
+
+bool PendingMessage::processMessage() {
+  bool retval = true;
+  switch(peerMessageId) {
+  case PeerMessage::HAVE:
+    peerConnection->sendHave(index);
+    break;
+  case PeerMessage::BITFIELD:
+    peerConnection->sendBitfield();
+    break;
+  case PeerMessage::UNCHOKE:
+    if(peerConnection->getPeer()->amChocking) {
+      peerConnection->sendUnchoke();
+      peerConnection->getPeer()->amChocking = false;
+    }
+    break;
+  case PeerMessage::CHOKE:
+    if(!peerConnection->getPeer()->amChocking) {
+      peerConnection->sendChoke();
+      peerConnection->getPeer()->amChocking = true;
+    }
+    break;
+  case PeerMessage::NOT_INTERESTED:
+    if(peerConnection->getPeer()->amInterested) {
+      peerConnection->sendNotInterested();
+      peerConnection->getPeer()->amInterested = false;
+    }
+    break;
+  case PeerMessage::INTERESTED:
+    if(!peerConnection->getPeer()->amInterested) {
+      peerConnection->sendInterested();
+      peerConnection->getPeer()->amInterested = true;
+    }
+    break;
+  case PeerMessage::PIECE:
+    if(!peerConnection->getPeer()->amChocking) {
+      if(!inProgress) {
+	peerConnection->sendPieceHeader(index, begin, length);
+	peerConnection->getPeer()->addPeerDownload(length);
+      }
+      int writtenLength = peerConnection->sendPieceData(pieceDataOffset, leftPieceDataLength);
+      if(writtenLength != leftPieceDataLength) {
+	inProgress = true;
+	leftPieceDataLength -= writtenLength;
+	pieceDataOffset += writtenLength;
+	retval = false;
+      }
+    }
+    break;
+  case PeerMessage::REQUEST:
+    peerConnection->sendRequest(index, begin, length);
+    break;
+  case PeerMessage::CANCEL:
+    peerConnection->sendCancel(index, begin, length);
+    break;
+  default:
+    break;
+  }
+  return retval;
+}
+
+PendingMessage PendingMessage::createRequestMessage(int index, int begin, int length, PeerConnection* peerConnection) {
+  PendingMessage pendingMessage(PeerMessage::REQUEST, peerConnection);
+  pendingMessage.setIndex(index);
+  pendingMessage.setBegin(begin);
+  pendingMessage.setLength(length);
+  return pendingMessage;
+}
+
+PendingMessage PendingMessage::createCancelMessage(int index, int begin, int length, PeerConnection* peerConnection) {
+  PendingMessage pendingMessage(PeerMessage::CANCEL, peerConnection);
+  pendingMessage.setIndex(index);
+  pendingMessage.setBegin(begin);
+  pendingMessage.setLength(length);
+  return pendingMessage;
+}
+
+PendingMessage PendingMessage::createPieceMessage(int index, int begin, int length, int pieceLength, PeerConnection* peerConnection) {
+  PendingMessage pendingMessage(PeerMessage::PIECE, peerConnection);
+  pendingMessage.setIndex(index);
+  pendingMessage.setBegin(begin);
+  pendingMessage.setLength(length);
+  pendingMessage.setPieceDataOffset(((long long int)index)*pieceLength+begin);
+  pendingMessage.setLeftPieceDataLength(length);
+  return pendingMessage;
+}
+
+PendingMessage PendingMessage::createHaveMessage(int index, PeerConnection* peerConnection) {
+  PendingMessage pendingMessage(PeerMessage::HAVE, peerConnection);
+  pendingMessage.setIndex(index);
+  return pendingMessage;
+}
+

+ 71 - 0
src/PendingMessage.h

@@ -0,0 +1,71 @@
+/* <!-- 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_PENDING_MESSAGE_H_
+#define _D_PENDING_MESSAGE_H_
+
+#include "common.h"
+#include "PeerConnection.h"
+#include <vector>
+
+class PendingMessage {
+private:
+  int peerMessageId;
+  int index;
+  int begin;
+  int length;
+  long long int pieceDataOffset;
+  int leftPieceDataLength;
+  bool inProgress;
+  PeerConnection* peerConnection;
+public:
+  PendingMessage(int peerMessageId, PeerConnection* peerConnection):peerMessageId(peerMessageId), inProgress(false), peerConnection(peerConnection) {}
+  ~PendingMessage() {}
+
+  void setPeerMessageId(int peerMessageId) { this->peerMessageId = peerMessageId; }
+  int getPeerMessageId() const { return peerMessageId; }
+
+  void setPieceDataOffset(long long int offset) { this->pieceDataOffset = offset; }
+  long long int getPieceDataOffset() const { return pieceDataOffset; }
+
+  void setLeftPieceDataLength(int length) { this->leftPieceDataLength = length; }
+  int getLeftPieceDataLength() const { return leftPieceDataLength; }
+
+  void setInProgress(bool inprogress) { this->inProgress = inProgress; }
+  bool isInProgress() const { return inProgress; }
+
+  void setIndex(int index) { this->index = index; }
+  int getIndex() const { return index; }
+  void setBegin(int begin) { this->begin = begin; }
+  int getBegin() const { return begin; }
+  void setLength(int length) { this->length = length; }
+  int getLength() const { return length; }
+  bool processMessage();
+
+  static PendingMessage createRequestMessage(int index, int begin, int length, PeerConnection* peerConnection);
+  static PendingMessage createCancelMessage(int index, int begin, int length, PeerConnection* peerConnection);
+  static PendingMessage createPieceMessage(int index, int begin, int length, int pieceLength, PeerConnection* peerConnection);
+  static PendingMessage createHaveMessage(int index, PeerConnection* peerConnectioin);
+};
+
+typedef vector<PendingMessage> PendingMessages;
+
+#endif // _D_PENDING_MESSAGE_H_

+ 84 - 0
src/Piece.cc

@@ -0,0 +1,84 @@
+/* <!-- 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 "Piece.h"
+
+Piece Piece::nullPiece;
+
+Piece::Piece(const Piece& piece) {
+  index = piece.index;
+  length = piece.length;
+  if(piece.bitfield == NULL) {
+    bitfield = NULL;
+  } else {
+    bitfield = new BitfieldMan(*piece.bitfield);
+  }
+}
+
+Piece& Piece::operator=(const Piece& piece) {
+  if(this != &piece) {
+    index = piece.index;
+    length = piece.length;
+    if(bitfield != NULL) {
+      delete bitfield;
+    }
+    if(piece.bitfield == NULL) {
+      bitfield = NULL;
+    } else {
+      bitfield = new BitfieldMan(*piece.bitfield);
+    }
+  }
+  return *this;
+}
+
+void Piece::completeBlock(int blockIndex) {
+  bitfield->setBit(blockIndex);
+  bitfield->unsetUseBit(blockIndex);
+}
+
+void Piece::clearAllBlock() {
+  bitfield->clearAllBit();
+}
+
+void Piece::setAllBlock() {
+  bitfield->setAllBit();
+}
+
+bool Piece::pieceComplete() const {
+  return bitfield->isAllBitSet();
+}
+
+void Piece::cancelBlock(int blockIndex) {
+  bitfield->unsetUseBit(blockIndex);
+}
+
+int Piece::getMissingUnusedBlockIndex() const {
+  int blockIndex = bitfield->getFirstMissingUnusedIndex();
+  if(blockIndex == -1) {
+    return blockIndex;
+  }
+  bitfield->setUseBit(blockIndex);
+  return blockIndex;
+}
+
+vector<int> Piece::getAllMissingBlockIndexes() const {
+  return bitfield->getAllMissingIndexes();
+}

+ 81 - 0
src/Piece.h

@@ -0,0 +1,81 @@
+/* <!-- 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_PIECE_H_
+#define _D_PIECE_H_
+
+#include "BitfieldMan.h"
+#include "common.h"
+
+#define BLOCK_LENGTH 16*1024
+
+class Piece {
+private:
+  int index;
+  int length;
+  BitfieldMan* bitfield;
+public:
+  Piece():index(0), length(0), bitfield(NULL) {}
+  Piece(int index, int length):index(index), length(length) {
+    bitfield = new BitfieldMan(BLOCK_LENGTH, length);
+  }
+  Piece(const Piece& piece);
+  ~Piece() {
+    delete bitfield;
+  }
+
+  Piece& operator=(const Piece& piece);
+
+  int getMissingUnusedBlockIndex() const;
+  vector<int> getAllMissingBlockIndexes() const;
+  void completeBlock(int blockIndex);
+  void cancelBlock(int blockIndex);
+  int countCompleteBlock() const {
+    return bitfield->countBlock()-bitfield->countMissingBlock();
+  }
+  bool hasBlock(int blockIndex) const {
+    return bitfield->isBitSet(blockIndex);
+  }
+
+  bool pieceComplete() const;
+  int countBlock() const { return bitfield->countBlock(); }
+  int getBlockLength(int index) const {
+    return bitfield->getBlockLength(index);
+  }
+  int getBlockLength() const { return bitfield->getBlockLength(); }
+  int getIndex() const { return index; }
+  void setIndex(int index) { this->index = index; }
+  int getLength() const { return length; }
+  void setLength(int index) { this->length = length; }
+
+  const unsigned char* getBitfield() const { return bitfield->getBitfield(); }
+  void setBitfield(const unsigned char* bitfield, int len);
+
+  void clearAllBlock();
+  void setAllBlock();
+
+  static Piece nullPiece;
+  static bool isNull(const Piece& piece) {
+    return piece.index == 0 && piece.length == 0;
+  }
+};
+
+#endif // _D_PIECE_H_

+ 25 - 26
src/PreAllocationDiskWriter.cc

@@ -20,15 +20,16 @@
  */
 /* copyright --> */
 #include "PreAllocationDiskWriter.h"
+#include "DlAbortEx.h"
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
-#include "DlAbortEx.h"
 
-PreAllocationDiskWriter::PreAllocationDiskWriter(unsigned long int size):AbstractDiskWriter(),size(size) {}
+PreAllocationDiskWriter::PreAllocationDiskWriter(long long int totalLength)
+  :AbstractDiskWriter(),totalLength(totalLength) {}
 
 PreAllocationDiskWriter::~PreAllocationDiskWriter() {}
 
@@ -36,34 +37,32 @@ void PreAllocationDiskWriter::initAndOpenFile(string filename) {
   createFile(filename, O_DIRECT);
   
   int pageSize = getpagesize();
+  int bufSize = pageSize*4;
   char* buf;
-  int size = pageSize*4;
-  int rt = posix_memalign((void**)&buf, pageSize, size);
+  int rt = posix_memalign((void**)&buf, pageSize, bufSize);
   if(rt != 0) {
     throw new DlAbortEx(strerror(rt));
   }
-  memset(buf, 0, size);
-  int x = size/4096;
-  int r = size%4096;
-  for(int i = 0; i < x; i++) {
-    if(write(fd, buf, size) < 0) {
-      free(buf);
-      throw new DlAbortEx(strerror(errno));
+  try {
+    memset(buf, 0, bufSize);
+    long long int x = totalLength/bufSize;
+    int r = totalLength%bufSize;
+    for(long long int i = 0; i < x; i++) {
+      if(write(fd, buf, bufSize) < 0) {
+	throw new DlAbortEx(strerror(errno));
+      }
     }
-  }
-  free(buf);
-  closeFile();
-  openExistingFile(filename);
-  char cbuf[4096];
-  memset(cbuf, 0, sizeof(cbuf));
-  if(write(fd, cbuf, r) < 0) {
-    throw new DlAbortEx(strerror(errno));
+    closeFile();
+    openExistingFile(filename);
+    if(r > 0) {
+      seek(totalLength-r);
+      if(write(fd, buf, r) < 0) {
+	throw new DlAbortEx(strerror(errno));
+      }
+    }
+    free(buf);
+  } catch(Exception* ex) {
+    free(buf);
+    throw;
   }
 }
-
-void PreAllocationDiskWriter::writeData(const char* data, int len, unsigned long int offset) {
-  int x = lseek(fd, offset, SEEK_SET);
-  // TODO check the return value of write
-  writeDataInternal(data, len);
-}
-

+ 2 - 4
src/PreAllocationDiskWriter.h

@@ -26,14 +26,12 @@
 
 class PreAllocationDiskWriter:public AbstractDiskWriter {
 private:
-  unsigned long int size;
+  long long int totalLength;
 public:
-  PreAllocationDiskWriter(unsigned long int size);
+  PreAllocationDiskWriter(long long int totalLength);
   ~PreAllocationDiskWriter();
 
   void initAndOpenFile(string filename);
-
-  void writeData(const char* data, int len, unsigned long int position);
 };
 
 #endif // _D_PRE_ALLOCATION_DISK_WRITER_H_

+ 1 - 1
src/Request.cc

@@ -22,7 +22,7 @@
 #include "Request.h"
 #include "Util.h"
 
-Request::Request():port(0), tryCount(0) {
+Request::Request():port(0), tryCount(0), isTorrent(false) {
   defaultPorts["http"] = 80;
 #ifdef HAVE_LIBSSL
   // for SSL

+ 13 - 0
src/Request.h

@@ -56,10 +56,12 @@ private:
   string file;
   map<string, int> defaultPorts;
   int tryCount;
+  int trackerEvent;
   bool parseUrl(string url);
 public:
   Segment seg;
   CookieBox* cookieBox;
+  bool isTorrent;
 public:
   Request();
   virtual ~Request();
@@ -87,6 +89,17 @@ public:
   int getPort() const { return port; }
   string getDir() const { return dir; }
   string getFile() const { return file;}
+
+  void setTrackerEvent(int event) { trackerEvent = event; }
+  int getTrackerEvent() const { return trackerEvent; }
+
+  enum TRACKER_EVENT {
+    AUTO,
+    STARTED,
+    STOPPED,
+    COMPLETED
+  };
+
 };
 
 #endif // _D_REQUEST_H_

+ 70 - 0
src/RequestSlot.cc

@@ -0,0 +1,70 @@
+/* <!-- 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 "RequestSlot.h"
+#include "Util.h"
+
+RequestSlot::RequestSlot(int index, int begin, int length, int blockIndex)
+  :index(index), begin(begin), length(length), blockIndex(blockIndex) {
+  setDispatchedTime();
+}
+
+RequestSlot::RequestSlot(const RequestSlot& requestSlot) {
+  copy(requestSlot);
+}
+
+RequestSlot& RequestSlot::operator=(const RequestSlot& requestSlot) {
+  if(this != &requestSlot) {
+    copy(requestSlot);
+  }
+  return *this;
+}
+
+void RequestSlot::copy(const RequestSlot& requestSlot) {
+  index = requestSlot.index;
+  begin = requestSlot.begin;
+  length = requestSlot.length;
+  blockIndex = requestSlot.blockIndex;
+  dispatchedTime = requestSlot.dispatchedTime;
+}
+
+RequestSlot RequestSlot::nullSlot(0, 0, 0, 0);
+
+void RequestSlot::setDispatchedTime() {
+  gettimeofday(&dispatchedTime, NULL);
+}
+
+bool RequestSlot::isTimeout(int timeoutSec) const {
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  return Util::difftv(now, dispatchedTime) > timeoutSec*1000000;
+}
+
+bool RequestSlot::isNull(const RequestSlot& requestSlot) {
+  return requestSlot.index == 0 && requestSlot.begin == 0&&
+    requestSlot.length == 0;
+}
+
+bool RequestSlot::operator==(const RequestSlot& requestSlot) const {
+  return index == requestSlot.index &&
+    begin == requestSlot.begin &&
+    length == requestSlot.length;
+}

+ 63 - 0
src/RequestSlot.h

@@ -0,0 +1,63 @@
+/* <!-- 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_REQUEST_SLOT_H_
+#define _D_REQUEST_SLOT_H_
+
+#include "common.h"
+#include <sys/time.h>
+
+class RequestSlot {
+private:
+  struct timeval dispatchedTime;
+  int index;
+  int begin;
+  int length;
+  int blockIndex;
+  void copy(const RequestSlot& requestSlot);
+public:
+  RequestSlot(int index, int begin, int legnth, int blockIndex);
+  RequestSlot(const RequestSlot& requestSlot);
+  ~RequestSlot() {}
+
+  RequestSlot& operator=(const RequestSlot& requestSlot);
+
+  void setDispatchedTime();
+
+  bool isTimeout(int timeoutSec) const;
+
+  bool operator==(const RequestSlot& requestSlot) const;
+
+  int getIndex() const { return index; }
+  void setIndex(int index) { this->index = index; }
+  int getBegin() const { return begin; }
+  void setBegin(int begin) { this->begin = begin; }
+  int getLength() const { return length; }
+  void setLength(int length) { this->length = length; }
+  int getBlockIndex() const { return blockIndex; }
+  void setBlockIndex(int blockIndex) { this->blockIndex = blockIndex; }
+
+  static RequestSlot nullSlot;
+
+  static bool isNull(const RequestSlot& requestSlot);
+};
+
+#endif // _D_REQUEST_SLOT_H_

+ 98 - 0
src/RequestSlotMan.cc

@@ -0,0 +1,98 @@
+/* <!-- 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 "RequestSlotMan.h"
+
+void RequestSlotMan::addRequestSlot(const RequestSlot& requestSlot) {
+  requestSlots.push_back(requestSlot);
+}
+
+void RequestSlotMan::deleteRequestSlot(const RequestSlot& requestSlot) {
+  for(RequestSlots::iterator itr = requestSlots.begin();
+      itr != requestSlots.end(); itr++) {
+    if(*itr == requestSlot) {
+      requestSlots.erase(itr);
+      break;
+    }
+  }
+}
+
+void RequestSlotMan::deleteAllRequestSlot(Piece& piece) {
+  if(!Piece::isNull(piece)) {
+    for(RequestSlots::const_iterator itr = requestSlots.begin();
+	itr != requestSlots.end(); itr++) {
+      if(itr->getIndex() == piece.getIndex()) {
+	piece.cancelBlock(itr->getBlockIndex());
+      }
+    }
+    torrentMan->updatePiece(piece);
+  }
+  requestSlots.clear();
+}
+
+void RequestSlotMan::deleteTimedoutRequestSlot(Piece& piece) {
+  for(RequestSlots::iterator itr = requestSlots.begin();
+      itr != requestSlots.end();) {
+    if(itr->isTimeout(timeout)) {
+      logger->debug("CUID#%d - deleting requestslot blockIndex %d because of time out", cuid,
+		    itr->getBlockIndex());
+      if(!Piece::isNull(piece)) {
+	piece.cancelBlock(itr->getBlockIndex());
+      }
+      itr = requestSlots.erase(itr);
+    } else {
+      itr++;
+    }
+  }
+  torrentMan->updatePiece(piece);
+}
+
+void RequestSlotMan::deleteCompletedRequestSlot(const Piece& piece) {
+  for(RequestSlots::iterator itr = requestSlots.begin();
+      itr != requestSlots.end();) {
+    if(Piece::isNull(piece) || piece.hasBlock(itr->getBlockIndex())) {
+      logger->debug("CUID#%d - deleting requestslot blockIndex %d because the block is already acquired.", cuid,
+		    itr->getBlockIndex());
+      PendingMessage pendingMessage =
+	PendingMessage::createCancelMessage(itr->getIndex(),
+					    itr->getBegin(),
+					    itr->getLength(),
+					    peerConnection);
+      pendingMessages->push_back(pendingMessage);
+      itr = requestSlots.erase(itr);
+    } else {
+      itr++;
+    }
+  }
+}
+
+RequestSlot RequestSlotMan::getCorrespoindingRequestSlot(const PeerMessage* pieceMessage) const {
+  for(RequestSlots::const_iterator itr = requestSlots.begin();
+      itr != requestSlots.end(); itr++) {
+    const RequestSlot& slot = *itr;
+    if(slot.getIndex() == pieceMessage->getIndex() &&
+       slot.getBegin() == pieceMessage->getBegin() &&
+       slot.getLength() == pieceMessage->getBlockLength()) {
+      return slot;
+    }
+  }
+  return RequestSlot::nullSlot;
+}

+ 72 - 0
src/RequestSlotMan.h

@@ -0,0 +1,72 @@
+/* <!-- 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_REQUEST_SLOT_MAN_H_
+#define _D_REQUEST_SLOT_MAN_H_
+
+#include "RequestSlot.h"
+#include "common.h"
+#include "PeerMessage.h"
+#include "Logger.h"
+#include "PeerConnection.h"
+#include "PendingMessage.h"
+#include "TorrentMan.h"
+#include <vector>
+
+#define DEFAULT_TIME_OUT 120
+
+typedef vector<RequestSlot> RequestSlots;
+
+class RequestSlotMan {
+private:
+  int cuid;
+  RequestSlots requestSlots;
+  int timeout;
+  PendingMessages* pendingMessages;
+  PeerConnection* peerConnection;
+  TorrentMan* torrentMan;
+  const Logger* logger;
+public:
+  RequestSlotMan(int cuid,
+		 PendingMessages* pendingMessages,
+		 PeerConnection* peerConnection,
+		 TorrentMan* torrentMan,
+		 const Logger* logger):cuid(cuid), timeout(DEFAULT_TIME_OUT),
+  pendingMessages(pendingMessages), peerConnection(peerConnection),
+  torrentMan(torrentMan), logger(logger) {}
+  ~RequestSlotMan() {}
+
+  void addRequestSlot(const RequestSlot& requestSlot);
+  void deleteRequestSlot(const RequestSlot& requestSlot);
+  void deleteAllRequestSlot(Piece& piece);
+
+  void deleteTimedoutRequestSlot(Piece& piece);
+  void deleteCompletedRequestSlot(const Piece& piece);
+
+  RequestSlot getCorrespoindingRequestSlot(const PeerMessage* pieceMessage) const;
+  bool isEmpty() { return requestSlots.empty(); }
+  int countRequestSlot() const { return requestSlots.size(); }
+
+  void setTimeout(int timeout) { this->timeout = timeout; }
+  int getTimeout() const { return timeout; }
+};
+
+#endif // _D_REQUEST_SLOT_MAN_H_

+ 82 - 0
src/ShaVisitor.cc

@@ -0,0 +1,82 @@
+/* <!-- 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 "ShaVisitor.h"
+#include "Util.h"
+
+ShaVisitor::ShaVisitor() {
+  EVP_MD_CTX_init(&ctx);
+  EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
+}
+
+ShaVisitor::~ShaVisitor() {
+  EVP_MD_CTX_cleanup(&ctx);
+}
+
+void ShaVisitor::visit(const Data* d) {
+  if(d->isNumber()) {
+    EVP_DigestUpdate(&ctx, "i", 1);
+  } else {
+    string lenStr = Util::llitos(d->getLen());
+    EVP_DigestUpdate(&ctx, lenStr.c_str(), lenStr.size());
+    EVP_DigestUpdate(&ctx, ":", 1);
+  }
+  EVP_DigestUpdate(&ctx, d->getData(), d->getLen());
+  if(d->isNumber()) {
+    EVP_DigestUpdate(&ctx, "e", 1);
+  }
+}
+
+void ShaVisitor::visit(const Dictionary* d) {
+  EVP_DigestUpdate(&ctx, "d", 1);
+  const vector<string>& v = d->getOrder();
+  for(vector<string>::const_iterator itr = v.begin(); itr != v.end(); itr++) {
+    string lenStr = Util::llitos(itr->size());
+    EVP_DigestUpdate(&ctx, lenStr.c_str(), lenStr.size());
+    EVP_DigestUpdate(&ctx, ":", 1);
+    EVP_DigestUpdate(&ctx, itr->c_str(), itr->size());
+    const MetaEntry* e = d->get(*itr);
+    this->visit(e);
+  }
+  EVP_DigestUpdate(&ctx, "e", 1);
+}
+
+void ShaVisitor::visit(const List* l) {
+  EVP_DigestUpdate(&ctx, "l", 1);
+  for(MetaList::const_iterator itr = l->getList().begin(); itr != l->getList().end(); itr++) {
+    this->visit(*itr);
+  }
+  EVP_DigestUpdate(&ctx, "e", 1);
+}
+
+void ShaVisitor::visit(const MetaEntry* e) {
+  if(dynamic_cast<const Data*>(e) != NULL) {
+    visit((const Data*)e);
+  } else if(dynamic_cast<const Dictionary*>(e) != NULL) {
+    visit((const Dictionary*)e);
+  } else if(dynamic_cast<const List*>(e) != NULL) {
+    visit((const List*)e);
+  }
+}
+
+void ShaVisitor::getHash(unsigned char* hashValue, int& len) {
+  EVP_DigestFinal_ex(&ctx, hashValue, (unsigned int*)&len);
+}

+ 47 - 0
src/ShaVisitor.h

@@ -0,0 +1,47 @@
+/* <!-- 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_SHA_VISITOR_H_
+#define _D_SHA_VISITOR_H_
+
+#include "MetaEntryVisitor.h"
+#include "Data.h"
+#include "Dictionary.h"
+#include "List.h"
+#include "common.h"
+#include <openssl/evp.h>
+
+class ShaVisitor : public MetaEntryVisitor {
+private:
+  EVP_MD_CTX ctx;
+public:
+  ShaVisitor();
+  ~ShaVisitor();
+
+  void visit(const Data* d);
+  void visit(const Dictionary* d);
+  void visit(const List* l);
+  void visit(const MetaEntry* e);
+
+  void getHash(unsigned char* md, int& s);
+};
+
+#endif // _D_SHA_VISITOR_H_

+ 6 - 2
src/Socket.cc

@@ -53,14 +53,18 @@ Socket& Socket::operator=(const Socket& s) {
   return *this;
 }
 
-void Socket::beginListen() const {
-  core->beginListen();
+void Socket::beginListen(int port) const {
+  core->beginListen(port);
 }
 
 void Socket::getAddrInfo(pair<string, int>& addrinfo) const {
   core->getAddrInfo(addrinfo);
 }
 
+void Socket::getPeerInfo(pair<string, int>& peerinfo) const {
+  core->getPeerInfo(peerinfo);
+}
+
 Socket* Socket::acceptConnection() const {
   return new Socket(core->acceptConnection());
 }

+ 6 - 1
src/Socket.h

@@ -51,13 +51,18 @@ public:
   /**
    * @see SocketCore::beginListen()
    */
-  void beginListen() const;
+  void beginListen(int port = 0) const;
   
   /**
    * @see SocketCore::getAddrInfo()
    */
   void getAddrInfo(pair<string, int>& addrinfo) const;
 
+  /**
+   * @see SocketCore::getPeerInfo();
+   */
+  void getPeerInfo(pair<string, int>& peerinfo) const;
+
   /**
    * @see SocketCore::acceptConnection()
    */

+ 17 - 9
src/SocketCore.cc

@@ -56,7 +56,7 @@ SocketCore::~SocketCore() {
   closeConnection();
 }
 
-void SocketCore::beginListen() {
+void SocketCore::beginListen(int port) {
   closeConnection();
   //sockfd = socket(AF_UNSPEC, SOCK_STREAM, PF_UNSPEC);
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
@@ -74,7 +74,7 @@ void SocketCore::beginListen() {
   memset((char*)&sockaddr, 0, sizeof(sockaddr));
   sockaddr.sin_family = AF_INET;
   sockaddr.sin_addr.s_addr = INADDR_ANY;
-  sockaddr.sin_port = htons(0);
+  sockaddr.sin_port = htons(port);
   
   if(bind(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {
     throw new DlAbortEx(strerror(errno));
@@ -93,6 +93,7 @@ SocketCore* SocketCore::acceptConnection() const {
   if((fd = accept(sockfd, (struct sockaddr*)&sockaddr, &len)) == -1) {
     throw new DlAbortEx(strerror(errno));
   }
+
   SocketCore* s = new SocketCore(fd);
   return s;
 }
@@ -108,6 +109,17 @@ void SocketCore::getAddrInfo(pair<string, int>& addrinfo) const {
   addrinfo.second = ntohs(listenaddr.sin_port);
 }
 
+void SocketCore::getPeerInfo(pair<string, int>& peerinfo) const {
+  struct sockaddr_in peerin;
+  memset(&peerin, 0, sizeof(peerin));
+  int len = sizeof(peerin);
+  if(getpeername(sockfd, (struct sockaddr*)&peerin, (socklen_t*)&len) < 0) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  peerinfo.first = inet_ntoa(peerin.sin_addr);
+  peerinfo.second = ntohs(peerin.sin_port);
+}
+
 void SocketCore::establishConnection(string host, int port) {
   closeConnection();
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
@@ -134,7 +146,6 @@ void SocketCore::establishConnection(string host, int port) {
     ai.ai_family = PF_INET;
     ai.ai_socktype = SOCK_STREAM;
     ai.ai_protocol = 0; 
-    ai.ai_addr = (struct sockaddr*)&sockaddr;
     struct addrinfo* res;
     int ec;
     if((ec = getaddrinfo(host.c_str(), NULL, &ai, &res)) != 0) {
@@ -227,8 +238,7 @@ bool SocketCore::isReadable(int timeout) const {
 }
 
 void SocketCore::writeData(const char* data, int len, int timeout) const {
-  if(!isWritable(timeout) ||
-     !secure && send(sockfd, data, (size_t)len, 0) != len
+  if(!secure && send(sockfd, data, (size_t)len, 0) != len
 #ifdef HAVE_LIBSSL
      // for SSL
      // TODO handling len == 0 case required
@@ -240,8 +250,7 @@ void SocketCore::writeData(const char* data, int len, int timeout) const {
 }
 
 void SocketCore::readData(char* data, int& len, int timeout) const {
-  if(!isReadable(timeout) ||
-     !secure && (len = recv(sockfd, data, (size_t)len, 0)) < 0
+  if(!secure && (len = recv(sockfd, data, (size_t)len, 0)) < 0
 #ifdef HAVE_LIBSSL
      // for SSL
      // TODO handling len == 0 case required
@@ -253,8 +262,7 @@ void SocketCore::readData(char* data, int& len, int timeout) const {
 }
 
 void SocketCore::peekData(char* data, int& len, int timeout) const {
-  if(!isReadable(timeout) ||
-     !secure && (len = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0
+  if(!secure && (len = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0
 #ifdef HAVE_LIBSSL
      // for SSL
      // TODO handling len == 0 case required

+ 12 - 4
src/SocketCore.h

@@ -54,14 +54,22 @@ public:
 
   /**
    * Creates a socket and listens form connection on it.
+   * @param port port to listen. If 0 is specified, os automaticaly
+   * choose avaiable port.
    */
-  void beginListen();
+  void beginListen(int port = 0);
 
   /**
    * Stores host address and port of this socket to addrinfo.
    * @param addrinfo placeholder to store host address and port.
    */
   void getAddrInfo(pair<string, int>& addrinfo) const;
+  
+  /**
+   * Stores peer's address and port to peerinfo.
+   * @param peerinfo placeholder to store peer's address and port.
+   */
+  void getPeerInfo(pair<string, int>& peerinfo) const;
 
   /**
    * Accepts incoming connection on this socket.
@@ -118,7 +126,7 @@ public:
    * @param timeout the amount of time elapsed before isWritable()
    * are timed out.
    */
-  void writeData(const char* data, int len, int timeout = 5) const;
+  void writeData(const char* data, int len, int timeout = 0) const;
 
   /**
    * Reads up to len bytes from this socket.
@@ -134,7 +142,7 @@ public:
    * @param timeout the amount of time elapsed before isReadable() are timed
    * out.
    */
-  void readData(char* data, int& len, int timeout = 5) const;
+  void readData(char* data, int& len, int timeout = 0) const;
 
   /**
    * Reads up to len bytes from this socket, but bytes are not removed from
@@ -147,7 +155,7 @@ public:
    * @param timeout the amount of time elapsed before isReadable() are timed
    * out.
    */
-  void peekData(char* data, int& len, int timeout = 5) const;
+  void peekData(char* data, int& len, int timeout = 0) const;
   
   /**
    * Makes this socket secure.

+ 37 - 0
src/TorrentAutoSaveCommand.cc

@@ -0,0 +1,37 @@
+/* <!-- 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 "TorrentAutoSaveCommand.h"
+#include "SleepCommand.h"
+
+TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), e(e), interval(interval) {}
+
+TorrentAutoSaveCommand::~TorrentAutoSaveCommand() {}
+
+bool TorrentAutoSaveCommand::execute() {
+  if(e->torrentMan->downloadComplete()) {
+    return true;
+  }
+  e->torrentMan->save();
+  SleepCommand* sleepCommand = new SleepCommand(cuid, e, this, interval);
+  e->commands.push(sleepCommand);
+  return false;
+}

+ 40 - 0
src/TorrentAutoSaveCommand.h

@@ -0,0 +1,40 @@
+/* <!-- 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_TORRENT_AUTO_SAVE_COMMAND_H_
+#define _D_TORRENT_AUTO_SAVE_COMMAND_H_
+
+#include "Command.h"
+#include "TorrentDownloadEngine.h"
+
+class TorrentAutoSaveCommand : public Command {
+private:
+  int cuid;
+  TorrentDownloadEngine* e;
+  int interval;
+public:
+  TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval);
+  ~TorrentAutoSaveCommand();
+
+  bool execute();
+};
+
+#endif // _D_TORRENT_AUTO_SAVE_COMMAND_H_

+ 132 - 0
src/TorrentConsoleDownloadEngine.cc

@@ -0,0 +1,132 @@
+/* <!-- 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 "TorrentConsoleDownloadEngine.h"
+#include "Util.h"
+
+TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {}
+
+TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {}
+
+void TorrentConsoleDownloadEngine::printStatistics() {
+  printf("\r                                                                            ");
+  printf("\r");
+  printf("%s/%sB %d%% DW:%.2f UP:%.2f(%s) %dpeers",
+	 Util::llitos(torrentMan->getDownloadedSize(), true).c_str(),
+	 Util::llitos(torrentMan->totalSize, true).c_str(),
+	 (torrentMan->totalSize == 0 ?
+	  0 : (int)((torrentMan->getDownloadedSize()*100)/torrentMan->totalSize)),
+	 downloadSpeed/1000.0,
+	 uploadSpeed/1000.0,
+	 Util::llitos(torrentMan->getUploadedSize(), true).c_str(),
+	 torrentMan->connections);
+  fflush(stdout);	 
+}
+
+void TorrentConsoleDownloadEngine::initStatistics() {
+  /*
+  gettimeofday(&cp, NULL);
+  */
+  downloadSpeed = 0;
+  uploadSpeed = 0;
+  /*
+  sessionDownloadSize = 0;
+  sessionUploadSize = 0;
+  */
+  lastElapsed = 0;
+  gettimeofday(&cp[0], NULL);
+  gettimeofday(&cp[1], NULL);
+  sessionDownloadSize[0] = 0;
+  sessionDownloadSize[1] = 0;
+  sessionUploadSize[0] = 0;
+  sessionUploadSize[1] = 0;
+  currentCp = 0;
+}
+
+/*
+int TorrentConsoleDownloadEngine::calculateSpeed(int deltaSize, long long int elapsed, int prevSpeed) {
+  int nowSpeed = (int)(deltaSize/(elapsed/1000000.0));
+  return (nowSpeed+prevSpeed)/2;
+}
+*/
+int TorrentConsoleDownloadEngine::calculateSpeed(long long int sessionSize, long long int elapsed) {
+  int nowSpeed = (int)(sessionSize/(elapsed/1000000.0));
+  return nowSpeed;
+}
+
+void TorrentConsoleDownloadEngine::calculateStatistics() {
+  /*
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  long long int elapsed = Util::difftv(now, cp);
+  sessionDownloadSize += torrentMan->getDeltaDownload();
+  sessionUploadSize += torrentMan->getDeltaUpload();
+  
+  downloadSpeed = calculateSpeed(sessionDownloadSize, elapsed);
+  uploadSpeed = calculateSpeed(sessionUploadSize, elapsed);
+  torrentMan->resetDeltaDownload();
+  torrentMan->resetDeltaUpload();
+  if(elapsed-lastElapsed >= 1000000) {
+    printStatistics();
+    lastElapsed = elapsed;
+  }
+  */
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  long long int elapsed = Util::difftv(now, cp[currentCp]);
+
+  sessionDownloadSize[0] += torrentMan->getDeltaDownload();
+  sessionUploadSize[0] += torrentMan->getDeltaUpload();
+  sessionDownloadSize[1] += torrentMan->getDeltaDownload();
+  sessionUploadSize[1] += torrentMan->getDeltaUpload();
+
+  downloadSpeed = calculateSpeed(sessionDownloadSize[currentCp], elapsed);
+  uploadSpeed = calculateSpeed(sessionUploadSize[currentCp], elapsed);
+
+  torrentMan->resetDeltaDownload();
+  torrentMan->resetDeltaUpload();
+
+  if(elapsed-lastElapsed >= 1000000) {
+    printStatistics();
+    lastElapsed = elapsed;
+  }
+
+  if(elapsed > 15*1000000) {
+    sessionDownloadSize[currentCp] = 0;
+    sessionUploadSize[currentCp] = 0;
+    cp[currentCp] = now;
+    lastElapsed = 0;
+    currentCp = currentCp ? 0 : 1;
+  }
+
+    /*
+    if(elapsed >= 1000000) {
+      downloadSpeed = calculateSpeed(torrentMan->getDeltaDownload(),
+				     elapsed, downloadSpeed);
+      uploadSpeed = calculateSpeed(torrentMan->getDeltaUpload(),
+				   elapsed, uploadSpeed);
+      torrentMan->resetDeltaDownload();
+      torrentMan->resetDeltaUpload();
+      cp = now;
+      printStatistics();
+    }
+    */
+}

+ 52 - 0
src/TorrentConsoleDownloadEngine.h

@@ -0,0 +1,52 @@
+/* <!-- 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_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_
+#define _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_
+
+#include "TorrentDownloadEngine.h"
+
+class TorrentConsoleDownloadEngine : public TorrentDownloadEngine {
+private:
+  /*
+  struct timeval cp;
+  long long int sessionDownloadSize;
+  long long int sessionUploadSize;
+  */
+  struct timeval cp[2];
+  long long int sessionDownloadSize[2];
+  long long int sessionUploadSize[2];
+  int currentCp;
+
+  int downloadSpeed;
+  int uploadSpeed;
+  long long int lastElapsed;
+  void printStatistics();
+  int calculateSpeed(long long int sessionSize, long long int elapsed);
+protected:
+  void initStatistics();
+  void calculateStatistics();
+public:
+  TorrentConsoleDownloadEngine();
+  ~TorrentConsoleDownloadEngine();
+};
+
+#endif // _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_

+ 32 - 0
src/TorrentDownloadEngine.cc

@@ -0,0 +1,32 @@
+/* <!-- 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 "TorrentDownloadEngine.h"
+
+void TorrentDownloadEngine::onEndOfRun() {
+  torrentMan->diskWriter->closeFile();
+  if(torrentMan->downloadComplete()) {
+    torrentMan->remove();
+    torrentMan->fixFilename();
+  } else {
+    torrentMan->save();
+  }
+}

+ 38 - 0
src/TorrentDownloadEngine.h

@@ -0,0 +1,38 @@
+/* <!-- 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_TORRENT_DOWNLOAD_ENGINE_H_
+#define _D_TORRENT_DOWNLOAD_ENGINE_H_
+
+#include "DownloadEngine.h"
+#include "TorrentMan.h"
+
+class TorrentDownloadEngine : public DownloadEngine {
+protected:
+  void onEndOfRun();
+public:
+  TorrentDownloadEngine() {}
+  virtual ~TorrentDownloadEngine() {}
+
+  TorrentMan* torrentMan;
+};
+
+#endif // _D_TORRENT_DOWNLOAD_ENGINE_H_

+ 505 - 0
src/TorrentMan.cc

@@ -0,0 +1,505 @@
+/* <!-- 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 "TorrentMan.h"
+#include "Dictionary.h"
+#include "List.h"
+#include "ShaVisitor.h"
+#include "Util.h"
+#include "MetaFileUtil.h"
+#include "DlAbortEx.h"
+#include "File.h"
+#include "message.h"
+#include "PreAllocationDiskWriter.h"
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+TorrentMan::TorrentMan():bitfield(NULL),
+			 peerEntryIdCounter(0), cuidCounter(0),
+			 downloadedSize(0), uploadedSize(0),
+			 deltaDownload(0), deltaUpload(0),
+			 multiFileTopDir(NULL),
+			 interval(DEFAULT_ANNOUNCE_INTERVAL),
+			 minInterval(DEFAULT_ANNOUNCE_MIN_INTERVAL),
+			 complete(0), incomplete(0),
+			 connections(0) {}
+
+TorrentMan::~TorrentMan() {
+  if(bitfield != NULL) {
+    delete bitfield;
+  }
+  if(multiFileTopDir != NULL) {
+    delete multiFileTopDir;
+  }
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    delete *itr;
+  }
+}
+
+// TODO do not use this method in application code
+void TorrentMan::updatePeers(const Peers& peers) {
+  this->peers = peers;
+}
+
+bool TorrentMan::addPeer(Peer* peer, bool duplicate) {
+  if(duplicate) {
+    for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+      Peer* p = *itr;
+      if(p->ipaddr == peer->ipaddr && p->port == peer->port && p->error > 0) {
+	return false;
+      }
+    }
+  } else {
+    for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+      Peer* p = *itr;
+      if(p->ipaddr == peer->ipaddr && p->port == peer->port) {
+	return false;
+      }
+    }
+  }
+  ++peerEntryIdCounter;
+  peer->entryId = peerEntryIdCounter;
+  peers.push_back(peer);
+  return true;
+}
+
+/*
+void TorrentMan::updatePeer(const Peer& peer) {
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    Peer& p = *itr;
+    if(p.eid == peer.eid) {
+      p = peer;
+      break;
+    }
+  }
+}
+*/
+
+bool TorrentMan::isPeerAvailable() const {
+  return getPeer() != Peer::nullPeer;
+}
+
+int TorrentMan::deleteOldErrorPeers(int maxNum) {
+  int counter = 0;
+  for(Peers::iterator itr = peers.begin(); itr != peers.end();) {
+    Peer* p = *itr;
+    if(p->error != 0 && p->cuid == 0) {
+      delete p;
+      itr = peers.erase(itr);
+      counter++;
+      if(maxNum <= counter) {
+	break;
+      }
+    } else {
+      itr++;
+    }
+  }
+  return counter;
+}
+
+Peer* TorrentMan::getPeer() const {
+  for(Peers::const_iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    Peer* p = *itr;
+    if(p->cuid == 0 && p->error == 0) {
+      return p;
+    }
+  }
+  return Peer::nullPeer;
+}
+
+bool TorrentMan::isEndGame() const {
+  return bitfield->countMissingBlock() <= END_GAME_PIECE_NUM;
+}
+
+Piece TorrentMan::getMissingPiece(const unsigned char* peerBitfield, int length) {
+  int index = -1;
+  if(isEndGame()) {
+    index = bitfield->getMissingIndex(peerBitfield, length);
+  } else {
+    index = bitfield->getMissingUnusedIndex(peerBitfield, length);
+  }
+  if(index == -1) {
+    return Piece::nullPiece;
+  }
+  bitfield->setUseBit(index);
+
+  Piece piece = findUsedPiece(index);
+  if(Piece::isNull(piece)) {
+    Piece piece(index, bitfield->getBlockLength(index));
+    addUsedPiece(piece);
+    return piece;
+  } else {
+    return piece;
+  }
+}
+
+int TorrentMan::deleteUsedPiecesByFillRate(int fillRate, int toDelete) {
+  int deleted = 0;
+  for(UsedPieces::iterator itr = usedPieces.begin();
+      itr != usedPieces.end() && deleted < toDelete;) {
+    Piece& piece = *itr;
+    if(!bitfield->isUseBitSet(piece.getIndex()) &&
+       piece.countCompleteBlock() <= piece.countBlock()*(fillRate/100.0)) {
+      logger->debug("deleting used piece index=%d, fillRate(%%)=%d<=%d",
+		    piece.getIndex(),
+		    (piece.countCompleteBlock()*100)/piece.countBlock(),
+		    fillRate);
+      itr = usedPieces.erase(itr);
+      deleted++;
+    } else {
+      itr++;
+    }
+  }
+  return deleted;
+}
+
+void TorrentMan::reduceUsedPieces(int max) {
+  int toDelete = usedPieces.size()-max;
+  if(toDelete <= 0) {
+    return;
+  }
+  int fillRate = 10;
+  while(fillRate < 50) {
+    int deleted = deleteUsedPiecesByFillRate(fillRate, toDelete);
+    if(deleted == 0) {
+      break;
+    }
+    toDelete -= deleted;
+    fillRate += 10;
+  }
+}
+
+void TorrentMan::addUsedPiece(const Piece& piece) {
+  usedPieces.push_back(piece);
+}
+
+Piece TorrentMan::findUsedPiece(int index) const {
+  for(UsedPieces::const_iterator itr = usedPieces.begin(); itr != usedPieces.end(); itr++) {
+    const Piece& piece = *itr;
+    if(piece.getIndex() == index) {
+      return piece;
+    }
+  }
+  return Piece::nullPiece;
+}
+
+void TorrentMan::deleteUsedPiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  for(UsedPieces::iterator itr = usedPieces.begin(); itr != usedPieces.end(); itr++) {
+    if(itr->getIndex() == piece.getIndex()) {
+      usedPieces.erase(itr);
+      break;
+    }
+  }  
+}
+
+void TorrentMan::completePiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  bitfield->setBit(piece.getIndex());
+  bitfield->unsetUseBit(piece.getIndex());
+  addDownloadedSize(piece.getLength());
+  deleteUsedPiece(piece);
+  if(!isEndGame()) {
+    reduceUsedPieces(100);
+  }
+}
+
+void TorrentMan::cancelPiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  bitfield->unsetUseBit(piece.getIndex());
+  if(!isEndGame()) {
+    if(piece.countCompleteBlock() == 0) {
+      deleteUsedPiece(piece);
+    }
+  }
+}
+
+void TorrentMan::updatePiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  for(UsedPieces::iterator itr = usedPieces.begin(); itr != usedPieces.end(); itr++) {
+    if(itr->getIndex() == piece.getIndex()) {
+      *itr = piece;
+      break;
+    }
+  }
+}
+
+void TorrentMan::syncPiece(Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  for(UsedPieces::iterator itr = usedPieces.begin(); itr != usedPieces.end(); itr++) {
+    if(itr->getIndex() == piece.getIndex()) {
+      piece = *itr;
+      return;
+    }
+  }
+  // hasPiece(piece.getIndex()) is true, then set all bit of
+  // piece.bitfield to 1
+  if(hasPiece(piece.getIndex())) {
+    piece.setAllBlock();
+  }
+}
+
+void TorrentMan::initBitfield() {
+  if(bitfield != NULL) {
+    delete bitfield;
+  }
+  bitfield = new BitfieldMan(pieceLength, totalSize);
+}
+
+void TorrentMan::setBitfield(unsigned char* bitfield, int bitfieldLength) {
+  if(this->bitfield == NULL) {
+    initBitfield();
+  }
+  this->bitfield->setBitfield(bitfield, bitfieldLength);
+}
+
+bool TorrentMan::downloadComplete() const {
+  return bitfield->isAllBitSet();
+}
+
+void TorrentMan::setup(string metaInfoFile) {
+  peerId = "-A2****-";
+  for(int i = 0; i < 12; i++) {
+    peerId += Util::itos((int)(((double)10)*random()/(RAND_MAX+1.0)));
+  }
+
+  uploadedSize = 0;
+  downloadedSize = 0;
+  Dictionary* topDic = (Dictionary*)MetaFileUtil::parseMetaFile(metaInfoFile);
+  const Dictionary* infoDic = (const Dictionary*)topDic->get("info");
+  ShaVisitor v;
+  infoDic->accept(&v);
+  unsigned char md[20];
+  int len;
+  v.getHash(md, len);
+  setInfoHash(md);
+
+  Data* topName = (Data*)infoDic->get("name");
+  if(topName != NULL) {
+    name = topName->toString();
+  } else {
+    char* basec = strdup(metaInfoFile.c_str());
+    name = string(basename(basec));
+    free(basec);
+  }
+
+  List* files = (List*)infoDic->get("files");
+  if(files == NULL) {
+    // single-file mode;
+    setFileMode(SINGLE);
+    Data* length = (Data*)infoDic->get("length");
+    totalSize = length->toLLInt();
+  } else {
+    long long int length = 0;
+    // multi-file mode
+    setFileMode(MULTI);
+    multiFileTopDir = new Directory(name);
+    const MetaList& metaList = files->getList();
+    for(MetaList::const_iterator itr = metaList.begin(); itr != metaList.end();
+	itr++) {
+      Dictionary* fileDic = (Dictionary*)(*itr);
+      Data* lengthData = (Data*)fileDic->get("length");
+      //length += strtoll(data->toString().c_str(), NULL, 10);
+      length += lengthData->toLLInt();
+      List* path = (List*)fileDic->get("path");
+      const MetaList& paths = path->getList();
+      Directory* parentDir = multiFileTopDir;
+      string filePath = name;
+      for(int i = 0; i < (int)paths.size()-1; i++) {
+	Data* subpath = (Data*)paths.at(i);
+	Directory* dir = new Directory(subpath->toString());
+	parentDir->addFile(dir);
+	parentDir = dir;
+	filePath.append("/").append(subpath->toString());
+      }
+      Data* lastpath = (Data*)paths.back();
+      filePath.append("/").append(lastpath->toString());
+      FileEntry fileEntry(filePath, lengthData->toLLInt());
+      multiFileEntries.push_back(fileEntry);
+    }
+    totalSize = length;
+  }
+  announce = ((Data*)topDic->get("announce"))->toString();
+  pieceLength = ((Data*)infoDic->get("piece length"))->toInt();
+  pieces = totalSize/pieceLength+(totalSize%pieceLength ? 1 : 0);
+    
+  Data* piecesHashData = (Data*)infoDic->get("pieces");
+  if(piecesHashData->getLen() != pieces*20) {
+    throw new DlAbortEx("the number of pieces is wrong.");
+  }
+  for(int index = 0; index < pieces; index++) {
+    string hex = Util::toHex((unsigned char*)&piecesHashData->getData()[index*20], 20);
+    pieceHashes.push_back(hex);
+    logger->debug("piece #%d, hash:%s", index, hex.c_str());
+  }
+
+  initBitfield();
+  delete topDic;
+
+  diskWriter = new PreAllocationDiskWriter(totalSize);
+  if(segmentFileExists()) {
+    load();
+    diskWriter->openExistingFile(getTempFilePath());
+  } else {
+    diskWriter->initAndOpenFile(getTempFilePath());
+  }
+}
+
+bool TorrentMan::hasPiece(int index) const {
+  return bitfield->isBitSet(index);
+}
+
+string TorrentMan::getPieceHash(int index) const {
+  return pieceHashes.at(index);
+}
+
+string TorrentMan::getFilePath() const {
+  return (storeDir == "" ? "." : storeDir)+"/"+name;
+}
+
+string TorrentMan::getTempFilePath() const {
+  return getFilePath()+".a2tmp";
+}
+
+string TorrentMan::getSegmentFilePath() const {
+  return getFilePath()+".aria2";
+}
+
+bool TorrentMan::segmentFileExists() const {
+  string segFilename = getSegmentFilePath();
+  File f(segFilename);
+  if(f.isFile()) {
+    logger->info(MSG_SEGMENT_FILE_EXISTS, segFilename.c_str());
+    return true;
+  } else {
+    logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, segFilename.c_str());
+    return false;
+  }
+}
+
+FILE* TorrentMan::openSegFile(string segFilename, string mode) const {
+  FILE* segFile = fopen(segFilename.c_str(), mode.c_str());
+  if(segFile == NULL) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  return segFile;
+}
+
+void TorrentMan::load() {
+  string segFilename = getSegmentFilePath();
+  logger->info(MSG_LOADING_SEGMENT_FILE, segFilename.c_str());
+  FILE* segFile = openSegFile(segFilename, "r+");
+  read(segFile);
+  fclose(segFile);
+  logger->info(MSG_LOADED_SEGMENT_FILE);
+}
+
+void TorrentMan::read(FILE* file) {
+  assert(file != NULL);
+  unsigned char savedInfoHash[INFO_HASH_LENGTH];
+  if(fread(savedInfoHash, INFO_HASH_LENGTH, 1, file) < 1) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  if(Util::toHex(savedInfoHash, INFO_HASH_LENGTH) != Util::toHex(infoHash, INFO_HASH_LENGTH)) {
+    throw new DlAbortEx("info hash mismatch");
+  }
+  unsigned char* savedBitfield = new unsigned char[bitfield->getBitfieldLength()];
+  try {
+    if(fread(savedBitfield, bitfield->getBitfieldLength(), 1, file) < 1) {
+      throw new DlAbortEx(strerror(errno));
+    }
+    setBitfield(savedBitfield, bitfield->getBitfieldLength());
+    if(fread(&downloadedSize, sizeof(downloadedSize), 1, file) < 1) {
+      throw new DlAbortEx(strerror(errno));
+    }
+    if(fread(&uploadedSize, sizeof(uploadedSize), 1, file) < 1) {
+      throw new DlAbortEx(strerror(errno));
+    }
+    delete savedBitfield;
+  } catch(Exception* ex) {
+    delete savedBitfield;
+    throw;
+  }
+}
+
+void TorrentMan::save() const {
+  if(downloadedSize == 0) {
+    return;
+  }
+  string segFilename = getSegmentFilePath();
+  logger->info(MSG_SAVING_SEGMENT_FILE, segFilename.c_str());
+  FILE* file = openSegFile(segFilename, "w");
+  if(fwrite(infoHash, INFO_HASH_LENGTH, 1, file) < 1) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  if(fwrite(bitfield->getBitfield(), bitfield->getBitfieldLength(), 1, file) < 1) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  if(fwrite(&downloadedSize, sizeof(downloadedSize), 1, file) < 1) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  if(fwrite(&uploadedSize, sizeof(uploadedSize), 1, file) < 1) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  fclose(file);
+  logger->info(MSG_SAVED_SEGMENT_FILE);
+}
+
+void TorrentMan::remove() const {
+  if(segmentFileExists()) {
+    File f(getSegmentFilePath());
+    f.remove();
+  }
+}
+
+void TorrentMan::fixFilename() const {
+  if(fileMode == SINGLE) {
+    renameSingleFile();
+  } else {
+    splitMultiFile();
+  }
+}
+
+void TorrentMan::renameSingleFile() const {
+  rename(getTempFilePath().c_str(), getFilePath().c_str());
+}
+
+void TorrentMan::splitMultiFile() const {
+  multiFileTopDir->createDir((storeDir == "" ? "." : storeDir), true);
+  long long int offset = 0;
+  for(MultiFileEntries::const_iterator itr = multiFileEntries.begin();
+      itr != multiFileEntries.end(); itr++) {
+    Util::rangedFileCopy(itr->path, getTempFilePath(), offset, itr->length);
+    offset += itr->length;
+  }
+  unlink(getTempFilePath().c_str());
+}

+ 217 - 0
src/TorrentMan.h

@@ -0,0 +1,217 @@
+/* <!-- 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_TORRENT_MAN_H_
+#define _D_TORRENT_MAN_H_
+
+#include "Peer.h"
+#include "common.h"
+#include "Logger.h"
+#include "BitfieldMan.h"
+#include "DiskWriter.h"
+#include "Piece.h"
+#include "Directory.h"
+#include <vector>
+#include <map>
+#include <string>
+
+using namespace std;
+
+#define DEFAULT_BLOCK_LEN 16*1024;
+#define MAX_BLOCK_LEN 128*1024;
+
+#define INFO_HASH_LENGTH 20
+
+#define IS_NULL_PIECE(X) (X.index == 0 && X.length == 0)
+
+#define DEFAULT_ANNOUNCE_INTERVAL 1800
+#define DEFAULT_ANNOUNCE_MIN_INTERVAL 120
+#define MAX_PEERS 55
+#define END_GAME_PIECE_NUM 20
+
+class FileEntry {
+public:
+  string path;
+  long long int length;
+  FileEntry(string path, long long int length):path(path), length(length) {}
+  ~FileEntry() {}
+};
+
+typedef vector<Peer*> Peers;
+typedef multimap<int, int> Haves;
+typedef vector<FileEntry> MultiFileEntries;
+typedef vector<Piece> UsedPieces;
+
+class TorrentMan {
+private:
+  Peers peers;
+  BitfieldMan* bitfield;
+  unsigned char infoHash[INFO_HASH_LENGTH];
+  vector<string> pieceHashes;
+  int peerEntryIdCounter;
+  int cuidCounter;
+  long long int downloadedSize;
+  long long int uploadedSize;
+  int deltaDownload;
+  int deltaUpload;
+  int fileMode;
+  string storeDir;
+  int port;
+  Haves haves;
+  UsedPieces usedPieces;
+  Directory* multiFileTopDir;
+  MultiFileEntries multiFileEntries;
+
+  FILE* openSegFile(string segFilename, string mode) const;
+  void read(FILE* file);
+
+  Piece findUsedPiece(int index) const;
+  void addUsedPiece(const Piece& piece);
+  void deleteUsedPiece(const Piece& piece);
+  int deleteUsedPiecesByFillRate(int fillRate, int toDelete);
+  void reduceUsedPieces(int max);
+public:
+  int pieceLength;
+  int pieces;
+  long long int totalSize;
+  string peerId;
+  string announce;
+  string trackerId;
+  string name;
+  int interval;
+  int minInterval;
+  int complete;
+  int incomplete;
+  int connections;
+public:
+  TorrentMan();
+  ~TorrentMan();
+
+  const Logger* logger;
+  DiskWriter* diskWriter;
+
+  int getNewCuid() { return ++cuidCounter; }
+
+  // TODO do not use this method
+  void updatePeers(const Peers& peers);
+  bool addPeer(Peer* peer, bool duplicate = false);
+  //void updatePeer(const Peer* peer);
+  const Peers& getPeers() const { return peers; }
+  Peer* getPeer() const;
+  bool isPeerAvailable() const;
+  int deleteOldErrorPeers(int maxNum);
+
+  Piece getMissingPiece(const unsigned char* peerBitfield, int len);
+  void completePiece(const Piece& piece);
+  void cancelPiece(const Piece& piece);
+  void updatePiece(const Piece& piece);
+  void syncPiece(Piece& piece);
+  bool hasPiece(int index) const;
+  void initBitfield();
+  bool isEndGame() const;
+  bool downloadComplete() const;
+  void setBitfield(unsigned char* bitfield, int len);
+  const unsigned char* getBitfield() const {
+    return bitfield->getBitfield();
+  }
+  int getBitfieldLength() const { return bitfield->getBitfieldLength(); }
+  void setInfoHash(const unsigned char* infoHash) {
+    memcpy(this->infoHash, infoHash, INFO_HASH_LENGTH);
+  }
+  const unsigned char* getInfoHash() const {
+    return infoHash;
+  }
+
+  void setup(string metaInfoFile);
+
+  string getPieceHash(int index) const;
+
+  void advertisePiece(int cuid, int index) {
+    Haves::value_type vt(cuid, index);
+    haves.insert(vt);
+  }
+
+  vector<int> getAdvertisedPieceIndexes(int myCuid) const {
+    vector<int> indexes;
+    for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) {
+      const Haves::value_type& have = *itr;
+      if(have.first == myCuid) {
+	continue;
+      }
+      indexes.push_back(have.second);
+    }
+    return indexes;
+  }
+
+  void unadvertisePiece(int cuid) {
+    haves.erase(cuid);
+  }
+
+  void addDeltaDownload(int size) { deltaDownload += size; }
+  int getDeltaDownload() const { return deltaDownload; }
+  void resetDeltaDownload() { deltaDownload = 0; }
+
+  void addDeltaUpload(int size) { deltaUpload += size; }
+  int getDeltaUpload() const { return deltaUpload; }
+  void resetDeltaUpload() { deltaUpload = 0; }
+
+  void addDownloadedSize(int size) { downloadedSize += size; }
+  long long int getDownloadedSize() const { return downloadedSize; }
+  void setDownloadedSize(long long int size) { downloadedSize = size; }
+
+  void addUploadedSize(int size) { uploadedSize += size; }
+  long long int getUploadedSize() const { return uploadedSize; }
+  void setUploadedSize(long long int size) { uploadedSize = size; }
+
+  void setFileMode(int mode) {
+    fileMode = mode;
+  }
+
+  int getFileMode() const {
+    return fileMode;
+  }
+
+  string getStoreDir() const { return storeDir; }
+  void setStoreDir(string dir) { storeDir = dir; }
+
+  string getFilePath() const;
+  string getTempFilePath() const;
+  string getSegmentFilePath() const;
+
+  bool segmentFileExists() const;  
+  void load();
+  void save() const;
+  void remove() const;
+
+  void renameSingleFile() const;
+  void splitMultiFile() const;
+  void fixFilename() const;
+
+  void setPort(int port) { this->port = port; }
+  int getPort() const { return port; }
+
+  enum FILE_MODE {
+    SINGLE,
+    MULTI
+  };
+};
+
+#endif // _D_TORRENT_MAN_H_

+ 99 - 0
src/TrackerDownloadCommand.cc

@@ -0,0 +1,99 @@
+/* <!-- 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 "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,
+					       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<string, TransferEncoding*>::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();
+    e->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;
+}

+ 50 - 0
src/TrackerDownloadCommand.h

@@ -0,0 +1,50 @@
+/* <!-- 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_TRACKER_DOWNLOAD_COMMAND_H_
+#define _D_TRACKER_DOWNLOAD_COMMAND_H_
+
+#include "AbstractCommand.h"
+#include "TorrentDownloadEngine.h"
+#include "TransferEncoding.h"
+#include "Segment.h"
+#include <map>
+
+class TrackerDownloadCommand : public AbstractCommand {
+private:
+  char* res;
+  int resSize;
+  int len;
+  map<string, TransferEncoding*> transferEncodings;
+  void expandBuffer(int newSize);
+protected:
+  bool executeInternal(Segment segment);
+public:
+  TrackerDownloadCommand(int cuid, Request* req, TorrentDownloadEngine* e, Socket* s);
+  ~TrackerDownloadCommand();
+
+  TransferEncoding* getTransferEncoding(string transferEncoding);
+
+  string transferEncoding;
+};
+
+#endif // _D_TRACKER_DOWNLOAD_COMMAND_H_
+

+ 67 - 0
src/TrackerInitCommand.cc

@@ -0,0 +1,67 @@
+/* <!-- 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 "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()) {
+    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->getUploadedSize())+"&"+
+    "downloaded="+Util::llitos(e->torrentMan->getDownloadedSize())+"&"+
+    "left="+Util::llitos(e->torrentMan->totalSize-e->torrentMan->getDownloadedSize())+"&"+
+    "compact=1";
+  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;
+}
+

+ 40 - 0
src/TrackerInitCommand.h

@@ -0,0 +1,40 @@
+/* <!-- 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_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_

+ 126 - 0
src/TrackerUpdateCommand.cc

@@ -0,0 +1,126 @@
+/* <!-- 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 "TrackerUpdateCommand.h"
+#include "TrackerInitCommand.h"
+#include "PeerInitiateConnectionCommand.h"
+#include "PeerListenCommand.h"
+#include "SleepCommand.h"
+#include "Dictionary.h"
+#include "Data.h"
+#include "DlAbortEx.h"
+#include "message.h"
+#include <netinet/in.h>
+
+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() {
+  if(req->getTrackerEvent() == Request::COMPLETED) {
+    return true;
+  }
+  e->torrentMan->deleteOldErrorPeers(25);
+
+  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) {
+    e->logger->info(MSG_TRACKER_WARNING_MESSAGE, cuid, warningMessage->toString().c_str());
+  }
+  Data* trackerId = (Data*)response->get("tracker id");
+  if(trackerId != NULL) {
+    e->torrentMan->trackerId = trackerId->toString();
+    e->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();
+    e->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();
+    e->logger->debug("CUID#%d - min interval:%d", cuid, e->torrentMan->minInterval);
+  }
+  Data* complete = (Data*)response->get("complete");
+  if(complete != NULL) {
+    e->torrentMan->complete = complete->toInt();
+    e->logger->debug("CUID#%d - complete:%d", cuid, e->torrentMan->complete);
+  }
+  Data* incomplete = (Data*)response->get("incomplete");
+  if(incomplete != NULL) {
+    e->torrentMan->incomplete = incomplete->toInt();
+    e->logger->debug("CUID#%d - incomplete:%d", cuid, e->torrentMan->incomplete);
+  } 
+  Data* peers = (Data*)response->get("peers");
+  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 short int nPort = 0;
+    //memcpy(&nPort, peers->getData()+i+4, 2);
+    unsigned int port = ntohs(*(unsigned short int*)(peers->getData()+i+4));
+    //unsigned int port = ntohs(nPort);
+    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->totalSize);
+    if(e->torrentMan->addPeer(peer)) {
+      e->logger->debug("CUID#%d - adding peer %s:%d", cuid,
+		       peer->ipaddr.c_str(), peer->port);
+    } else {
+      delete peer;
+    }
+  }
+  /*
+  if(req->getTrackerEvent() == Request::STARTED) {
+    PeerListenCommand* command = new PeerListenCommand(e->torrentMan->getNewCuid(), e);
+    e->commands.push(command);
+    e->logger->debug("CUID#%d - adding listen command", cuid);
+  }
+  */
+  while(e->torrentMan->isPeerAvailable() &&
+	e->torrentMan->connections < MAX_PEERS) {
+    Peer* peer = e->torrentMan->getPeer();
+    int newCuid =  e->torrentMan->getNewCuid();
+    peer->cuid = newCuid;
+    PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e);
+    e->commands.push(command);
+    e->logger->debug("CUID#%d - adding new command CUID#%d", cuid, newCuid);
+  }
+  req->setTrackerEvent(Request::AUTO);
+  TrackerInitCommand* command = new TrackerInitCommand(cuid, req, e);
+  SleepCommand* slpCommand = new SleepCommand(cuid, e, command, e->torrentMan->minInterval);
+  e->commands.push(slpCommand);
+  return true;
+}

+ 42 - 0
src/TrackerUpdateCommand.h

@@ -0,0 +1,42 @@
+/* <!-- 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_TRACKER_UPDATE_COMMAND_H_
+#define _D_TRACKER_UPDATE_COMMAND_H_
+
+#include "Command.h"
+#include "Request.h"
+#include "TorrentDownloadEngine.h"
+#include "MetaEntry.h"
+
+class TrackerUpdateCommand : public Command {
+private:
+  Request* req;
+  TorrentDownloadEngine* e;
+  MetaEntry* trackerResponse;
+public:
+  TrackerUpdateCommand(int cuid, Request* req, TorrentDownloadEngine* e, MetaEntry* trackerResponse);
+  ~TrackerUpdateCommand();
+
+  bool execute();
+};
+
+#endif // _D_TRACKER_UPDATE_COMMAND_H_

+ 72 - 0
src/Util.cc

@@ -20,6 +20,11 @@
  */
 /* copyright --> */
 #include "Util.h"
+#include "DlAbortEx.h"
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 string Util::itos(int value, bool comma) {
   string str = llitos(value, comma);
@@ -146,3 +151,70 @@ string Util::replace(string target, string oldstr, string newstr) {
   return result;
 }
 
+string Util::urlencode(const unsigned char* target, int len) {
+  string dest;
+  for(int i = 0; i < len; i++) {
+    if(!('0' <= target[i] && target[i] <= '9' ||
+	 'A' <= target[i] && target[i] <= 'Z' ||
+	 'a' <= target[i] && target[i] <= 'z' ||
+	 '$' == target[i] || '-' == target[i] ||
+	 '_' == target[i] || '.' == target[i] ||
+	 '+' == target[i] || '!' == target[i] ||
+	 '*' == target[i] || '\'' == target[i] ||
+	 '(' == target[i] || ')' == target[i] ||
+	 ',' == target[i])) {
+      char temp[4];
+      sprintf(temp, "%%%02x", target[i]);
+      temp[sizeof(temp)-1] = '\0';
+      dest.append(temp);
+    } else {
+      dest += target[i];
+    }
+  }
+  return dest;
+}
+
+string Util::toHex(const unsigned char* src, int len) {
+  char* temp = new char[len*2+1];
+  for(int i = 0; i < len; i++) {
+    sprintf(temp+i*2, "%02x", src[i]);
+  }
+  temp[len*2] = '\0';
+  string hex = temp;
+  delete [] temp;
+  return hex;
+}
+
+FILE* Util::openFile(string filename, string mode) {
+  FILE* file = fopen(filename.c_str(), mode.c_str());
+  return file;
+}
+
+void Util::rangedFileCopy(string dest, string src, long long int srcOffset, long long int length) {
+  int destFd;
+  if((destFd = open(dest.c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  int srcFd;
+  if((srcFd = open(src.c_str(), O_RDONLY, S_IRUSR|S_IWUSR)) < 0) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  if(lseek(srcFd, srcOffset, SEEK_SET) != srcOffset) {
+    throw new DlAbortEx(strerror(errno));
+  }
+  int BUF_SIZE = 16*1024;
+  char buf[BUF_SIZE];
+  int x = length/BUF_SIZE+(length%BUF_SIZE ? 1 : 0);
+  for(int i = 0; i < x; i++) {
+    int readLength;
+    if((readLength = read(srcFd, buf, BUF_SIZE)) == -1) {
+      throw new DlAbortEx(strerror(errno));
+    }
+    if(write(destFd, buf, readLength) == -1) {
+      throw new DlAbortEx(strerror(errno));
+    }
+  }
+  close(srcFd);
+  close(destFd);
+}
+

+ 9 - 0
src/Util.h

@@ -56,6 +56,15 @@ public:
   static bool endsWith(string target, string part);
 
   static string replace(string target, string oldstr, string newstr);
+
+  static string urlencode(const unsigned char* target, int len);
+
+  static string toHex(const unsigned char* src, int len);
+
+  static FILE* openFile(string filename, string mode);
+
+  static void rangedFileCopy(string destFile, string src, long long int srcOffset, long long int length);
+
 };
 
 #endif // _D_UTIL_H_

+ 2 - 0
src/common.h

@@ -41,6 +41,8 @@
 
 #define USER_AGENT "aria2"
 
+#define BITFIELD_LEN_FROM_PIECES(X) (X/8+(X%8? 1 : 0))
+
 using namespace std;
 
 #endif // _D_COMMON_H_

+ 173 - 36
src/main.cc

@@ -21,7 +21,9 @@
 /* copyright --> */
 #include "HttpInitiateConnectionCommand.h"
 #include "ConsoleDownloadEngine.h"
+#include "TorrentConsoleDownloadEngine.h"
 #include "SegmentMan.h"
+#include "TorrentMan.h"
 #include "SplitSlowestSegmentSplitter.h"
 #include "SimpleLogger.h"
 #include "common.h"
@@ -29,8 +31,13 @@
 #include "Util.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "prefs.h"
+#include "TrackerInitCommand.h"
+#include "PeerListenCommand.h"
+#include "TorrentAutoSaveCommand.h"
+#include "SleepCommand.h"
 #include <vector>
 #include <algorithm>
+#include <time.h>
 #include <signal.h>
 #include <unistd.h>
 #include <libgen.h>
@@ -47,11 +54,20 @@ extern int optind, opterr, optopt;
 
 using namespace std;
 
+void printDownloadCompeleteMessage(string filename) {
+  printf(_("\nThe download was complete. <%s>\n"), filename.c_str());
+}
+
+void printDownloadAbortMessage() {
+  printf(_("\nThe download was not complete because of errors. Check the log.\n"));
+}
+
 void clearRequest(Request* req) {
   delete(req);
 }
 
 DownloadEngine* e;
+TorrentDownloadEngine* te;
 
 void handler(int signal) {
   cout << _("\nSIGINT signal received.") << endl;
@@ -62,6 +78,22 @@ void handler(int signal) {
   exit(0);
 }
 
+void torrentHandler(int signal) {
+  cout << _("\nSIGINT signal received.") << endl;
+  if(te->torrentMan->diskWriter != NULL) {
+    te->torrentMan->diskWriter->closeFile();
+  }
+  if(te->torrentMan->downloadComplete()) {
+    te->torrentMan->remove();
+    te->torrentMan->fixFilename();
+    printDownloadCompeleteMessage(te->torrentMan->getFilePath());
+  } else {
+    te->torrentMan->save();
+  }
+
+  exit(0);
+}
+
 void addCommand(int cuid, const char* url, string referer, vector<Request*> requests) {
   Request* req = new Request();
   req->setReferer(referer);
@@ -146,6 +178,11 @@ void showUsage() {
   cout << _(" --ftp-via-http-proxy=METHOD  Use HTTP proxy in FTP. METHOD is either 'get' or\n"
 	    "                              'tunnel'.\n"
 	    "                              Default: tunnel") << endl;
+  cout << _(" --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 << _(" -v, --version                Print the version number and exit.") << endl;
   cout << _(" -h, --help                   Print this message and exit.") << endl;
   cout << endl;
@@ -162,6 +199,8 @@ void showUsage() {
   cout << "  aria2c http://AAA.BBB.CCC/file.zip http://DDD.EEE.FFF/GGG/file.zip" << endl;
   cout << _(" You can mix up different protocols:") << endl;
   cout << "  aria2c http://AAA.BBB.CCC/file.zip ftp://DDD.EEE.FFF/GGG/file.zip" << endl;
+  cout << _(" Download a torrent") << endl;
+  cout << "  aria2c -o test.torret http://AAA.BBB.CCC/file.torrent" << endl;
   cout << endl;
   printf(_("Reports bugs to %s"), "<tujikawa at users dot sourceforge dot net>");
   cout << endl;
@@ -181,6 +220,8 @@ int main(int argc, char* argv[]) {
   int split = 1;
   bool daemonMode = false;
   string referer;
+  string torrentFile;
+  bool followTorrent = true;
 
   int c;
   Option* op = new Option();
@@ -193,6 +234,7 @@ int main(int argc, char* argv[]) {
   op->put(PREF_FTP_PASSWD, "ARIA2USER@");
   op->put(PREF_FTP_TYPE, V_BINARY);
   op->put(PREF_FTP_VIA_HTTP_PROXY, V_TUNNEL);
+  op->put(PREF_AUTO_SAVE_INTERVAL, "60");
 
   while(1) {
     int optIndex = 0;
@@ -220,6 +262,8 @@ int main(int argc, char* argv[]) {
       { "ftp-via-http-proxy", required_argument, &lopt, 12 },
       { "min-segment-size", required_argument, &lopt, 13 },
       { "http-proxy-method", required_argument, &lopt, 14 },
+      { "torrent-file", required_argument, &lopt, 15 },
+      { "follow-torrent", required_argument, &lopt, 16 },
       { "version", no_argument, NULL, 'v' },
       { "help", no_argument, NULL, 'h' },
       { 0, 0, 0, 0 }
@@ -332,6 +376,19 @@ int main(int argc, char* argv[]) {
 	  exit(1);
 	}
 	break;
+      case 15:
+	torrentFile = string(optarg);
+	break;
+      case 16:
+	if(string(optarg) == "on") {
+	  followTorrent = true;
+	} else if(string(optarg) == "off") {
+	  followTorrent = false;
+	} else {
+	  cerr << _("follow-torrent must be either 'true' or 'false'.") << endl;
+	  showUsage();
+	  exit(1);
+	}
       }
       break;
     }
@@ -394,10 +451,12 @@ int main(int argc, char* argv[]) {
       exit(1);
     }
   }
-  if(optind == argc) {
-    cerr << _("specify at least one URL") << endl;
-    showUsage();
-    exit(1);
+  if(torrentFile.empty()) {
+    if(optind == argc) {
+      cerr << _("specify at least one URL") << endl;
+      showUsage();
+      exit(1);
+    }
   }
   if(daemonMode) {
     if(daemon(1, 1) < 0) {
@@ -410,6 +469,7 @@ int main(int argc, char* argv[]) {
   SSL_load_error_strings();
   SSL_library_init();
 #endif // HAVE_LIBSSL
+  srandom(time(NULL));
   SimpleLogger* logger;
   if(stdoutLog) {
     logger = new SimpleLogger(stdout);
@@ -420,43 +480,120 @@ int main(int argc, char* argv[]) {
   }
   SegmentSplitter* splitter = new SplitSlowestSegmentSplitter();
   splitter->setMinSegmentSize(op->getAsLLInt(PREF_MIN_SEGMENT_SIZE));
-  splitter->logger = logger;
-  e = new ConsoleDownloadEngine();
-  e->logger = logger;
-  e->option = op;
-  e->diskWriter = new DefaultDiskWriter();
-  e->segmentMan = new SegmentMan();
-  e->segmentMan->dir = dir;
-  e->segmentMan->ufilename = ufilename;
-  e->segmentMan->logger = logger;
-  e->segmentMan->option = op;
-  e->segmentMan->splitter = splitter;
-  vector<Request*> requests;
-  for(int i = 1; optind+i-1 < argc; i++) {
-    for(int s = 1; s <= split; s++) {
+
+  struct sigaction sigactIgn;
+  sigactIgn.sa_handler = SIG_IGN;
+  sigactIgn.sa_flags = 0;
+  sigemptyset(&sigactIgn.sa_mask);
+  sigaction(SIGPIPE, &sigactIgn, NULL);  
+
+  bool readyToTorrentMode = false;
+  string downloadedTorrentFile;
+  if(torrentFile.empty()) {
+    struct sigaction sigact;
+    sigact.sa_handler = handler;
+    sigact.sa_flags = 0;
+    sigemptyset(&sigact.sa_mask);
+    sigaction(SIGINT, &sigact, NULL);
+  
+    splitter->logger = logger;
+    e = new ConsoleDownloadEngine();
+    e->logger = logger;
+    e->option = op;
+    e->diskWriter = new DefaultDiskWriter();
+    e->segmentMan = new SegmentMan();
+    e->segmentMan->dir = dir;
+    e->segmentMan->ufilename = ufilename;
+    e->segmentMan->logger = logger;
+    e->segmentMan->option = op;
+    e->segmentMan->splitter = splitter;
+    
+    vector<Request*> requests;
+    for(int i = 1; optind+i-1 < argc; i++) {
+      for(int s = 1; s <= split; s++) {
       addCommand(split*(i-1)+s, argv[optind+i-1], referer, requests); 
+      }
     }
-  }
-  struct sigaction sigact;
-  sigact.sa_handler = handler;
-  sigact.sa_flags = 0;
-  sigemptyset(&sigact.sa_mask);
-  sigaction(SIGINT, &sigact, NULL);
+    e->run();
+    
+    if(e->segmentMan->finished()) {
+      printDownloadCompeleteMessage(e->segmentMan->getFilePath());
+      if(Util::endsWith(e->segmentMan->getFilePath(), ".torrent")) {
+	downloadedTorrentFile = e->segmentMan->getFilePath();
+	readyToTorrentMode = true;
+      }
+    } else {
+      printDownloadAbortMessage();
+    }
+    
+    for_each(requests.begin(), requests.end(), clearRequest);
+    requests.clear();
 
-  e->run();
+    delete(e->segmentMan);
+    delete(e->diskWriter);
+    delete(e);
+  }
+  if(!torrentFile.empty() || followTorrent && readyToTorrentMode) {
+    try {
+      op->put(PREF_MAX_TRIES, "0");
+      struct sigaction sigact;
+      sigact.sa_handler = torrentHandler;
+      sigact.sa_flags = 0;
+      sigemptyset(&sigact.sa_mask);
+      sigaction(SIGINT, &sigact, NULL);
+      Request* req = new Request();
+      req->isTorrent = true;
+      req->setTrackerEvent(Request::STARTED);
+      te = new TorrentConsoleDownloadEngine();
+      te->logger = logger;
+      te->option = op;
+      te->diskWriter = new DefaultDiskWriter();
+      te->segmentMan = new SegmentMan();
+      te->segmentMan->logger = logger;
+      te->segmentMan->option = op;
+      te->segmentMan->splitter = splitter;
+      te->torrentMan = new TorrentMan();
+      te->torrentMan->setStoreDir(dir);
+      te->torrentMan->logger = logger;
+      te->torrentMan->setup(torrentFile.empty() ? 
+			    downloadedTorrentFile : torrentFile);
 
-  if(e->segmentMan->finished()) {
-    printf(_("\nThe download was complete. <%s>\n"), e->segmentMan->getFilePath().c_str());
-  } else {
-    printf(_("\nThe download was not complete because of errors. Check the log.\n"));
+      PeerListenCommand* listenCommand =
+	new PeerListenCommand(te->torrentMan->getNewCuid(), te);
+      int port = listenCommand->bindPort(6881, 6999);
+      if(port == -1) {
+	printf("an error occurred while binding port.\n");
+	exit(1);
+      }
+      te->torrentMan->setPort(port);
+      te->commands.push(listenCommand);
+      te->commands.push(new TrackerInitCommand(te->torrentMan->getNewCuid(),
+					       req, te));
+      int autoSaveCommandCuid = te->torrentMan->getNewCuid();
+      te->commands.push(new SleepCommand(autoSaveCommandCuid, te,
+					 new TorrentAutoSaveCommand(autoSaveCommandCuid, te, op->getAsInt(PREF_AUTO_SAVE_INTERVAL)),
+					 op->getAsInt(PREF_AUTO_SAVE_INTERVAL)));
+      te->run();
+      
+      if(te->torrentMan->downloadComplete()) {
+	printDownloadCompeleteMessage(te->torrentMan->getFilePath());
+      } else {
+	printDownloadAbortMessage();
+      }
+      
+      delete(te->segmentMan);
+      delete(te->torrentMan);
+      delete(te);
+    } catch(Exception* ex) {
+      cerr << ex->getMsg() << endl;
+      delete ex;
+      exit(1);
+    }
   }
-  
-  for_each(requests.begin(), requests.end(), clearRequest);
-  requests.clear();
+
   delete(logger);
-  delete(e->segmentMan);
-  delete(e->option);
-  delete(e->diskWriter);
-  delete(e);
+  delete(op);
+  delete(splitter);
+
   return 0;
 }

+ 11 - 1
src/message.h

@@ -35,6 +35,15 @@
 #define MSG_RESTARTING_DOWNLOAD _("CUID#%d - Restarting the download.")
 #define MSG_MAX_TRY _("CUID#%d - %d times attempted, but no success. Download aborted.")
 #define MSG_UNREGISTER_CUID _("CUID#%d - Unregistering cuid from segmentManager.")
+#define MSG_SEND_PEER_MESSAGE "CUID#%d - To: %s:%d %s"
+#define MSG_SEND_PEER_MESSAGE_WITH_INDEX "CUID#%d - To: %s:%d %s index=%d"
+#define MSG_SEND_PEER_MESSAGE_WITH_BITFIELD "CUID#%d - To: %s:%d %s %s"
+#define MSG_SEND_PEER_MESSAGE_WITH_INDEX_BEGIN_LENGTH "CUID#%d - To: %s:%d %s index=%d, begin=%d, length=%d"
+#define MSG_RECEIVE_PEER_MESSAGE "CUID#%d - From: %s:%d %s"
+#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_SEGMENT_FILE_EXISTS _("The segment file %s exists.")
 #define MSG_SEGMENT_FILE_DOES_NOT_EXIST _("The segment file %s does not exist.")
@@ -59,5 +68,6 @@
 #define EX_SSL_INIT_FAILURE _("SSL initialization failed.")
 #define EX_SIZE_MISMATCH _("Size mismatch %lld != %lld")
 #define EX_GOT_EOF _("Got EOF from the server.")
-
+#define EX_EOF_FROM_PEER "Got EOF from peer."
+#define EX_MULFORMED_META_INFO "Mulformed meta info."
 #endif // _D_MESSAGE_H_

+ 2 - 0
src/prefs.h

@@ -41,6 +41,8 @@
 #define PREF_MAX_TRIES "max_try"
 // values: 1*digit
 #define PREF_MIN_SEGMENT_SIZE "min_segment_size"
+// values: 1*digit
+#define PREF_AUTO_SAVE_INTERVAL "auto_save_interval"
 
 /**
  * FTP related preferences

+ 76 - 0
test/BitfieldManTest.cc

@@ -0,0 +1,76 @@
+#include "BitfieldMan.h"
+#include <string>
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class BitfieldManTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(BitfieldManTest);
+  CPPUNIT_TEST(testGetBlockSize);
+  CPPUNIT_TEST(testGetFirstMissingUnusedIndex);
+  CPPUNIT_TEST(testIsAllBitSet);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testGetBlockSize();
+  void testGetFirstMissingUnusedIndex();
+  void testIsAllBitSet();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( BitfieldManTest );
+
+void BitfieldManTest::testGetBlockSize() {
+  BitfieldMan bt1(1024, 1024*10);
+  CPPUNIT_ASSERT_EQUAL(1024, bt1.getBlockSize(9));
+
+  BitfieldMan bt2(1024, 1024*10+1);
+  CPPUNIT_ASSERT_EQUAL(1024, bt2.getBlockSize(9));
+  CPPUNIT_ASSERT_EQUAL(1, bt2.getBlockSize(10));
+  CPPUNIT_ASSERT_EQUAL(0, bt2.getBlockSize(11));
+}
+
+void BitfieldManTest::testGetFirstMissingUnusedIndex() {
+  BitfieldMan bt1(1024, 1024*10);
+  unsigned char bitfield[2];
+  memset(bitfield, 0xff, sizeof(bitfield));
+
+  CPPUNIT_ASSERT_EQUAL(0, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+  CPPUNIT_ASSERT(bt1.setUseBit(0));
+  CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+  CPPUNIT_ASSERT(bt1.unsetUseBit(0));
+  CPPUNIT_ASSERT_EQUAL(0, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+  CPPUNIT_ASSERT(bt1.setBit(0));
+  CPPUNIT_ASSERT_EQUAL(1, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+
+  for(int i = 0; i < 8; i++) {
+    CPPUNIT_ASSERT(bt1.setBit(i));
+  }
+  CPPUNIT_ASSERT_EQUAL(8, bt1.getFirstMissingUnusedIndex(bitfield, sizeof(bitfield)));
+
+  CPPUNIT_ASSERT_EQUAL(8, bt1.getFirstMissingUnusedIndex());
+  CPPUNIT_ASSERT(bt1.setUseBit(8));
+  CPPUNIT_ASSERT_EQUAL(9, bt1.getFirstMissingUnusedIndex());
+}
+
+void BitfieldManTest::testIsAllBitSet() {
+  BitfieldMan bt1(1024, 1024*10);
+  CPPUNIT_ASSERT(!bt1.isAllBitSet());
+  bt1.setBit(1);
+  CPPUNIT_ASSERT(!bt1.isAllBitSet());
+  
+  for(int i = 0; i < 8; i++) {
+    CPPUNIT_ASSERT(bt1.setBit(i));
+  }
+  CPPUNIT_ASSERT(!bt1.isAllBitSet());
+
+  for(int i = 0; i < bt1.getBlocks(); i++) {
+    CPPUNIT_ASSERT(bt1.setBit(i));
+  }
+  CPPUNIT_ASSERT(bt1.isAllBitSet());
+}

+ 70 - 0
test/DataTest.cc

@@ -0,0 +1,70 @@
+#include "Data.h"
+#include <string>
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class DataTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(DataTest);
+  CPPUNIT_TEST(testToString);
+  CPPUNIT_TEST(testGetData);
+  CPPUNIT_TEST(testToInt);
+  CPPUNIT_TEST(testToLLInt);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testToString();
+  void testGetData();
+  void testToInt();
+  void testToLLInt();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( DataTest );
+
+void DataTest::testToString() {
+  Data data("aria2", 5);
+  CPPUNIT_ASSERT_EQUAL(string("aria2"), data.toString());
+
+  Data null(NULL, 0);
+  CPPUNIT_ASSERT_EQUAL(string(""), null.toString());
+}
+
+void DataTest::testGetData() {
+  Data data("aria2", 5);
+  int len;
+  CPPUNIT_ASSERT_EQUAL(0, memcmp("aria2", data.getData(), 5));
+  CPPUNIT_ASSERT_EQUAL(5, data.getLen());  
+
+  Data null(NULL, 0);
+  CPPUNIT_ASSERT_EQUAL((const char*)NULL, null.getData());
+  CPPUNIT_ASSERT_EQUAL(0, null.getLen());
+
+}
+
+void DataTest::testToInt() {
+  Data data("1000", 4);
+  CPPUNIT_ASSERT_EQUAL(1000, data.toInt());
+
+  Data null(NULL, 0);
+  CPPUNIT_ASSERT_EQUAL(0, null.toInt());
+
+  Data alpha("abc", 3);
+  CPPUNIT_ASSERT_EQUAL(0, alpha.toInt());
+}
+
+void DataTest::testToLLInt() {
+  Data data("1000", 4);
+  CPPUNIT_ASSERT_EQUAL(1000, (int)data.toLLInt());
+
+  Data null(NULL, 0);
+  CPPUNIT_ASSERT_EQUAL(0, (int)null.toLLInt());
+
+  Data alpha("abc", 3);
+  CPPUNIT_ASSERT_EQUAL(0, (int)alpha.toLLInt());
+}

+ 35 - 0
test/DefaultDiskWriterTest.cc

@@ -0,0 +1,35 @@
+#include "DefaultDiskWriter.h"
+#include <string>
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class DefaultDiskWriterTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(DefaultDiskWriterTest);
+  CPPUNIT_TEST(testSha1Sum);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testSha1Sum();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( DefaultDiskWriterTest );
+
+void DefaultDiskWriterTest::testSha1Sum() {
+  DefaultDiskWriter dw;
+  dw.openExistingFile("4096chunk.txt");
+  
+  CPPUNIT_ASSERT_EQUAL(string("608cabc0f2fa18c260cafd974516865c772363d5"),
+		       dw.sha1Sum(0, 4096));
+
+  CPPUNIT_ASSERT_EQUAL(string("7a4a9ae537ebbbb826b1060e704490ad0f365ead"),
+		       dw.sha1Sum(5, 100));
+
+  dw.closeFile();
+}

+ 35 - 0
test/DictionaryTest.cc

@@ -0,0 +1,35 @@
+#include "Dictionary.h"
+#include "Data.h"
+#include <string>
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class DictionaryTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(DictionaryTest);
+  CPPUNIT_TEST(testGet);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testGet();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( DictionaryTest );
+
+void DictionaryTest::testGet() {
+  Dictionary d;
+  Data* data1 = new Data("aria2", 5);
+  d.put("app_name", data1);
+  Data* data2 = new Data("linux", 5);
+  d.put("platform", data2);
+  Data* dataGot = (Data*)d.get("app_name");
+  CPPUNIT_ASSERT(dataGot != NULL);
+  CPPUNIT_ASSERT_EQUAL(string("aria2"), dataGot->toString());
+}
+

+ 7 - 0
test/FileTest.cc

@@ -14,6 +14,7 @@ class FileTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testIsFile);
   CPPUNIT_TEST(testIsDir);
   CPPUNIT_TEST(testRemove);
+  CPPUNIT_TEST(testSize);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -25,6 +26,7 @@ public:
   void testIsFile();
   void testIsDir();
   void testRemove();
+  void testSize();
 };
 
 
@@ -86,3 +88,8 @@ void FileTest::testRemove() {
   // delete the directory again
   CPPUNIT_ASSERT(!d.remove());
 }
+
+void FileTest::testSize() {
+  File f("4096chunk.txt");
+  CPPUNIT_ASSERT_EQUAL(4096, (int)f.size());
+}

+ 33 - 0
test/ListTest.cc

@@ -0,0 +1,33 @@
+#include "List.h"
+#include "Data.h"
+#include <string>
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class ListTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(ListTest);
+  CPPUNIT_TEST(testAdd);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testAdd();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( ListTest );
+
+void ListTest::testAdd() {
+  List l;
+  Data* data1 = new Data("usr", 3);
+  l.add(data1);
+  Data* data2 = new Data("local", 5);
+  l.add(data2);
+  CPPUNIT_ASSERT_EQUAL(2, (int)l.getList().size());
+}
+

+ 10 - 1
test/Makefile.am

@@ -7,7 +7,16 @@ aria2c_SOURCES = AllTest.cc\
 	OptionTest.cc\
 	Base64Test.cc\
 	UtilTest.cc\
-	CookieBoxTest.cc
+	CookieBoxTest.cc\
+	DataTest.cc\
+	DictionaryTest.cc\
+	ListTest.cc\
+	MetaFileUtilTest.cc\
+	ShaVisitorTest.cc\
+	TorrentManTest.cc\
+	PeerMessageUtilTest.cc\
+	BitfieldManTest.cc\
+	DefaultDiskWriterTest.cc
 aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 aria2c_LDFLAGS = ${CPPUNIT_LIBS}
 aria2c_LDADD = ../src/libaria2c.a

+ 153 - 2
test/Makefile.in

@@ -59,7 +59,14 @@ am_aria2c_OBJECTS = aria2c-AllTest.$(OBJEXT) \
 	aria2c-RequestTest.$(OBJEXT) \
 	aria2c-ChunkedEncodingTest.$(OBJEXT) aria2c-FileTest.$(OBJEXT) \
 	aria2c-OptionTest.$(OBJEXT) aria2c-Base64Test.$(OBJEXT) \
-	aria2c-UtilTest.$(OBJEXT) aria2c-CookieBoxTest.$(OBJEXT)
+	aria2c-UtilTest.$(OBJEXT) aria2c-CookieBoxTest.$(OBJEXT) \
+	aria2c-DataTest.$(OBJEXT) aria2c-DictionaryTest.$(OBJEXT) \
+	aria2c-ListTest.$(OBJEXT) aria2c-MetaFileUtilTest.$(OBJEXT) \
+	aria2c-ShaVisitorTest.$(OBJEXT) \
+	aria2c-TorrentManTest.$(OBJEXT) \
+	aria2c-PeerMessageUtilTest.$(OBJEXT) \
+	aria2c-BitfieldManTest.$(OBJEXT) \
+	aria2c-DefaultDiskWriterTest.$(OBJEXT)
 aria2c_OBJECTS = $(am_aria2c_OBJECTS)
 aria2c_DEPENDENCIES = ../src/libaria2c.a
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
@@ -197,7 +204,16 @@ aria2c_SOURCES = AllTest.cc\
 	OptionTest.cc\
 	Base64Test.cc\
 	UtilTest.cc\
-	CookieBoxTest.cc
+	CookieBoxTest.cc\
+	DataTest.cc\
+	DictionaryTest.cc\
+	ListTest.cc\
+	MetaFileUtilTest.cc\
+	ShaVisitorTest.cc\
+	TorrentManTest.cc\
+	PeerMessageUtilTest.cc\
+	BitfieldManTest.cc\
+	DefaultDiskWriterTest.cc
 
 aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@@ -250,11 +266,20 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-AllTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-Base64Test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-BitfieldManTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-ChunkedEncodingTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-CookieBoxTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-DataTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-DefaultDiskWriterTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-DictionaryTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-FileTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-ListTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-MetaFileUtilTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-OptionTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-PeerMessageUtilTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-RequestTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-ShaVisitorTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-TorrentManTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aria2c-UtilTest.Po@am__quote@
 
 .cc.o:
@@ -382,6 +407,132 @@ aria2c-CookieBoxTest.obj: CookieBoxTest.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='CookieBoxTest.cc' object='aria2c-CookieBoxTest.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-CookieBoxTest.obj `if test -f 'CookieBoxTest.cc'; then $(CYGPATH_W) 'CookieBoxTest.cc'; else $(CYGPATH_W) '$(srcdir)/CookieBoxTest.cc'; fi`
+
+aria2c-DataTest.o: DataTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-DataTest.o -MD -MP -MF "$(DEPDIR)/aria2c-DataTest.Tpo" -c -o aria2c-DataTest.o `test -f 'DataTest.cc' || echo '$(srcdir)/'`DataTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-DataTest.Tpo" "$(DEPDIR)/aria2c-DataTest.Po"; else rm -f "$(DEPDIR)/aria2c-DataTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='DataTest.cc' object='aria2c-DataTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-DataTest.o `test -f 'DataTest.cc' || echo '$(srcdir)/'`DataTest.cc
+
+aria2c-DataTest.obj: DataTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-DataTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-DataTest.Tpo" -c -o aria2c-DataTest.obj `if test -f 'DataTest.cc'; then $(CYGPATH_W) 'DataTest.cc'; else $(CYGPATH_W) '$(srcdir)/DataTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-DataTest.Tpo" "$(DEPDIR)/aria2c-DataTest.Po"; else rm -f "$(DEPDIR)/aria2c-DataTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='DataTest.cc' object='aria2c-DataTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-DataTest.obj `if test -f 'DataTest.cc'; then $(CYGPATH_W) 'DataTest.cc'; else $(CYGPATH_W) '$(srcdir)/DataTest.cc'; fi`
+
+aria2c-DictionaryTest.o: DictionaryTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-DictionaryTest.o -MD -MP -MF "$(DEPDIR)/aria2c-DictionaryTest.Tpo" -c -o aria2c-DictionaryTest.o `test -f 'DictionaryTest.cc' || echo '$(srcdir)/'`DictionaryTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-DictionaryTest.Tpo" "$(DEPDIR)/aria2c-DictionaryTest.Po"; else rm -f "$(DEPDIR)/aria2c-DictionaryTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='DictionaryTest.cc' object='aria2c-DictionaryTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-DictionaryTest.o `test -f 'DictionaryTest.cc' || echo '$(srcdir)/'`DictionaryTest.cc
+
+aria2c-DictionaryTest.obj: DictionaryTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-DictionaryTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-DictionaryTest.Tpo" -c -o aria2c-DictionaryTest.obj `if test -f 'DictionaryTest.cc'; then $(CYGPATH_W) 'DictionaryTest.cc'; else $(CYGPATH_W) '$(srcdir)/DictionaryTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-DictionaryTest.Tpo" "$(DEPDIR)/aria2c-DictionaryTest.Po"; else rm -f "$(DEPDIR)/aria2c-DictionaryTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='DictionaryTest.cc' object='aria2c-DictionaryTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-DictionaryTest.obj `if test -f 'DictionaryTest.cc'; then $(CYGPATH_W) 'DictionaryTest.cc'; else $(CYGPATH_W) '$(srcdir)/DictionaryTest.cc'; fi`
+
+aria2c-ListTest.o: ListTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-ListTest.o -MD -MP -MF "$(DEPDIR)/aria2c-ListTest.Tpo" -c -o aria2c-ListTest.o `test -f 'ListTest.cc' || echo '$(srcdir)/'`ListTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-ListTest.Tpo" "$(DEPDIR)/aria2c-ListTest.Po"; else rm -f "$(DEPDIR)/aria2c-ListTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='ListTest.cc' object='aria2c-ListTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-ListTest.o `test -f 'ListTest.cc' || echo '$(srcdir)/'`ListTest.cc
+
+aria2c-ListTest.obj: ListTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-ListTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-ListTest.Tpo" -c -o aria2c-ListTest.obj `if test -f 'ListTest.cc'; then $(CYGPATH_W) 'ListTest.cc'; else $(CYGPATH_W) '$(srcdir)/ListTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-ListTest.Tpo" "$(DEPDIR)/aria2c-ListTest.Po"; else rm -f "$(DEPDIR)/aria2c-ListTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='ListTest.cc' object='aria2c-ListTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-ListTest.obj `if test -f 'ListTest.cc'; then $(CYGPATH_W) 'ListTest.cc'; else $(CYGPATH_W) '$(srcdir)/ListTest.cc'; fi`
+
+aria2c-MetaFileUtilTest.o: MetaFileUtilTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-MetaFileUtilTest.o -MD -MP -MF "$(DEPDIR)/aria2c-MetaFileUtilTest.Tpo" -c -o aria2c-MetaFileUtilTest.o `test -f 'MetaFileUtilTest.cc' || echo '$(srcdir)/'`MetaFileUtilTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-MetaFileUtilTest.Tpo" "$(DEPDIR)/aria2c-MetaFileUtilTest.Po"; else rm -f "$(DEPDIR)/aria2c-MetaFileUtilTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='MetaFileUtilTest.cc' object='aria2c-MetaFileUtilTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-MetaFileUtilTest.o `test -f 'MetaFileUtilTest.cc' || echo '$(srcdir)/'`MetaFileUtilTest.cc
+
+aria2c-MetaFileUtilTest.obj: MetaFileUtilTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-MetaFileUtilTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-MetaFileUtilTest.Tpo" -c -o aria2c-MetaFileUtilTest.obj `if test -f 'MetaFileUtilTest.cc'; then $(CYGPATH_W) 'MetaFileUtilTest.cc'; else $(CYGPATH_W) '$(srcdir)/MetaFileUtilTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-MetaFileUtilTest.Tpo" "$(DEPDIR)/aria2c-MetaFileUtilTest.Po"; else rm -f "$(DEPDIR)/aria2c-MetaFileUtilTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='MetaFileUtilTest.cc' object='aria2c-MetaFileUtilTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-MetaFileUtilTest.obj `if test -f 'MetaFileUtilTest.cc'; then $(CYGPATH_W) 'MetaFileUtilTest.cc'; else $(CYGPATH_W) '$(srcdir)/MetaFileUtilTest.cc'; fi`
+
+aria2c-ShaVisitorTest.o: ShaVisitorTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-ShaVisitorTest.o -MD -MP -MF "$(DEPDIR)/aria2c-ShaVisitorTest.Tpo" -c -o aria2c-ShaVisitorTest.o `test -f 'ShaVisitorTest.cc' || echo '$(srcdir)/'`ShaVisitorTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-ShaVisitorTest.Tpo" "$(DEPDIR)/aria2c-ShaVisitorTest.Po"; else rm -f "$(DEPDIR)/aria2c-ShaVisitorTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='ShaVisitorTest.cc' object='aria2c-ShaVisitorTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-ShaVisitorTest.o `test -f 'ShaVisitorTest.cc' || echo '$(srcdir)/'`ShaVisitorTest.cc
+
+aria2c-ShaVisitorTest.obj: ShaVisitorTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-ShaVisitorTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-ShaVisitorTest.Tpo" -c -o aria2c-ShaVisitorTest.obj `if test -f 'ShaVisitorTest.cc'; then $(CYGPATH_W) 'ShaVisitorTest.cc'; else $(CYGPATH_W) '$(srcdir)/ShaVisitorTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-ShaVisitorTest.Tpo" "$(DEPDIR)/aria2c-ShaVisitorTest.Po"; else rm -f "$(DEPDIR)/aria2c-ShaVisitorTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='ShaVisitorTest.cc' object='aria2c-ShaVisitorTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-ShaVisitorTest.obj `if test -f 'ShaVisitorTest.cc'; then $(CYGPATH_W) 'ShaVisitorTest.cc'; else $(CYGPATH_W) '$(srcdir)/ShaVisitorTest.cc'; fi`
+
+aria2c-TorrentManTest.o: TorrentManTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-TorrentManTest.o -MD -MP -MF "$(DEPDIR)/aria2c-TorrentManTest.Tpo" -c -o aria2c-TorrentManTest.o `test -f 'TorrentManTest.cc' || echo '$(srcdir)/'`TorrentManTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-TorrentManTest.Tpo" "$(DEPDIR)/aria2c-TorrentManTest.Po"; else rm -f "$(DEPDIR)/aria2c-TorrentManTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentManTest.cc' object='aria2c-TorrentManTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-TorrentManTest.o `test -f 'TorrentManTest.cc' || echo '$(srcdir)/'`TorrentManTest.cc
+
+aria2c-TorrentManTest.obj: TorrentManTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-TorrentManTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-TorrentManTest.Tpo" -c -o aria2c-TorrentManTest.obj `if test -f 'TorrentManTest.cc'; then $(CYGPATH_W) 'TorrentManTest.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentManTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-TorrentManTest.Tpo" "$(DEPDIR)/aria2c-TorrentManTest.Po"; else rm -f "$(DEPDIR)/aria2c-TorrentManTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='TorrentManTest.cc' object='aria2c-TorrentManTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-TorrentManTest.obj `if test -f 'TorrentManTest.cc'; then $(CYGPATH_W) 'TorrentManTest.cc'; else $(CYGPATH_W) '$(srcdir)/TorrentManTest.cc'; fi`
+
+aria2c-PeerMessageUtilTest.o: PeerMessageUtilTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-PeerMessageUtilTest.o -MD -MP -MF "$(DEPDIR)/aria2c-PeerMessageUtilTest.Tpo" -c -o aria2c-PeerMessageUtilTest.o `test -f 'PeerMessageUtilTest.cc' || echo '$(srcdir)/'`PeerMessageUtilTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-PeerMessageUtilTest.Tpo" "$(DEPDIR)/aria2c-PeerMessageUtilTest.Po"; else rm -f "$(DEPDIR)/aria2c-PeerMessageUtilTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerMessageUtilTest.cc' object='aria2c-PeerMessageUtilTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-PeerMessageUtilTest.o `test -f 'PeerMessageUtilTest.cc' || echo '$(srcdir)/'`PeerMessageUtilTest.cc
+
+aria2c-PeerMessageUtilTest.obj: PeerMessageUtilTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-PeerMessageUtilTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-PeerMessageUtilTest.Tpo" -c -o aria2c-PeerMessageUtilTest.obj `if test -f 'PeerMessageUtilTest.cc'; then $(CYGPATH_W) 'PeerMessageUtilTest.cc'; else $(CYGPATH_W) '$(srcdir)/PeerMessageUtilTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-PeerMessageUtilTest.Tpo" "$(DEPDIR)/aria2c-PeerMessageUtilTest.Po"; else rm -f "$(DEPDIR)/aria2c-PeerMessageUtilTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='PeerMessageUtilTest.cc' object='aria2c-PeerMessageUtilTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-PeerMessageUtilTest.obj `if test -f 'PeerMessageUtilTest.cc'; then $(CYGPATH_W) 'PeerMessageUtilTest.cc'; else $(CYGPATH_W) '$(srcdir)/PeerMessageUtilTest.cc'; fi`
+
+aria2c-BitfieldManTest.o: BitfieldManTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-BitfieldManTest.o -MD -MP -MF "$(DEPDIR)/aria2c-BitfieldManTest.Tpo" -c -o aria2c-BitfieldManTest.o `test -f 'BitfieldManTest.cc' || echo '$(srcdir)/'`BitfieldManTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-BitfieldManTest.Tpo" "$(DEPDIR)/aria2c-BitfieldManTest.Po"; else rm -f "$(DEPDIR)/aria2c-BitfieldManTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='BitfieldManTest.cc' object='aria2c-BitfieldManTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-BitfieldManTest.o `test -f 'BitfieldManTest.cc' || echo '$(srcdir)/'`BitfieldManTest.cc
+
+aria2c-BitfieldManTest.obj: BitfieldManTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-BitfieldManTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-BitfieldManTest.Tpo" -c -o aria2c-BitfieldManTest.obj `if test -f 'BitfieldManTest.cc'; then $(CYGPATH_W) 'BitfieldManTest.cc'; else $(CYGPATH_W) '$(srcdir)/BitfieldManTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-BitfieldManTest.Tpo" "$(DEPDIR)/aria2c-BitfieldManTest.Po"; else rm -f "$(DEPDIR)/aria2c-BitfieldManTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='BitfieldManTest.cc' object='aria2c-BitfieldManTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-BitfieldManTest.obj `if test -f 'BitfieldManTest.cc'; then $(CYGPATH_W) 'BitfieldManTest.cc'; else $(CYGPATH_W) '$(srcdir)/BitfieldManTest.cc'; fi`
+
+aria2c-DefaultDiskWriterTest.o: DefaultDiskWriterTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-DefaultDiskWriterTest.o -MD -MP -MF "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Tpo" -c -o aria2c-DefaultDiskWriterTest.o `test -f 'DefaultDiskWriterTest.cc' || echo '$(srcdir)/'`DefaultDiskWriterTest.cc; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Tpo" "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Po"; else rm -f "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='DefaultDiskWriterTest.cc' object='aria2c-DefaultDiskWriterTest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-DefaultDiskWriterTest.o `test -f 'DefaultDiskWriterTest.cc' || echo '$(srcdir)/'`DefaultDiskWriterTest.cc
+
+aria2c-DefaultDiskWriterTest.obj: DefaultDiskWriterTest.cc
+@am__fastdepCXX_TRUE@	if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -MT aria2c-DefaultDiskWriterTest.obj -MD -MP -MF "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Tpo" -c -o aria2c-DefaultDiskWriterTest.obj `if test -f 'DefaultDiskWriterTest.cc'; then $(CYGPATH_W) 'DefaultDiskWriterTest.cc'; else $(CYGPATH_W) '$(srcdir)/DefaultDiskWriterTest.cc'; fi`; \
+@am__fastdepCXX_TRUE@	then mv -f "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Tpo" "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Po"; else rm -f "$(DEPDIR)/aria2c-DefaultDiskWriterTest.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='DefaultDiskWriterTest.cc' object='aria2c-DefaultDiskWriterTest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(aria2c_CXXFLAGS) $(CXXFLAGS) -c -o aria2c-DefaultDiskWriterTest.obj `if test -f 'DefaultDiskWriterTest.cc'; then $(CYGPATH_W) 'DefaultDiskWriterTest.cc'; else $(CYGPATH_W) '$(srcdir)/DefaultDiskWriterTest.cc'; fi`
 uninstall-info-am:
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio