浏览代码

2006-11-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To divide TorrentMan into 6 classes: BtContext, BtRuntime,
	PeerStorage, PieceStorage, BtAnnounce and BtProgressInfoFile

	* src/TrackerWatcherComand.h: Made subclass of 
BtContextAwareCommand.
	* src/SeedCheckCommand.cc: Use pieceStorage, btRuntime
	* src/PeerAbstractCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/PeerAbstractCommand.cc: Use btRuntime.
	* src/BtContextAwareCommand.h: New class.
	* src/FileEntry.h: Added accessor methods for following 
variables.
	(path): Made private.
	(length): Made private.
	(offset): Made private.
	(extracted): Made private.
	(requested): Made private.
	(FileEntries): New definition.
	(FileEntryHandle): New definition.
	* src/FileEntry.cc: New file.
	* src/HaveEraseCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/HaveEraseCommand.cc: Use btRuntime, pieceStorage.
	* src/PeerChokeCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/PeerChokeCommand.cc: Use btRuntime, peerStorage, 
pieceStorage.
	* src/PieceStorage.h: New file.
	* src/PeerInteractionCommand.h: Use btContext.
	* src/PeerInteractionCommand.cc: Use pieceStorage, peerStorage,
	btRuntime.
	* src/DefaultBtProgressInfoFile.h: New file.
	* src/DefaultBtProgressInfoFile.cc: New file.
	* src/File.cc
	(Util.h): New include.
	(mkdirs): New function.
	* src/MultiDiskAdaptor.h
	(mkdir): New function.
	* src/PeerListProcessor.h
	(Peers): Removed.
	* src/PeerInteraction.h
	(torrentMan): Removed.
	(btContext): New variable.
	(peerStorage): New variable.
	(pieceStorage): New variable.
	(btAnnounce): New variable.
	(getTorrentMan): Removed.
	(getBtContext): New function.
	* src/PeerInteraction.cc: Use btContext, peerStorage, 
pieceStorage,
	btAnnounce.
	* src/HandshakeMessage.h
	(TorrentMan.h): Removed.
	* src/HandshakeMessage.cc: Use btContext.
	* src/DefaultBtAnnounce.cc: New file.
	* src/MultiDiskWriter.cc: Use the accessor methods of FileEntry.
	* src/DefaultPieceStorage.cc: New file.
	* src/DefaultBtContext.h: New file.
	* src/TorrentRequestInfo.cc: Use btContext, pieceStorage.
	Use the accessor methods of FileEntry.
	* src/CookieBox.cc: Updated to use Util::slice().
	* src/PieceMessage.cc: Use btContext, pieceStorage.
	* src/common.h (SharedHandle.h): New include.
	* src/PeerMessage.cc (PeerMessage): Added btContext, 
peerStorage,
	pieceStorage.
	* src/TorrentAutoSaveCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/DiskAdaptor.h
	(topDir): Removed.
	(getFileEntryFromPath): Changed the return type to 
FileEntryHandle.
	(setTopDir): Removed.
	(getTopDir): Removed.
	* src/BtContext.h: New file.
	* src/DefaultPeerStorage.h: New file.
	* src/PieceMessage.h (TorrentMan.h): Removed.
	* src/RequestMessage.h (TorrentMan.h): Removed.
	* src/TorrentDownloadEngine.h
	(uploadLength): New variable.
	(btContext): New variable.
	(btRuntime): New variable.
	(pieceStorage): New variable.
	(peerStorage): New variable.
	(btAnnounce): New variable.
	(btProgressInfoFile): New variable.
	(torrentMan): Removed.
	(setBtContext): New function.
	* src/TorrentDownloadEngine.cc: Use BtContext, BtRuntime, 
pieceStorage,
	peerStorage, btAnnounce, btProgressInfoFile.
	* src/Piece.h
	(toString): New function.
	(Pieces): New type definition.
	* src/Peer.h
	(active): New variable.
	(Peer): Added active.
	(activate): Set active to true.
	(deactivate): Set active to false.
	(isActive): New function.
	(Peers): New type definition.
	* src/DirectDiskAdaptor.cc
	(getFilePath): Use the accessor methods of FileEntry.
	* src/TorrentConsoleDownloadEngine.h
	(afterEachIteration): New function.
	* src/TorrentConsoleDownloadEngine.cc
	(haltRequested): New variable.
	(sendStatistics): Use pieceStorage, btRuntime.
	(afterEachIteration): New function.
	* src/AnnounceList: AnnounceTier->AnnounceTierHandle.
	* src/Directry.h
	(Directory): New function.
	(DirectoryHandle): New type definition.
	* src/BtProgressInfoFile.h: New file.
	* src/RequestMessage.cc: Use pieceStorage.
	* src/BtRuntime.h: New file.
	* src/DefaultBtContext.cc: New file.
	* src/BitfieldMan.h
	(getCompletedLength): New function(private).
	(getCompletedLength): New function.
	(getFilteredCompletedLength): New function.
	* src/BitfieldMan.h
	(getCompletedLength): New function(private).
	(getCompletedLength): New function.
	(getFilteredCompletedLength): New function.
	* src/MultiDiskAdaptor.cc
	(mkdir): New function.
	(openFile): Call mkdir().
	(initAndOpenFile): Call mkdir().
	* src/CancelMessage.h
	(TorrentMan.h): Removed.
	* src/RejectMessage.h
	(TorrentMan.h): Removed.
	* src/DownloadEngineFactory.cc
	(DefaultPieceStorage.h): New include.
	(DefaultPeerStorage.h): New include.
	(DefaultBtAnnounce.h): New include.
	(DefaultBtProgressInfoFile.h): New include.
	(newTorrentConsoleEngine): Rewritten.
	* src/ShareRatioSeedCriteria.h
	(torrentMan): Removed.
	(btContext): New variable.
	(peerStorage): New variable.
	(btRuntime): New variable.
	(evaluate): Use btContext, btRuntime, peerStorage.
	* src/AnnounceTier.h: New file.
	* src/BtAnnounce.h: New file.
	* src/BtRegistry.h: New file.
	* src/PeerInitiateConnectionCommand.h: Added btContext.
	* src/PeerConnection.h (TorrentMan.h): Removed.
	* src/PeerMessageFactory.cc: Use btContext, pieceStorage.
	* src/Util.h
	(slice): Added an argument.
	* src/Util.cc
	(slice): Added an argument to control whether trim is made or 
not.
	* src/PeerStorage.h: New file.
	* src/BtRegistry.cc: New file.
	* src/TrackerUpdateCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/CopyDiskAdaptor.cc: Use the accessor methods of FileEntry.
	* src/MultiDiskWriter.h: FileEntry -> FileEntryHandle
	* src/PeerListenCommand.cc: Use btRuntime, peerStorage, 
btContext.
	* src/TorrentRequestInfo.h
	(e): Removed.
	(showFileEntry): Added an argument.
	(getDownloadEngine): Return 0.
	* src/DefaultBtAnnounce.h: New file.
	* src/TorrentAutoSaveCommand.cc: Use btRuntime, 
btProgressInfoFile.
	* src/TrackerWatcherComand.cc: Use btRuntime, btAnnounce,
	* src/PeerMessageFactory.h
	(btContext): New variable.
	(pieceStorage): New variable.
	* src/TrackerUpdateCommand.cc: Use btRuntime, peerStorage, 
btContext,
	btAnnounce.
	* src/DiskAdaptor.cc
	(DiskAdaptor): Removed topDir.
	(~DiskAdaptor): Removed topDir.
	* src/PeerListenCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/SeedCheckCommand.h: Made subclass of 
BtContextAwareCommand.
	* src/File.h (mkdirs): New function.
	* src/DefaultPeerStorage): New file.
	* src/DownloadEngineFactory.h
	(newTorrentConsoleEngine): Use btContext.
	* src/BtContextAwareCommand.cc: New file.
	* src/PeerInitiateConnectionCommand.cc: Use btRuntime, 
peerStorage.
	* src/PeerMessage.h
	(btContext): New variable.
	(peerStorage): New variable.
	(pieceStorage): New variable.
	(setBtContext): New function.
	* src/Directry.cc
	(Directory): New function.
	(createDir): Do nothing if name.size() == 0.
	* src/AnnounceList.h
	(AnnounceTier): Removed. 
	(AnnounceTiers): Removed.
	* src/DefaultPieceStorage.h: New file.
	* src/Piece.cc (toString): New function.
	
	To fix typo:
	
	* src/main.cc (showVersion): Fixed typo.

	To fix compile warning:
	
	* src/DelegatingPeerListProcessor.cc
	(canHandle): Added "return false".
Tatsuhiro Tsujikawa 19 年之前
父节点
当前提交
ec642ad294
共有 100 个文件被更改,包括 3996 次插入447 次删除
  1. 198 0
      ChangeLog
  2. 2 1
      TODO
  3. 20 19
      src/AnnounceList.cc
  4. 1 39
      src/AnnounceList.h
  5. 80 0
      src/AnnounceTier.h
  6. 17 5
      src/BitfieldMan.cc
  7. 7 1
      src/BitfieldMan.h
  8. 111 0
      src/BtAnnounce.h
  9. 84 0
      src/BtContext.h
  10. 48 0
      src/BtContextAwareCommand.cc
  11. 60 0
      src/BtContextAwareCommand.h
  12. 59 0
      src/BtProgressInfoFile.h
  13. 130 0
      src/BtRegistry.cc
  14. 98 0
      src/BtRegistry.h
  15. 94 0
      src/BtRuntime.h
  16. 0 1
      src/CancelMessage.h
  17. 1 1
      src/CookieBox.cc
  18. 6 8
      src/CopyDiskAdaptor.cc
  19. 246 0
      src/DefaultBtAnnounce.cc
  20. 122 0
      src/DefaultBtAnnounce.h
  21. 237 0
      src/DefaultBtContext.cc
  22. 97 0
      src/DefaultBtContext.h
  23. 172 0
      src/DefaultBtProgressInfoFile.cc
  24. 92 0
      src/DefaultBtProgressInfoFile.h
  25. 174 0
      src/DefaultPeerStorage.cc
  26. 90 0
      src/DefaultPeerStorage.h
  27. 433 0
      src/DefaultPieceStorage.cc
  28. 158 0
      src/DefaultPieceStorage.h
  29. 1 0
      src/DelegatingPeerListProcessor.cc
  30. 1 1
      src/DirectDiskAdaptor.cc
  31. 5 0
      src/Directory.cc
  32. 3 0
      src/Directory.h
  33. 8 11
      src/DiskAdaptor.cc
  34. 5 10
      src/DiskAdaptor.h
  35. 57 20
      src/DownloadEngineFactory.cc
  36. 2 2
      src/DownloadEngineFactory.h
  37. 28 0
      src/File.cc
  38. 9 0
      src/File.h
  39. 64 0
      src/FileEntry.cc
  40. 29 6
      src/FileEntry.h
  41. 1 1
      src/HandshakeMessage.cc
  42. 0 1
      src/HandshakeMessage.h
  43. 10 2
      src/HaveEraseCommand.cc
  44. 6 6
      src/HaveEraseCommand.h
  45. 16 3
      src/Makefile.am
  46. 52 18
      src/Makefile.in
  47. 9 2
      src/MultiDiskAdaptor.cc
  48. 1 0
      src/MultiDiskAdaptor.h
  49. 10 10
      src/MultiDiskWriter.cc
  50. 4 4
      src/MultiDiskWriter.h
  51. 11 3
      src/Peer.h
  52. 8 6
      src/PeerAbstractCommand.cc
  53. 4 2
      src/PeerAbstractCommand.h
  54. 13 6
      src/PeerChokeCommand.cc
  55. 7 3
      src/PeerChokeCommand.h
  56. 0 1
      src/PeerConnection.h
  57. 22 8
      src/PeerInitiateConnectionCommand.cc
  58. 5 2
      src/PeerInitiateConnectionCommand.h
  59. 28 22
      src/PeerInteraction.cc
  60. 15 4
      src/PeerInteraction.h
  61. 18 14
      src/PeerInteractionCommand.cc
  62. 2 0
      src/PeerInteractionCommand.h
  63. 0 2
      src/PeerListProcessor.h
  64. 14 9
      src/PeerListenCommand.cc
  65. 6 3
      src/PeerListenCommand.h
  66. 5 1
      src/PeerMessage.cc
  67. 18 1
      src/PeerMessage.h
  68. 20 20
      src/PeerMessageFactory.cc
  69. 5 0
      src/PeerMessageFactory.h
  70. 128 0
      src/PeerStorage.h
  71. 5 0
      src/Piece.cc
  72. 4 0
      src/Piece.h
  73. 18 26
      src/PieceMessage.cc
  74. 0 1
      src/PieceMessage.h
  75. 157 0
      src/PieceStorage.h
  76. 0 1
      src/RejectMessage.h
  77. 1 2
      src/RequestMessage.cc
  78. 0 1
      src/RequestMessage.h
  79. 12 3
      src/SeedCheckCommand.cc
  80. 6 8
      src/SeedCheckCommand.h
  81. 17 6
      src/ShareRatioSeedCriteria.h
  82. 10 4
      src/TorrentAutoSaveCommand.cc
  83. 8 3
      src/TorrentAutoSaveCommand.h
  84. 14 4
      src/TorrentConsoleDownloadEngine.cc
  85. 2 0
      src/TorrentConsoleDownloadEngine.h
  86. 40 31
      src/TorrentDownloadEngine.cc
  87. 16 3
      src/TorrentDownloadEngine.h
  88. 22 20
      src/TorrentRequestInfo.cc
  89. 7 5
      src/TorrentRequestInfo.h
  90. 23 11
      src/TrackerUpdateCommand.cc
  91. 6 3
      src/TrackerUpdateCommand.h
  92. 16 13
      src/TrackerWatcherCommand.cc
  93. 6 3
      src/TrackerWatcherCommand.h
  94. 12 4
      src/Util.cc
  95. 1 1
      src/Util.h
  96. 2 0
      src/common.h
  97. 1 1
      src/main.cc
  98. 8 8
      test/AnnounceListTest.cc
  99. 7 6
      test/BitfieldManTest.cc
  100. 88 0
      test/BtRegistryTest.cc

+ 198 - 0
ChangeLog

@@ -1,3 +1,201 @@
+2006-11-05  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To divide TorrentMan into 6 classes: BtContext, BtRuntime,
+	PeerStorage, PieceStorage, BtAnnounce and BtProgressInfoFile
+
+	* src/TrackerWatcherComand.h: Made subclass of BtContextAwareCommand.
+	* src/SeedCheckCommand.cc: Use pieceStorage, btRuntime
+	* src/PeerAbstractCommand.h: Made subclass of BtContextAwareCommand.
+	* src/PeerAbstractCommand.cc: Use btRuntime.
+	* src/BtContextAwareCommand.h: New class.
+	* src/FileEntry.h: Added accessor methods for following variables.
+	(path): Made private.
+	(length): Made private.
+	(offset): Made private.
+	(extracted): Made private.
+	(requested): Made private.
+	(FileEntries): New definition.
+	(FileEntryHandle): New definition.
+	* src/FileEntry.cc: New file.
+	* src/HaveEraseCommand.h: Made subclass of BtContextAwareCommand.
+	* src/HaveEraseCommand.cc: Use btRuntime, pieceStorage.
+	* src/PeerChokeCommand.h: Made subclass of BtContextAwareCommand.
+	* src/PeerChokeCommand.cc: Use btRuntime, peerStorage, pieceStorage.
+	* src/PieceStorage.h: New file.
+	* src/PeerInteractionCommand.h: Use btContext.
+	* src/PeerInteractionCommand.cc: Use pieceStorage, peerStorage,
+	btRuntime.
+	* src/DefaultBtProgressInfoFile.h: New file.
+	* src/DefaultBtProgressInfoFile.cc: New file.
+	* src/File.cc
+	(Util.h): New include.
+	(mkdirs): New function.
+	* src/MultiDiskAdaptor.h
+	(mkdir): New function.
+	* src/PeerListProcessor.h
+	(Peers): Removed.
+	* src/PeerInteraction.h
+	(torrentMan): Removed.
+	(btContext): New variable.
+	(peerStorage): New variable.
+	(pieceStorage): New variable.
+	(btAnnounce): New variable.
+	(getTorrentMan): Removed.
+	(getBtContext): New function.
+	* src/PeerInteraction.cc: Use btContext, peerStorage, pieceStorage,
+	btAnnounce.
+	* src/HandshakeMessage.h
+	(TorrentMan.h): Removed.
+	* src/HandshakeMessage.cc: Use btContext.
+	* src/DefaultBtAnnounce.cc: New file.
+	* src/MultiDiskWriter.cc: Use the accessor methods of FileEntry.
+	* src/DefaultPieceStorage.cc: New file.
+	* src/DefaultBtContext.h: New file.
+	* src/TorrentRequestInfo.cc: Use btContext, pieceStorage.
+	Use the accessor methods of FileEntry.
+	* src/CookieBox.cc: Updated to use Util::slice().
+	* src/PieceMessage.cc: Use btContext, pieceStorage.
+	* src/common.h (SharedHandle.h): New include.
+	* src/PeerMessage.cc (PeerMessage): Added btContext, peerStorage,
+	pieceStorage.
+	* src/TorrentAutoSaveCommand.h: Made subclass of BtContextAwareCommand.
+	* src/DiskAdaptor.h
+	(topDir): Removed.
+	(getFileEntryFromPath): Changed the return type to FileEntryHandle.
+	(setTopDir): Removed.
+	(getTopDir): Removed.
+	* src/BtContext.h: New file.
+	* src/DefaultPeerStorage.h: New file.
+	* src/PieceMessage.h (TorrentMan.h): Removed.
+	* src/RequestMessage.h (TorrentMan.h): Removed.
+	* src/TorrentDownloadEngine.h
+	(uploadLength): New variable.
+	(btContext): New variable.
+	(btRuntime): New variable.
+	(pieceStorage): New variable.
+	(peerStorage): New variable.
+	(btAnnounce): New variable.
+	(btProgressInfoFile): New variable.
+	(torrentMan): Removed.
+	(setBtContext): New function.
+	* src/TorrentDownloadEngine.cc: Use BtContext, BtRuntime, pieceStorage,
+	peerStorage, btAnnounce, btProgressInfoFile.
+	* src/Piece.h
+	(toString): New function.
+	(Pieces): New type definition.
+	* src/Peer.h
+	(active): New variable.
+	(Peer): Added active.
+	(activate): Set active to true.
+	(deactivate): Set active to false.
+	(isActive): New function.
+	(Peers): New type definition.
+	* src/DirectDiskAdaptor.cc
+	(getFilePath): Use the accessor methods of FileEntry.
+	* src/TorrentConsoleDownloadEngine.h
+	(afterEachIteration): New function.
+	* src/TorrentConsoleDownloadEngine.cc
+	(haltRequested): New variable.
+	(sendStatistics): Use pieceStorage, btRuntime.
+	(afterEachIteration): New function.
+	* src/AnnounceList: AnnounceTier->AnnounceTierHandle.
+	* src/Directry.h
+	(Directory): New function.
+	(DirectoryHandle): New type definition.
+	* src/BtProgressInfoFile.h: New file.
+	* src/RequestMessage.cc: Use pieceStorage.
+	* src/BtRuntime.h: New file.
+	* src/DefaultBtContext.cc: New file.
+	* src/BitfieldMan.h
+	(getCompletedLength): New function(private).
+	(getCompletedLength): New function.
+	(getFilteredCompletedLength): New function.
+	* src/BitfieldMan.h
+	(getCompletedLength): New function(private).
+	(getCompletedLength): New function.
+	(getFilteredCompletedLength): New function.
+	* src/MultiDiskAdaptor.cc
+	(mkdir): New function.
+	(openFile): Call mkdir().
+	(initAndOpenFile): Call mkdir().
+	* src/CancelMessage.h
+	(TorrentMan.h): Removed.
+	* src/RejectMessage.h
+	(TorrentMan.h): Removed.
+	* src/DownloadEngineFactory.cc
+	(DefaultPieceStorage.h): New include.
+	(DefaultPeerStorage.h): New include.
+	(DefaultBtAnnounce.h): New include.
+	(DefaultBtProgressInfoFile.h): New include.
+	(newTorrentConsoleEngine): Rewritten.
+	* src/ShareRatioSeedCriteria.h
+	(torrentMan): Removed.
+	(btContext): New variable.
+	(peerStorage): New variable.
+	(btRuntime): New variable.
+	(evaluate): Use btContext, btRuntime, peerStorage.
+	* src/AnnounceTier.h: New file.
+	* src/BtAnnounce.h: New file.
+	* src/BtRegistry.h: New file.
+	* src/PeerInitiateConnectionCommand.h: Added btContext.
+	* src/PeerConnection.h (TorrentMan.h): Removed.
+	* src/PeerMessageFactory.cc: Use btContext, pieceStorage.
+	* src/Util.h
+	(slice): Added an argument.
+	* src/Util.cc
+	(slice): Added an argument to control whether trim is made or not.
+	* src/PeerStorage.h: New file.
+	* src/BtRegistry.cc: New file.
+	* src/TrackerUpdateCommand.h: Made subclass of BtContextAwareCommand.
+	* src/CopyDiskAdaptor.cc: Use the accessor methods of FileEntry.
+	* src/MultiDiskWriter.h: FileEntry -> FileEntryHandle
+	* src/PeerListenCommand.cc: Use btRuntime, peerStorage, btContext.
+	* src/TorrentRequestInfo.h
+	(e): Removed.
+	(showFileEntry): Added an argument.
+	(getDownloadEngine): Return 0.
+	* src/DefaultBtAnnounce.h: New file.
+	* src/TorrentAutoSaveCommand.cc: Use btRuntime, btProgressInfoFile.
+	* src/TrackerWatcherComand.cc: Use btRuntime, btAnnounce,
+	* src/PeerMessageFactory.h
+	(btContext): New variable.
+	(pieceStorage): New variable.
+	* src/TrackerUpdateCommand.cc: Use btRuntime, peerStorage, btContext,
+	btAnnounce.
+	* src/DiskAdaptor.cc
+	(DiskAdaptor): Removed topDir.
+	(~DiskAdaptor): Removed topDir.
+	* src/PeerListenCommand.h: Made subclass of BtContextAwareCommand.
+	* src/SeedCheckCommand.h: Made subclass of BtContextAwareCommand.
+	* src/File.h (mkdirs): New function.
+	* src/DefaultPeerStorage): New file.
+	* src/DownloadEngineFactory.h
+	(newTorrentConsoleEngine): Use btContext.
+	* src/BtContextAwareCommand.cc: New file.
+	* src/PeerInitiateConnectionCommand.cc: Use btRuntime, peerStorage.
+	* src/PeerMessage.h
+	(btContext): New variable.
+	(peerStorage): New variable.
+	(pieceStorage): New variable.
+	(setBtContext): New function.
+	* src/Directry.cc
+	(Directory): New function.
+	(createDir): Do nothing if name.size() == 0.
+	* src/AnnounceList.h
+	(AnnounceTier): Removed. 
+	(AnnounceTiers): Removed.
+	* src/DefaultPieceStorage.h: New file.
+	* src/Piece.cc (toString): New function.
+	
+	To fix typo:
+	
+	* src/main.cc (showVersion): Fixed typo.
+
+	To fix compile warning:
+	
+	* src/DelegatingPeerListProcessor.cc
+	(canHandle): Added "return false".
+	
 2006-10-20  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	To simplify TrackerWatherCommand, TrackerUpdateCommand and

+ 2 - 1
TODO

@@ -19,4 +19,5 @@
 * Use SharedHandle where it is useful.
 * Add support for "announce-list".
 * Rewrite Util::countBit
-* Add the ability to display filename or URL to be downloaded in metalink mode. 
+* Add the ability to display filename or URL to be downloaded in metalink mode. 
+* Add Turkish translation.

+ 20 - 19
src/AnnounceList.cc

@@ -59,7 +59,7 @@ void AnnounceList::reconfigure(const MetaEntry* announceListEntry) {
 	urls.push_back(data->toString());
       }
       if(urls.size()) {
-	AnnounceTier tier(urls);
+	AnnounceTierHandle tier(new AnnounceTier(urls));
 	tiers.push_back(tier);
       }
     }
@@ -70,14 +70,14 @@ void AnnounceList::reconfigure(const MetaEntry* announceListEntry) {
 void AnnounceList::reconfigure(const string& url) {
   Strings urls;
   urls.push_back(url);
-  tiers.push_back(AnnounceTier(urls));
+  tiers.push_back(AnnounceTierHandle(new AnnounceTier(urls)));
   resetIterator();
 }
 
 void AnnounceList::resetIterator() {
   currentTier = tiers.begin();
-  if(currentTier != tiers.end() && currentTier->urls.size()) {
-    currentTracker = currentTier->urls.begin();
+  if(currentTier != tiers.end() && (*currentTier)->urls.size()) {
+    currentTracker = (*currentTier)->urls.begin();
     currentTrackerInitialized = true;
   } else {
     currentTrackerInitialized = false;
@@ -94,31 +94,31 @@ string AnnounceList::getAnnounce() const {
 
 void AnnounceList::announceSuccess() {
   if(currentTrackerInitialized) {
-    currentTier->nextEvent();
+    (*currentTier)->nextEvent();
     string url = *currentTracker;
-    currentTier->urls.erase(currentTracker);
-    currentTier->urls.push_front(url);
+    (*currentTier)->urls.erase(currentTracker);
+    (*currentTier)->urls.push_front(url);
     currentTier = tiers.begin();
-    currentTracker = currentTier->urls.begin();
+    currentTracker = (*currentTier)->urls.begin();
   }
 }
 
 void AnnounceList::announceFailure() {
   if(currentTrackerInitialized) {
     currentTracker++;
-    if(currentTracker == currentTier->urls.end()) {
+    if(currentTracker == (*currentTier)->urls.end()) {
       currentTier++;
       if(currentTier == tiers.end()) {
 	currentTier = tiers.begin();
       }
-      currentTracker = currentTier->urls.begin();
+      currentTracker = (*currentTier)->urls.begin();
     }
   }
 }
 
 AnnounceTier::AnnounceEvent AnnounceList::getEvent() const {
   if(currentTrackerInitialized) {
-    return currentTier->event;
+    return (*currentTier)->event;
   } else {
     return AnnounceTier::STARTED;
   }
@@ -126,13 +126,13 @@ AnnounceTier::AnnounceEvent AnnounceList::getEvent() const {
 
 void AnnounceList::setEvent(AnnounceTier::AnnounceEvent event) {
   if(currentTrackerInitialized) {
-    currentTier->event = event;
+    (*currentTier)->event = event;
   }
 }
 
 string AnnounceList::getEventString() const {
   if(currentTrackerInitialized) {
-    switch(currentTier->event) {
+    switch((*currentTier)->event) {
     case AnnounceTier::STARTED:
     case AnnounceTier::STARTED_AFTER_COMPLETION:
       return "started";
@@ -150,8 +150,8 @@ string AnnounceList::getEventString() const {
 
 class FindStoppedAllowedTier {
 public:
-  bool operator()(const AnnounceTier& tier) const {
-    switch(tier.event) {
+  bool operator()(const AnnounceTierHandle& tier) const {
+    switch(tier->event) {
     case AnnounceTier::DOWNLOADING:
     case AnnounceTier::STOPPED:
     case AnnounceTier::COMPLETED:
@@ -165,8 +165,8 @@ public:
 
 class FindCompletedAllowedTier {
 public:
-  bool operator()(const AnnounceTier& tier) const {
-    switch(tier.event) {
+  bool operator()(const AnnounceTierHandle& tier) const {
+    switch(tier->event) {
     case AnnounceTier::DOWNLOADING:
     case AnnounceTier::COMPLETED:
       return true;
@@ -187,7 +187,7 @@ int AnnounceList::countCompletedAllowedTier() const {
 void AnnounceList::setCurrentTier(const AnnounceTiers::iterator& itr) {
   if(itr != tiers.end()) {
     currentTier = itr;
-    currentTracker = currentTier->urls.begin();
+    currentTracker = (*currentTier)->urls.begin();
   }
 }
 
@@ -220,6 +220,7 @@ void AnnounceList::moveToCompletedAllowedTier() {
 void AnnounceList::shuffle() {
   for(AnnounceTiers::iterator itr = tiers.begin();
       itr != tiers.end(); itr++) {
-    random_shuffle(itr->urls.begin(), itr->urls.end());
+    Strings& urls = (*itr)->urls;
+    random_shuffle(urls.begin(), urls.end());
   }
 }

+ 1 - 39
src/AnnounceList.h

@@ -37,45 +37,7 @@
 
 #include "common.h"
 #include "MetaEntry.h"
-
-class AnnounceTier {
-public:
-  enum AnnounceEvent {
-    STARTED,
-    STARTED_AFTER_COMPLETION,
-    DOWNLOADING,
-    STOPPED,
-    COMPLETED,
-    SEEDING,
-    HALTED
-  };
-
-  AnnounceEvent event;
-  Strings urls;
-
-  AnnounceTier(const Strings& urls):event(STARTED), urls(urls) {}
-
-  void nextEvent() {
-    switch(event) {
-    case STARTED:
-      event = DOWNLOADING;
-      break;
-    case STARTED_AFTER_COMPLETION:
-      event = SEEDING;
-      break;
-    case STOPPED:
-      event = HALTED;
-      break;
-    case COMPLETED:
-      event = SEEDING;
-      break;
-    default:
-      break;
-    }
-  }
-};
-
-typedef deque<AnnounceTier> AnnounceTiers;
+#include "AnnounceTier.h"
 
 class AnnounceList {
 public:

+ 80 - 0
src/AnnounceTier.h

@@ -0,0 +1,80 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_ANNOUNCE_TIER_H_
+#define _D_ANNOUNCE_TIER_H_
+
+#include "common.h"
+
+class AnnounceTier {
+public:
+  enum AnnounceEvent {
+    STARTED,
+    STARTED_AFTER_COMPLETION,
+    DOWNLOADING,
+    STOPPED,
+    COMPLETED,
+    SEEDING,
+    HALTED
+  };
+
+  AnnounceEvent event;
+  Strings urls;
+
+  AnnounceTier(const Strings& urls):event(STARTED), urls(urls) {}
+
+  void nextEvent() {
+    switch(event) {
+    case STARTED:
+      event = DOWNLOADING;
+      break;
+    case STARTED_AFTER_COMPLETION:
+      event = SEEDING;
+      break;
+    case STOPPED:
+      event = HALTED;
+      break;
+    case COMPLETED:
+      event = SEEDING;
+      break;
+    default:
+      break;
+    }
+  }
+};
+
+typedef SharedHandle<AnnounceTier> AnnounceTierHandle;
+typedef deque<AnnounceTierHandle> AnnounceTiers;
+
+#endif // _D_ANNOUNCE_TIER_H_

+ 17 - 5
src/BitfieldMan.cc

@@ -510,13 +510,17 @@ long long int BitfieldMan::getFilteredTotalLength() const {
   }
 }
 
-long long int BitfieldMan::getCompletedLength() const {
+long long int BitfieldMan::getCompletedLength(bool useFilter) const {
   unsigned char* temp = new unsigned char[bitfieldLength];
-  for(int i = 0; i < bitfieldLength; i++) {
-    temp[i] = bitfield[i];
-    if(filterEnabled) {
-      temp[i] &= filterBitfield[i];
+  if(useFilter) {
+    for(int i = 0; i < bitfieldLength; i++) {
+      temp[i] = bitfield[i];
+      if(filterEnabled) {
+	temp[i] &= filterBitfield[i];
+      }
     }
+  } else {
+    memcpy(temp, bitfield, bitfieldLength);
   }
   int completedBlocks = countSetBit(temp, bitfieldLength);
   long long int completedLength = 0;
@@ -532,3 +536,11 @@ long long int BitfieldMan::getCompletedLength() const {
   delete [] temp;
   return completedLength;
 }
+
+long long int BitfieldMan::getCompletedLength() const {
+  return getCompletedLength(false);
+}
+
+long long int BitfieldMan::getFilteredCompletedLength() const {
+  return getCompletedLength(true);
+}

+ 7 - 1
src/BitfieldMan.h

@@ -59,6 +59,8 @@ private:
 
   int getStartIndex(int index) const;
   int getEndIndex(int index) const;
+
+  long long int getCompletedLength(bool useFilter) const;
 public:
   BitfieldMan(int blockLength, long long int totalLength);
   BitfieldMan(const BitfieldMan& bitfieldMan);
@@ -191,11 +193,15 @@ public:
   void enableFilter();
   void disableFilter();
   bool isFilterEnabled() const;
-  long long int getFilteredTotalLength() const;
   /**
    * affected by filter
    */
+  long long int getFilteredTotalLength() const;
   long long int getCompletedLength() const;
+  /**
+   * affected by filter
+   */
+  long long int getFilteredCompletedLength() const;
 };
 
 #endif // _D_BITFIELD_MAN_H_

+ 111 - 0
src/BtAnnounce.h

@@ -0,0 +1,111 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_ANNOUNCE_H_
+#define _D_BT_ANNOUNCE_H_
+
+#include "common.h"
+
+class BtAnnounce {
+public:
+  virtual ~BtAnnounce() {}
+
+  /**
+   * Returns true if announce is required.
+   * Otherwise returns false.
+   *
+   * There are 4 announce timings:
+   * 1) started: when a download just started.
+   * 2) stopped: when the client quits.
+   * 3) completed: when a download just completed.
+   * 4) When a certain amount of time, aka announce interval, specified by
+   *    a tracker, is elapsed.
+   */
+  virtual bool isAnnounceReady() = 0;
+
+  /**
+   * Returns announe URL with all necessary parameters included.
+   */
+  virtual string getAnnounceUrl() = 0;
+
+  /**
+   * Tells that the announce process has just started.
+   */
+  virtual void announceStart() = 0;
+
+  /**
+   * Tells that the announce succeeded.
+   */
+  virtual void announceSuccess() = 0;
+
+  /**
+   * Tells that the announce failed.
+   */
+  virtual void announceFailure() = 0;
+
+  /**
+   * Returns true if all announce attempt failed.
+   */
+  virtual bool isAllAnnounceFailed() = 0;
+
+  /**
+   * Resets announce status.
+   */
+  virtual void resetAnnounce() = 0;
+
+  /**
+   * Processes the repsponse from the tracker.
+   */
+  virtual void processAnnounceResponse(const char* trackerResponse,
+				       size_t trackerResponseLength) = 0;
+
+  /**
+   * Returns true if no more announce is needed.
+   */
+  virtual bool noMoreAnnounce() = 0;
+
+  /**
+   * Shuffles the URLs in each announce tier.
+   */
+  virtual void shuffleAnnounce() = 0;
+
+  /**
+   * Returns the peer id of the client.
+   */
+  virtual string getPeerId() = 0;
+};
+
+typedef SharedHandle<BtAnnounce> BtAnnounceHandle;
+
+#endif // _D_BT_ANNOUNCE_H_

+ 84 - 0
src/BtContext.h

@@ -0,0 +1,84 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_CONTEXT_H_
+#define _D_BT_CONTEXT_H_
+
+#include "common.h"
+#include "FileEntry.h"
+#include "AnnounceTier.h"
+
+#define INFO_HASH_LENGTH 20
+#define MAX_PEER_ERROR 5
+#define MAX_PEERS 55
+
+typedef deque<AnnounceTierHandle> AnnounceTiers;
+
+class BtContext {
+public:
+  virtual ~BtContext() {}
+
+  enum FILE_MODE {
+    SINGLE,
+    MULTI
+  };
+
+  virtual const unsigned char* getInfoHash() const = 0;
+
+  virtual int getInfoHashLength() const = 0;
+
+  virtual string getInfoHashAsString() const = 0;
+
+  virtual string getPieceHash(int index) const = 0;
+  
+  virtual long long int getTotalLength() const = 0;
+
+  virtual FILE_MODE getFileMode() const = 0;
+
+  virtual FileEntries getFileEntries() const = 0;
+
+  virtual AnnounceTiers getAnnounceTiers() const = 0;
+
+  virtual void load(const string& torrentFile) = 0;
+
+  virtual string getName() const = 0;
+  
+  virtual int getPieceLength() const = 0;
+
+  virtual int getNumPieces() const = 0;
+};
+
+typedef SharedHandle<BtContext> BtContextHandle;
+
+#endif // _D_BT_CONTEXT_H_

+ 48 - 0
src/BtContextAwareCommand.cc

@@ -0,0 +1,48 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "BtContextAwareCommand.h"
+#include "BtRegistry.h"
+
+BtContextAwareCommand::BtContextAwareCommand(int cuid,
+					     const BtContextHandle& btContext):
+  Command(cuid),
+  btContext(btContext),
+  btRuntime(BT_RUNTIME(btContext)),
+  pieceStorage(PIECE_STORAGE(btContext)),
+  peerStorage(PEER_STORAGE(btContext)),
+  btAnnounce(BT_ANNOUNCE(btContext)),
+  btProgressInfoFile(BT_PROGRESS_INFO_FILE(btContext)) {}
+
+BtContextAwareCommand::~BtContextAwareCommand() {}

+ 60 - 0
src/BtContextAwareCommand.h

@@ -0,0 +1,60 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_CONTEXT_AWARE_COMMAND_H_
+#define _D_BT_CONTEXT_AWARE_COMMAND_H_
+
+#include "Command.h"
+#include "BtContext.h"
+#include "BtRuntime.h"
+#include "PieceStorage.h"
+#include "PeerStorage.h"
+#include "BtAnnounce.h"
+#include "BtProgressInfoFile.h"
+
+class BtContextAwareCommand : public Command {
+protected:
+  BtContextHandle btContext;
+  BtRuntimeHandle btRuntime;
+  PieceStorageHandle pieceStorage;
+  PeerStorageHandle peerStorage;
+  BtAnnounceHandle btAnnounce;
+  BtProgressInfoFileHandle btProgressInfoFile;
+public:
+  BtContextAwareCommand(int cuid, const BtContextHandle& btContext);
+
+  virtual ~BtContextAwareCommand();
+};
+
+#endif // _D_BT_CONTEXT_AWARE_COMMAND_H_

+ 59 - 0
src/BtProgressInfoFile.h

@@ -0,0 +1,59 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_PROGRESS_INFO_FILE_H_
+#define _D_BT_PROGRESS_INFO_FILE_H_
+
+#include "common.h"
+
+class BtProgressInfoFile {
+public:
+  virtual ~BtProgressInfoFile() {}
+
+  virtual string getFilename() = 0;
+
+  virtual void setFilename(const string& filename) = 0;
+
+  virtual bool exists() = 0;
+
+  virtual void save() = 0;
+
+  virtual void load() = 0;
+
+  virtual void removeFile() = 0;
+};
+
+typedef SharedHandle<BtProgressInfoFile> BtProgressInfoFileHandle;
+
+#endif // _D_BT_PROGRESS_INFO_FILE_H_

+ 130 - 0
src/BtRegistry.cc

@@ -0,0 +1,130 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "BtRegistry.h"
+#include "DlAbortEx.h"
+
+PeerStorageMap BtRegistry::peerStorageMap;
+PieceStorageMap BtRegistry::pieceStorageMap;
+BtAnnounceMap BtRegistry::btAnnounceMap;
+BtRuntimeMap BtRegistry::btRuntimeMap;
+BtProgressInfoFileMap BtRegistry::btProgressInfoFileMap;
+
+PeerStorageHandle BtRegistry::getPeerStorage(const string& key) {
+  PeerStorageMap::iterator itr = peerStorageMap.find(key);
+  if(itr == peerStorageMap.end()) {
+    return PeerStorageHandle(0);
+  } else {
+    return itr->second;
+  }
+}
+
+bool BtRegistry::registerPeerStorage(const string& key,
+				     const PeerStorageHandle& peerStorage) {
+  PeerStorageMap::value_type p(key, peerStorage);
+  pair<PeerStorageMap::iterator, bool> retval = peerStorageMap.insert(p);
+  return retval.second;
+}
+				  
+PieceStorageHandle
+BtRegistry::getPieceStorage(const string& key) {
+  PieceStorageMap::iterator itr = pieceStorageMap.find(key);
+  if(itr == pieceStorageMap.end()) {
+    return PieceStorageHandle(0);
+  } else {
+    return itr->second;
+  }
+}
+
+bool
+BtRegistry::registerPieceStorage(const string& key,
+				 const PieceStorageHandle& pieceStorage) {
+  PieceStorageMap::value_type p(key, pieceStorage);
+  pair<PieceStorageMap::iterator, bool> retval = pieceStorageMap.insert(p);
+  return retval.second;
+}
+
+BtRuntimeHandle BtRegistry::getBtRuntime(const string& key) {
+  BtRuntimeMap::iterator itr = btRuntimeMap.find(key);
+  if(itr == btRuntimeMap.end()) {
+    return BtRuntimeHandle(0);
+  } else {
+    return itr->second;
+  }
+}
+
+bool
+BtRegistry::registerBtRuntime(const string& key,
+			      const BtRuntimeHandle& btRuntime) {
+  BtRuntimeMap::value_type p(key, btRuntime);
+  pair<BtRuntimeMap::iterator, bool> retval =
+    btRuntimeMap.insert(p);
+  return retval.second;
+}
+
+BtAnnounceHandle BtRegistry::getBtAnnounce(const string& key) {
+  BtAnnounceMap::iterator itr = btAnnounceMap.find(key);
+  if(itr == btAnnounceMap.end()) {
+    return BtAnnounceHandle(0);
+  } else {
+    return itr->second;
+  }
+}
+
+bool
+BtRegistry::registerBtAnnounce(const string& key,
+			       const BtAnnounceHandle& btAnnounce) {
+  BtAnnounceMap::value_type p(key, btAnnounce);
+  pair<BtAnnounceMap::iterator, bool> retval =
+    btAnnounceMap.insert(p);
+  return retval.second;
+}
+
+BtProgressInfoFileHandle BtRegistry::getBtProgressInfoFile(const string& key) {
+  BtProgressInfoFileMap::iterator itr = btProgressInfoFileMap.find(key);
+  if(itr == btProgressInfoFileMap.end()) {
+    return BtProgressInfoFileHandle(0);
+  } else {
+    return itr->second;
+  }
+}
+
+bool
+BtRegistry::registerBtProgressInfoFile(const string& key,
+				       const BtProgressInfoFileHandle& btProgressInfoFile) {
+  BtProgressInfoFileMap::value_type p(key, btProgressInfoFile);
+  pair<BtProgressInfoFileMap::iterator, bool> retval =
+    btProgressInfoFileMap.insert(p);
+  return retval.second;
+}

+ 98 - 0
src/BtRegistry.h

@@ -0,0 +1,98 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_REGISTRY_H_
+#define _D_BT_REGISTRY_H_
+
+#include "common.h"
+#include "PeerStorage.h"
+#include "PieceStorage.h"
+#include "BtAnnounce.h"
+#include "BtRuntime.h"
+#include "BtProgressInfoFile.h"
+#include <map>
+
+typedef map<string, PeerStorageHandle> PeerStorageMap;
+typedef map<string, PieceStorageHandle> PieceStorageMap;
+typedef map<string, BtAnnounceHandle> BtAnnounceMap;
+typedef map<string, BtRuntimeHandle> BtRuntimeMap;
+typedef map<string, BtProgressInfoFileHandle> BtProgressInfoFileMap;
+
+class BtRegistry {
+private:
+  BtRegistry() {}
+
+  static PeerStorageMap peerStorageMap;
+  static PieceStorageMap pieceStorageMap;
+  static BtAnnounceMap btAnnounceMap;
+  static BtRuntimeMap btRuntimeMap;
+  static BtProgressInfoFileMap btProgressInfoFileMap;
+public:
+  static PeerStorageHandle getPeerStorage(const string& key);
+  static bool registerPeerStorage(const string& key,
+				  const PeerStorageHandle& peer);
+				  
+  static PieceStorageHandle getPieceStorage(const string& key);
+  static bool registerPieceStorage(const string& key,
+				   const PieceStorageHandle& pieceStorage);
+
+  static BtRuntimeHandle getBtRuntime(const string& key);
+  static bool registerBtRuntime(const string& key,
+				const BtRuntimeHandle& btRuntime);
+
+  static BtAnnounceHandle getBtAnnounce(const string& key);
+  static bool registerBtAnnounce(const string& key,
+				 const BtAnnounceHandle& btAnnounce);
+
+  static BtProgressInfoFileHandle getBtProgressInfoFile(const string& key);
+  static bool registerBtProgressInfoFile(const string& key,
+					 const BtProgressInfoFileHandle& btProgressInfoFile);
+};
+
+#define PEER_STORAGE(btContext) \
+BtRegistry::getPeerStorage(btContext->getInfoHashAsString())
+
+#define PIECE_STORAGE(btContext) \
+BtRegistry::getPieceStorage(btContext->getInfoHashAsString())
+
+#define BT_ANNOUNCE(btContext) \
+BtRegistry::getBtAnnounce(btContext->getInfoHashAsString())
+
+#define BT_RUNTIME(btContext) \
+BtRegistry::getBtRuntime(btContext->getInfoHashAsString())
+
+#define BT_PROGRESS_INFO_FILE(btContext) \
+BtRegistry::getBtProgressInfoFile(btContext->getInfoHashAsString())
+
+#endif // _D_BT_REGISTRY_H_

+ 94 - 0
src/BtRuntime.h

@@ -0,0 +1,94 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_RUNTIME_H_
+#define _D_BT_RUNTIME_H_
+
+#include "common.h"
+#include "SharedHandle.h"
+
+#define MIN_PEERS 15
+
+class BtRuntime {
+private:
+  long long int uploadLengthAtStartup;
+  int port;
+  bool halt;
+  int connections;
+  int cuidCounter;
+public:
+  BtRuntime():
+    uploadLengthAtStartup(0),
+    port(0),
+    halt(false),
+    connections(0),
+    cuidCounter(0) {}
+  ~BtRuntime() {}
+
+  long long int getUploadLengthAtStartup() const {
+    return uploadLengthAtStartup;
+  }
+
+  void setUploadLengthAtStartup(long long int length) {
+    this->uploadLengthAtStartup = length;
+  }
+
+  void setListenPort(int port) {
+    this->port = port;
+  }
+
+  int getListenPort() const { return port; }
+
+  bool isHalt() const { return halt; }
+
+  void setHalt(bool halt) {
+    this->halt = halt;
+  }
+
+  int getConnections() const { return connections; }
+
+  void increaseConnections() { connections++; }
+
+  void decreaseConnections() { connections--; }
+
+  bool lessThanMinPeer() const { return connections < MIN_PEERS; }
+
+  bool lessThanEqMinPeer() const { return connections <= MIN_PEERS; }
+  
+  int getNewCuid() { return ++cuidCounter; }
+};
+
+typedef SharedHandle<BtRuntime> BtRuntimeHandle;
+
+#endif // _D_BT_RUNTIME_H_

+ 0 - 1
src/CancelMessage.h

@@ -36,7 +36,6 @@
 #define _D_CANCEL_MESSAGE_H_
 
 #include "SimplePeerMessage.h"
-#include "TorrentMan.h"
 
 class CancelMessage : public SimplePeerMessage {
 private:

+ 1 - 1
src/CookieBox.cc

@@ -68,7 +68,7 @@ void CookieBox::setField(Cookie& cookie, const string& name, const string& value
 void CookieBox::parse(Cookie& cookie, const string& cookieStr) const {
   cookie.clear();
   Strings terms;
-  Util::slice(terms, cookieStr, ';');
+  Util::slice(terms, cookieStr, ';', true);
   for(Strings::iterator itr = terms.begin(); itr != terms.end(); itr++) {
     pair<string, string> nv;
     Util::split(nv, *itr, '=');

+ 6 - 8
src/CopyDiskAdaptor.cc

@@ -46,19 +46,17 @@ void CopyDiskAdaptor::onDownloadComplete() {
 }
 
 void CopyDiskAdaptor::fixFilename() {
-  if(topDir != NULL) {
-    topDir->createDir(storeDir, true);
-  }
   long long int offset = 0;
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
-    if(!itr->extracted && itr->requested) {
-      string dest = storeDir+"/"+itr->path;
+    if(!(*itr)->isExtracted() && (*itr)->isRequested()) {
+      (*itr)->setupDir(storeDir);
+      string dest = storeDir+"/"+(*itr)->getPath();
       logger->info("writing file %s", dest.c_str());
-      Util::rangedFileCopy(dest, getFilePath(), offset, itr->length);
-      itr->extracted = true;
+      Util::rangedFileCopy(dest, getFilePath(), offset, (*itr)->getLength());
+      (*itr)->setExtracted(true);
     }
-    offset += itr->length;
+    offset += (*itr)->getLength();
   }
 }
 

+ 246 - 0
src/DefaultBtAnnounce.cc

@@ -0,0 +1,246 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "DefaultBtAnnounce.h"
+#include "BtRegistry.h"
+#include "LogFactory.h"
+#include "MetaFileUtil.h"
+#include "Dictionary.h"
+#include "List.h"
+#include "Data.h"
+#include "DelegatingPeerListProcessor.h"
+#include "Util.h"
+#include "prefs.h"
+#include "DlAbortEx.h"
+#include "message.h"
+
+DefaultBtAnnounce::DefaultBtAnnounce(BtContextHandle btContext,
+				     const Option* option):
+  btContext(btContext),
+  trackers(0),
+  interval(DEFAULT_ANNOUNCE_INTERVAL),
+  minInterval(DEFAULT_ANNOUNCE_INTERVAL),
+  complete(0),
+  incomplete(0),
+  announceList(btContext->getAnnounceTiers()),
+  trackerNumTry(0),
+  option(option),
+  btRuntime(BT_RUNTIME(btContext)),
+  pieceStorage(PIECE_STORAGE(btContext)),
+  peerStorage(PEER_STORAGE(btContext))
+{
+  prevAnnounceTime.setTimeInSec(0);
+  key = generateKey();
+  peerId = generatePeerId();
+  logger = LogFactory::getInstance();
+}
+
+DefaultBtAnnounce::~DefaultBtAnnounce() {
+}
+
+string DefaultBtAnnounce::generateKey() const {
+  return Util::randomAlpha(8);
+}
+
+string DefaultBtAnnounce::generatePeerId() const {
+  string peerId = "-aria2-";
+  peerId += Util::randomAlpha(20-peerId.size());
+  return peerId;
+}
+
+bool DefaultBtAnnounce::isDefaultAnnounceReady() {
+  return (trackers == 0 && prevAnnounceTime.elapsed(minInterval));
+}
+
+bool DefaultBtAnnounce::isStoppedAnnounceReady() {
+  return (trackers == 0 &&
+	  btRuntime->isHalt() &&
+	  announceList.countStoppedAllowedTier());
+}
+
+bool DefaultBtAnnounce::isCompletedAnnounceReady() {
+  return (trackers == 0 &&
+	  pieceStorage->downloadFinished() &&
+	  announceList.countCompletedAllowedTier());
+}
+
+bool DefaultBtAnnounce::isAnnounceReady() {
+  return
+    isStoppedAnnounceReady() ||
+    isCompletedAnnounceReady() ||
+    isDefaultAnnounceReady();
+}
+
+string DefaultBtAnnounce::getAnnounceUrl() {
+  if(isStoppedAnnounceReady()) {
+    announceList.moveToStoppedAllowedTier();
+    announceList.setEvent(AnnounceTier::STOPPED);
+  } else if(isCompletedAnnounceReady()) {
+    announceList.moveToCompletedAllowedTier();
+    announceList.setEvent(AnnounceTier::COMPLETED);
+  } else if(isDefaultAnnounceReady()) {
+    // If download completed before "started" event is sent to a tracker,
+    // we change the event to something else to prevent us from
+    // sending "completed" event.
+    if(pieceStorage->downloadFinished() &&
+       announceList.getEvent() == AnnounceTier::STARTED) {
+      announceList.setEvent(AnnounceTier::STARTED_AFTER_COMPLETION);
+    }
+  }
+  int numWant = 50;
+  if(!btRuntime->lessThanEqMinPeer() ||
+     btRuntime->isHalt()) {
+    numWant = 0;
+  }
+  TransferStat stat = peerStorage->calculateStat();
+  long long int left = pieceStorage->getTotalLength()-pieceStorage->getCompletedLength();
+  if(left < 0) {
+    left = 0;
+  }
+  string url = announceList.getAnnounce()+"?"+
+    "info_hash="+Util::torrentUrlencode(btContext->getInfoHash(),
+					btContext->getInfoHashLength())+"&"+
+    "peer_id="+peerId+"&"+
+    "port="+Util::itos(btRuntime->getListenPort())+"&"+
+    "uploaded="+Util::llitos(stat.getSessionUploadLength())+"&"+
+    "downloaded="+Util::llitos(stat.getSessionDownloadLength())+"&"+
+    "left="+Util::llitos(left)+"&"+
+    "compact=1"+"&"+
+    "key="+key+"&"+
+    "numwant="+Util::itos(numWant)+"&"+
+    "no_peer_id=1";
+  string event = announceList.getEventString();
+  if(!event.empty()) {
+    url += string("&")+"event="+event;
+  }
+  if(!trackerId.empty()) {
+    url += string("&")+"trackerid="+Util::torrentUrlencode((const unsigned char*)trackerId.c_str(),
+							   trackerId.size());
+  }
+  return url;
+}
+
+void DefaultBtAnnounce::announceStart() {
+  trackers++;
+}
+
+void DefaultBtAnnounce::announceSuccess() {
+  trackers = 0;
+  announceList.announceSuccess();
+}
+
+void DefaultBtAnnounce::announceFailure() {
+  trackers = 0;
+  trackerNumTry++;
+  announceList.announceFailure();
+}
+
+bool DefaultBtAnnounce::isAllAnnounceFailed() {
+  return 
+    trackerNumTry >= option->getAsInt(PREF_TRACKER_MAX_TRIES);
+}
+
+void DefaultBtAnnounce::resetAnnounce() {
+  prevAnnounceTime.reset();
+  trackerNumTry = 0;
+}
+
+void
+DefaultBtAnnounce::processAnnounceResponse(const char* trackerResponse,
+						  size_t trackerResponseLength)
+{
+  SharedHandle<MetaEntry> entry(MetaFileUtil::bdecoding(trackerResponse,
+							trackerResponseLength));
+  Dictionary* response = (Dictionary*)entry.get();
+  Data* failureReasonData = (Data*)response->get("failure reason");
+  if(failureReasonData) {
+    throw new DlAbortEx("Tracker returned failure reason: %s",
+			failureReasonData->toString().c_str());
+  }
+  Data* warningMessageData = (Data*)response->get("warning message");
+  if(warningMessageData) {
+    logger->warn(MSG_TRACKER_WARNING_MESSAGE,
+		 warningMessageData->toString().c_str());
+  }
+  Data* trackerIdData = (Data*)response->get("tracker id");
+  if(trackerIdData) {
+    trackerId = trackerIdData->toString();
+    logger->debug("Tracker ID:%s", trackerId.c_str());
+  }
+  Data* intervalData = (Data*)response->get("interval");
+  if(intervalData) {
+    interval = intervalData->toInt();
+    logger->debug("Interval:%d", interval);
+  }
+  Data* minIntervalData = (Data*)response->get("min interval");
+  if(minIntervalData) {
+    minInterval = minIntervalData->toInt();
+    logger->debug("Min interval:%d", minInterval);
+  }
+  if(minInterval > interval) {
+    minInterval = interval;
+  }
+  Data* completeData = (Data*)response->get("complete");
+  if(completeData) {
+    complete = completeData->toInt();
+    logger->debug("Complete:%d", complete);
+  }
+  Data* incompleteData = (Data*)response->get("incomplete");
+  if(incompleteData) {
+    incomplete = incompleteData->toInt();
+    logger->debug("Incomplete:%d", incomplete);
+  }
+  const MetaEntry* peersEntry = response->get("peers");
+  if(peersEntry &&
+     !btRuntime->isHalt() &&
+     btRuntime->lessThanMinPeer()) {
+    DelegatingPeerListProcessor proc(btContext->getPieceLength(),
+				     btContext->getTotalLength());
+    Peers peers = proc.extractPeer(peersEntry);
+    peerStorage->addPeer(peers);
+  }
+  if(!peersEntry) {
+    logger->info("No peer list received.");
+  }
+}
+
+bool DefaultBtAnnounce::noMoreAnnounce() {
+  return (trackers == 0 &&
+	  btRuntime->isHalt() &&
+	  !announceList.countStoppedAllowedTier());
+}
+
+void DefaultBtAnnounce::shuffleAnnounce() {
+  announceList.shuffle();
+}

+ 122 - 0
src/DefaultBtAnnounce.h

@@ -0,0 +1,122 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_DEFAULT_BT_ANNOUNCE_H_
+#define _D_DEFAULT_BT_ANNOUNCE_H_
+
+#include "BtAnnounce.h"
+#include "BtContext.h"
+#include "TimeA2.h"
+#include "AnnounceList.h"
+#include "Option.h"
+#include "Logger.h"
+#include "BtRuntime.h"
+#include "PieceStorage.h"
+#include "PeerStorage.h"
+
+#define DEFAULT_ANNOUNCE_INTERVAL 1800
+
+class DefaultBtAnnounce : public BtAnnounce {
+private:
+  BtContextHandle btContext;
+  int trackers;
+  Time prevAnnounceTime;
+  int interval;
+  int minInterval;
+  int complete;
+  int incomplete;
+  AnnounceList announceList;
+  string trackerId;
+  string key;
+  int trackerNumTry;
+  string peerId;
+  const Option* option;
+  Logger* logger;
+  BtRuntimeHandle btRuntime;
+  PieceStorageHandle pieceStorage;
+  PeerStorageHandle peerStorage;
+public:
+  DefaultBtAnnounce(BtContextHandle btContext, const Option* option);
+  virtual ~DefaultBtAnnounce();
+
+  void setBtRuntime(const BtRuntimeHandle& btRuntime) {
+    this->btRuntime = btRuntime;
+  }
+  BtRuntimeHandle getBtRuntime() const { return btRuntime; }
+
+  void setPieceStorage(const PieceStorageHandle& pieceStorage) {
+    this->pieceStorage = pieceStorage;
+  }
+  PieceStorageHandle getPieceStorage() const { return pieceStorage; }
+
+  void setPeerStorage(const PeerStorageHandle& peerStorage) {
+    this->peerStorage = peerStorage;
+  }
+  PeerStorageHandle getPeerStorage() const { return peerStorage; }
+
+  bool isDefaultAnnounceReady();
+
+  bool isStoppedAnnounceReady();
+
+  bool isCompletedAnnounceReady();
+
+  virtual bool isAnnounceReady();
+
+  virtual string getAnnounceUrl();
+
+  virtual void announceStart();
+
+  virtual void announceSuccess();
+
+  virtual void announceFailure();
+
+  virtual bool isAllAnnounceFailed();
+
+  virtual void resetAnnounce();
+
+  virtual void processAnnounceResponse(const char* trackerResponse,
+				       size_t trackerResponseLength);
+
+  virtual bool noMoreAnnounce();
+
+  virtual void shuffleAnnounce();
+
+  string generateKey() const;
+  
+  string generatePeerId() const;
+
+  virtual string getPeerId() { return peerId; }
+};
+
+#endif // _D_DEFAULT_BT_ANNOUNCE_H_

+ 237 - 0
src/DefaultBtContext.cc

@@ -0,0 +1,237 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "DefaultBtContext.h"
+#include "MetaFileUtil.h"
+#include "Dictionary.h"
+#include "List.h"
+#include "Data.h"
+#include "DlAbortEx.h"
+#include "ShaVisitor.h"
+#include "Util.h"
+
+DefaultBtContext::DefaultBtContext() {}
+
+DefaultBtContext::~DefaultBtContext() {}
+
+const unsigned char* DefaultBtContext::getInfoHash() const {
+  return infoHash;
+}
+
+int DefaultBtContext::getInfoHashLength() const {
+  return INFO_HASH_LENGTH;
+}
+
+string DefaultBtContext::getInfoHashAsString() const {
+  return infoHashString;
+}
+
+void DefaultBtContext::clear() {
+  memset(infoHash, 0, INFO_HASH_LENGTH);
+  infoHashString = "";
+  pieceHashes.clear();
+  fileEntries.clear();
+  totalLength = 0;
+  pieceLength = 0;
+  fileMode = BtContext::SINGLE;
+  numPieces = 0;
+  name = "";
+  announceTiers.clear();
+}
+
+void DefaultBtContext::extractPieceHash(const unsigned char* hashData,
+					int hashDataLength,
+					int hashLength) {
+  assert(hashDataLength > 0);
+  assert(hashLength > 0);
+  int numPieces = hashDataLength/hashLength;
+  assert(numPieces > 0);
+
+  for(int i = 0; i < numPieces; i++) {
+    pieceHashes.push_back(Util::toHex(&hashData[i*hashLength],
+				      hashLength));
+  }
+}
+
+void DefaultBtContext::extractFileEntries(Dictionary* infoDic,
+					  const string& defaultName) {
+  // TODO use dynamic_cast
+  Data* nameData = (Data*)infoDic->get("name");
+  if(nameData) {
+    name = nameData->toString();
+  } else {
+    char* basec = strdup(defaultName.c_str());
+    name = string(basename(basec))+".file";
+    free(basec);
+  }
+  // TODO use dynamic_cast
+  List* files = (List*)infoDic->get("files");
+  if(files) {
+    long long int length = 0;
+    long long int offset = 0;
+    // multi-file mode
+    fileMode = BtContext::MULTI;
+    const MetaList& metaList = files->getList();
+    for(MetaList::const_iterator itr = metaList.begin();
+	itr != metaList.end(); itr++) {
+      Dictionary* fileDic = (Dictionary*)(*itr);
+      // TODO use dynamic_cast
+      Data* lengthData = (Data*)fileDic->get("length");
+      length += lengthData->toLLInt();
+      // TODO use dynamic_cast
+      List* pathList = (List*)fileDic->get("path");
+      const MetaList& paths = pathList->getList();
+      string path;
+      for(int i = 0; i < (int)paths.size()-1; i++) {
+	Data* subpath = (Data*)paths.at(i);
+	path += subpath->toString()+"/";
+      }
+      // TODO use dynamic_cast
+      Data* lastPath = (Data*)paths.back();
+      path += lastPath->toString();
+
+      FileEntryHandle fileEntry(new FileEntry(path,
+					      lengthData->toLLInt(),
+					      offset));
+      fileEntries.push_back(fileEntry);
+      offset += fileEntry->getLength();
+    }
+    totalLength = length;
+  } else {
+    // single-file mode;
+    fileMode = BtContext::SINGLE;
+    Data* length = (Data*)infoDic->get("length");
+    totalLength = length->toLLInt();
+    FileEntryHandle fileEntry(new FileEntry(name, totalLength, 0));
+    fileEntries.push_back(fileEntry);
+  }
+}
+
+void DefaultBtContext::extractAnnounce(Data* announceData) {
+  Strings urls;
+  urls.push_back(announceData->toString());
+  announceTiers.push_back(AnnounceTierHandle(new AnnounceTier(urls)));
+}
+
+void DefaultBtContext::extractAnnounceList(List* announceListData) {
+  for(MetaList::const_iterator itr = announceListData->getList().begin();
+      itr != announceListData->getList().end(); itr++) {
+    const List* elem = (List*)*itr;
+    Strings urls;
+    for(MetaList::const_iterator elemItr = elem->getList().begin();
+	elemItr != elem->getList().end(); elemItr++) {
+      const Data* data = (Data*)*elemItr;
+      urls.push_back(data->toString());
+    }
+    if(urls.size()) {
+      AnnounceTierHandle tier(new AnnounceTier(urls));
+      announceTiers.push_back(tier);
+    }
+  }
+}
+
+void DefaultBtContext::load(const string& torrentFile) {
+  clear();
+  MetaEntry* rootEntry = MetaFileUtil::parseMetaFile(torrentFile);
+  if(!dynamic_cast<Dictionary*>(rootEntry)) {
+    throw new DlAbortEx("torrent file does not contain a root dictionary .");
+  }
+  SharedHandle<Dictionary> rootDic =
+    SharedHandle<Dictionary>((Dictionary*)rootEntry);
+  Dictionary* infoDic = (Dictionary*)rootDic->get("info");
+  // retrieve infoHash
+  ShaVisitor v;
+  infoDic->accept(&v);
+  int len;
+  v.getHash(infoHash, len);
+  infoHashString = Util::toHex(infoHash, INFO_HASH_LENGTH);
+  // calculate the number of pieces
+  Data* pieceHashData = (Data*)infoDic->get("pieces");
+  numPieces = pieceHashData->getLen()/PIECE_HASH_LENGTH;
+  // retrieve piece length
+  Data* pieceLengthData = (Data*)infoDic->get("piece length");
+  pieceLength = pieceLengthData->toInt();
+  // retrieve piece hashes
+  extractPieceHash((unsigned char*)pieceHashData->getData(),
+		   pieceHashData->getLen(),
+		   PIECE_HASH_LENGTH);
+  // retrieve file entries
+  extractFileEntries(infoDic, torrentFile);
+  // retrieve announce
+  Data* announceData = (Data*)rootDic->get("announce");
+  List* announceListData = (List*)rootDic->get("announce-list");
+  if(announceListData) {
+    extractAnnounceList(announceListData);
+  } else if(announceData) {
+    extractAnnounce(announceData);
+  }
+  if(!announceTiers.size()) {
+    throw new DlAbortEx("No announce URL found.");
+  }
+}
+
+string DefaultBtContext::getPieceHash(int index) const {
+  if(index < 0 || numPieces <= index) {
+    return "";
+  }
+  return pieceHashes.at(index);
+}
+
+long long int DefaultBtContext::getTotalLength() const {
+  return totalLength;
+}
+
+BtContext::FILE_MODE DefaultBtContext::getFileMode() const {
+  return fileMode;
+}
+
+FileEntries DefaultBtContext::getFileEntries() const {
+  return fileEntries;
+}
+
+AnnounceTiers DefaultBtContext::getAnnounceTiers() const {
+  return announceTiers;
+}
+
+string DefaultBtContext::getName() const {
+  return name;
+}
+
+int DefaultBtContext::getPieceLength() const {
+  return pieceLength;
+}
+
+int DefaultBtContext::getNumPieces() const {
+  return numPieces;
+}

+ 97 - 0
src/DefaultBtContext.h

@@ -0,0 +1,97 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_DEFAULT_BT_CONTEXT_H_
+#define _D_DEFAULT_BT_CONTEXT_H_
+
+#include "BtContext.h"
+#include "Dictionary.h"
+#include "Data.h"
+#include "List.h"
+#define INFO_HASH_LENGTH 20
+#define PIECE_HASH_LENGTH 20
+
+typedef Strings PieceHashes;
+
+class DefaultBtContext : public BtContext {
+private:
+  unsigned char infoHash[INFO_HASH_LENGTH];
+  string infoHashString;
+  PieceHashes pieceHashes;
+  FileEntries fileEntries;
+  FILE_MODE fileMode;
+  long long int totalLength;
+  int pieceLength;
+  string name;
+  int numPieces;
+  AnnounceTiers announceTiers;
+
+  void clear();
+  void extractPieceHash(const unsigned char* hashData,
+			int hashDataLength,
+			int hashLength);
+  void extractFileEntries(Dictionary* infoDic,
+			  const string& defaultName);
+  void extractAnnounce(Data* announceData);
+  void extractAnnounceList(List* announceListData);
+ public:
+  DefaultBtContext();
+  virtual ~DefaultBtContext();
+
+  virtual const unsigned char* getInfoHash() const;
+
+  virtual int getInfoHashLength() const;
+
+  virtual string getInfoHashAsString() const;
+
+  virtual string getPieceHash(int index) const;
+
+  virtual long long int getTotalLength() const;
+
+  virtual FILE_MODE getFileMode() const;
+
+  virtual FileEntries getFileEntries() const;
+
+  virtual AnnounceTiers getAnnounceTiers() const;
+
+  virtual void load(const string& torrentFile);
+
+  virtual string getName() const;
+
+  virtual int getPieceLength() const;
+  
+  virtual int getNumPieces() const;
+};
+
+#endif // _D_DEFAULT_BT_CONTEXT_H_

+ 172 - 0
src/DefaultBtProgressInfoFile.cc

@@ -0,0 +1,172 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "DefaultBtProgressInfoFile.h"
+#include "BtRegistry.h"
+#include "LogFactory.h"
+#include "prefs.h"
+#include "DlAbortEx.h"
+#include "message.h"
+#include "File.h"
+#include "Util.h"
+#include <errno.h>
+
+DefaultBtProgressInfoFile::DefaultBtProgressInfoFile(const BtContextHandle& btContext,
+						     const Option* option):
+  btContext(btContext),
+  option(option),
+  pieceStorage(PIECE_STORAGE(btContext)),
+  btRuntime(BT_RUNTIME(btContext)),
+  peerStorage(PEER_STORAGE(btContext))
+{
+  logger = LogFactory::getInstance();
+  string storeDir = option->get(PREF_DIR);
+  filename = storeDir+"/"+btContext->getName()+".aria2";
+}
+
+DefaultBtProgressInfoFile::~DefaultBtProgressInfoFile() {}
+
+void DefaultBtProgressInfoFile::save() {
+  logger->info(MSG_SAVING_SEGMENT_FILE, filename.c_str());
+  FILE* file = openFile(filename, "w");
+  try {
+    if(fwrite(btContext->getInfoHash(),
+	      btContext->getInfoHashLength(), 1, file) < 1) {
+      throw string("writeError:info hash");
+    }
+    if(fwrite(pieceStorage->getBitfield(),
+	      pieceStorage->getBitfieldLength(), 1, file) < 1) {
+      throw string("writeError:bitfield");
+    }
+    TransferStat stat = peerStorage->calculateStat();
+    long long int allTimeDownloadLength = pieceStorage->getCompletedLength();
+    if(fwrite(&allTimeDownloadLength,
+	      sizeof(allTimeDownloadLength), 1, file) < 1) {
+      throw string("writeError:download length");
+    }
+    long long int allTimeUploadLength =
+      btRuntime->getUploadLengthAtStartup()+
+      stat.getSessionUploadLength();
+    if(fwrite(&allTimeUploadLength,
+	      sizeof(allTimeUploadLength), 1, file) < 1) {
+      throw string("writeError:upload length");
+    }
+    fclose(file);
+    logger->info(MSG_SAVED_SEGMENT_FILE);
+  } catch(string ex) {
+    fclose(file);
+    throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
+			filename.c_str(), strerror(errno));
+  }
+}
+
+void DefaultBtProgressInfoFile::load() {
+  logger->info(MSG_LOADING_SEGMENT_FILE, filename.c_str());
+  FILE* file = openFile(filename, "r+");
+  unsigned char* savedInfoHash = 0;
+  unsigned char* savedBitfield = 0;
+  try {
+    savedInfoHash = new unsigned char[btContext->getInfoHashLength()];
+    savedBitfield = new unsigned char[pieceStorage->getBitfieldLength()];
+    if(fread(savedInfoHash, btContext->getInfoHashLength(), 1, file) < 1) {
+      throw string("readError");
+    }
+    if(Util::toHex(savedInfoHash, btContext->getInfoHashLength()) != 
+       btContext->getInfoHashAsString()) {
+      throw new DlAbortEx("Incorrect infoHash.");
+    }
+    if(fread(savedBitfield, pieceStorage->getBitfieldLength(), 1, file) < 1) {
+      throw string("readError");
+    }
+    pieceStorage->setBitfield(savedBitfield,
+			      pieceStorage->getBitfieldLength());
+    // allTimeDownloadLength exists for only a compatibility reason.
+    long long int allTimeDownloadLength;
+    if(fread(&allTimeDownloadLength,
+	     sizeof(allTimeDownloadLength), 1, file) < 1) {
+      throw string("readError");
+    }
+    long long int allTimeUploadLength;
+    if(fread(&allTimeUploadLength,
+	     sizeof(allTimeUploadLength), 1, file) < 1) {
+      throw string("readError");
+    }
+    btRuntime->setUploadLengthAtStartup(allTimeUploadLength);
+    delete [] savedBitfield;
+    savedBitfield = 0;
+    delete [] savedInfoHash;
+    savedInfoHash = 0;
+    fclose(file);
+  } catch(string ex) {
+    if(savedBitfield) {
+      delete [] savedBitfield;
+    }
+    if(savedInfoHash) {
+      delete [] savedInfoHash;
+    }
+    fclose(file);
+    throw new DlAbortEx(EX_SEGMENT_FILE_READ,
+			filename.c_str(), strerror(errno));
+  }
+  logger->info(MSG_LOADED_SEGMENT_FILE);
+}
+
+void DefaultBtProgressInfoFile::removeFile() {
+  if(exists()) {
+    File f(filename);
+    f.remove();
+  }
+}
+
+FILE* DefaultBtProgressInfoFile::openFile(const string& filename,
+					  const string& mode) const
+{
+  FILE* file = fopen(filename.c_str(), mode.c_str());
+  if(!file) {
+    throw new DlAbortEx(EX_SEGMENT_FILE_OPEN,
+			filename.c_str(), strerror(errno));
+  }
+  return file;
+}
+
+bool DefaultBtProgressInfoFile::exists() {
+  File f(filename);
+  if(f.isFile()) {
+    logger->info(MSG_SEGMENT_FILE_EXISTS, filename.c_str());
+    return true;
+  } else {
+    logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, filename.c_str());
+    return false;
+  }
+}

+ 92 - 0
src/DefaultBtProgressInfoFile.h

@@ -0,0 +1,92 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_DEFAULT_BT_PROGRESS_INFO_FILE_H_
+#define _D_DEFAULT_BT_PROGRESS_INFO_FILE_H_
+
+#include "BtProgressInfoFile.h"
+#include "BtContext.h"
+#include "PieceStorage.h"
+#include "BtRuntime.h"
+#include "PeerStorage.h"
+#include "Logger.h"
+#include "Option.h"
+
+class DefaultBtProgressInfoFile : public BtProgressInfoFile {
+private:
+  BtContextHandle btContext;
+  const Option* option;
+  Logger* logger;
+  PieceStorageHandle pieceStorage;
+  BtRuntimeHandle btRuntime;
+  PeerStorageHandle peerStorage;
+  string filename;
+
+  FILE* openFile(const string& filename, const string& mode) const;
+public:
+  DefaultBtProgressInfoFile(const BtContextHandle& btContext,
+			    const Option* option);
+  virtual ~DefaultBtProgressInfoFile();
+
+  void setBtRuntime(const BtRuntimeHandle& btRuntime) {
+    this->btRuntime = btRuntime;
+  }
+  BtRuntimeHandle getBtRuntime() const { return btRuntime; }
+
+  void setPieceStorage(const PieceStorageHandle& pieceStorage) {
+    this->pieceStorage = pieceStorage;
+  }
+  PieceStorageHandle getPieceStorage() const { return pieceStorage; }
+
+  void setPeerStorage(const PeerStorageHandle& peerStorage) {
+    this->peerStorage = peerStorage;
+  }
+  PeerStorageHandle getPeerStorage() const { return peerStorage; }
+
+  virtual void setFilename(const string& filename) {
+    this->filename = filename;
+  }
+  virtual string getFilename() { return filename; }
+
+  virtual bool exists();
+
+  virtual void save();
+
+  virtual void load();
+
+  virtual void removeFile();
+
+};
+
+#endif // _D_DEFAULT_BT_PROGRESS_INFO_FILE_H_

+ 174 - 0
src/DefaultPeerStorage.cc

@@ -0,0 +1,174 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "DefaultPeerStorage.h"
+#include "LogFactory.h"
+#include "BtRegistry.h"
+
+extern PeerHandle nullPeer;
+
+DefaultPeerStorage::DefaultPeerStorage(BtContextHandle btContext,
+				       const Option* option):
+  btContext(btContext),
+  option(option),
+  maxPeerListSize(MAX_PEER_LIST_SIZE),
+  peerEntryIdCounter(0),
+  btRuntime(BT_RUNTIME(btContext))
+{
+  logger = LogFactory::getInstance();
+}
+
+DefaultPeerStorage::~DefaultPeerStorage() {}
+
+bool DefaultPeerStorage::addPeer(const PeerHandle& peer) {
+  Peers::iterator itr = find(peers.begin(), peers.end(), peer);
+  if(itr == peers.end()) {
+    if(peers.size() >= (size_t)maxPeerListSize) {
+      deleteUnusedPeer(peers.size()-maxPeerListSize+1);
+    }
+    ++peerEntryIdCounter;
+    peer->entryId = peerEntryIdCounter;
+    peers.push_back(peer);
+    return true;
+  } else {
+    const PeerHandle& peer = *itr;
+    if(peer->error >= MAX_PEER_ERROR || peer->cuid != 0) {
+      return false;
+    } else {
+      *itr = peer;
+      return true;
+    }      
+  }
+}
+
+void DefaultPeerStorage::addPeer(const Peers& peers) {
+  for(Peers::const_iterator itr = peers.begin();
+      itr != peers.end(); itr++) {
+    const PeerHandle& peer = *itr;
+    if(addPeer(peer)) {
+      logger->debug("Adding peer %s:%d",
+		    peer->ipaddr.c_str(), peer->port);
+    }
+  }  
+}
+
+const Peers& DefaultPeerStorage::getPeers() {
+  return peers;
+}
+
+class FindFinePeer {
+public:
+  bool operator()(const PeerHandle& peer) const {
+    return peer->cuid == 0 && peer->error < MAX_PEER_ERROR;
+  }
+};
+
+PeerHandle DefaultPeerStorage::getUnusedPeer() {
+  Peers::const_iterator itr = find_if(peers.begin(), peers.end(),
+				      FindFinePeer());
+  if(itr == peers.end()) {
+    return nullPeer;
+  } else {
+    return *itr;
+  }
+}
+
+class FindPeer {
+private:
+  string ipaddr;
+  int port;
+public:
+  FindPeer(const string& ipaddr, int port):ipaddr(ipaddr), port(port) {}
+
+  bool operator()(const PeerHandle& peer) const {
+    return ipaddr == peer->ipaddr && port == peer->port;
+  }
+};
+
+PeerHandle DefaultPeerStorage::getPeer(const string& ipaddr,
+				       int port) const {
+  Peers::const_iterator itr = find_if(peers.begin(), peers.end(),
+				      FindPeer(ipaddr, port));
+  if(itr == peers.end()) {
+    return nullPeer;
+  } else {
+    return *itr;
+  }
+}
+
+int DefaultPeerStorage::countPeer() const {
+  return peers.size();
+}
+
+bool DefaultPeerStorage::isPeerAvailable() {
+  return getUnusedPeer() != nullPeer;
+}
+
+Peers DefaultPeerStorage::getActivePeers() {
+  Peers activePeers;
+  for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
+    PeerHandle& peer = *itr;
+    if(peer->isActive()) {
+      activePeers.push_back(peer);
+    }
+  }
+  return activePeers;
+}
+
+TransferStat DefaultPeerStorage::calculateStat() {
+  TransferStat stat;
+  Peers activePeers = getActivePeers();
+  for(Peers::iterator itr = activePeers.begin();
+      itr != activePeers.end(); itr++) {
+    PeerHandle& peer = *itr;
+    stat.downloadSpeed += peer->calculateDownloadSpeed();
+    stat.uploadSpeed += peer->calculateUploadSpeed();
+    stat.sessionDownloadLength += peer->getSessionDownloadLength();
+    stat.sessionUploadLength += peer->getSessionUploadLength();
+  }
+  return stat;
+}
+
+void DefaultPeerStorage::deleteUnusedPeer(int delSize) {
+  for(Peers::iterator itr = peers.begin();
+      itr != peers.end() && delSize > 0;) {
+    const PeerHandle& p = *itr;
+    if(p->cuid == 0) {
+      itr = peers.erase(itr);
+      delSize--;
+    } else {
+      itr++;
+    }
+  }
+}

+ 90 - 0
src/DefaultPeerStorage.h

@@ -0,0 +1,90 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_DEFAULT_PEER_STORAGE_H_
+#define _D_DEFAULT_PEER_STORAGE_H_
+
+#include "PeerStorage.h"
+#include "BtContext.h"
+#include "Option.h"
+#include "Logger.h"
+#include "BtRuntime.h"
+
+#define MAX_PEER_LIST_SIZE 100
+#define MAX_PEER_ERROR 5
+
+class DefaultPeerStorage : public PeerStorage {
+private:
+  BtContextHandle btContext;
+  const Option* option;
+  Peers peers;
+  int maxPeerListSize;
+  int peerEntryIdCounter;
+  Logger* logger;
+  BtRuntimeHandle btRuntime;
+public:
+  DefaultPeerStorage(BtContextHandle btContext, const Option* option);
+  virtual ~DefaultPeerStorage();
+
+  void setBtRuntime(const BtRuntimeHandle& btRuntime) {
+    this->btRuntime = btRuntime;
+  }
+  BtRuntimeHandle getBtRuntime() const { return btRuntime; }
+
+  virtual bool addPeer(const PeerHandle& peer);
+
+  int countPeer() const;
+
+  virtual PeerHandle getUnusedPeer();
+
+  PeerHandle getPeer(const string& ipaddr, int port) const;
+
+  virtual void addPeer(const Peers& peers);
+
+  virtual const Peers& getPeers();
+
+  virtual bool isPeerAvailable();
+
+  virtual Peers getActivePeers();
+
+  virtual TransferStat calculateStat();
+
+  void setMaxPeerListSize(int size) { this->maxPeerListSize = size; }
+ 
+  int getMaxPeerListSize() const { return maxPeerListSize; }
+
+  void deleteUnusedPeer(int delSize);
+};
+
+#endif // _D_DEFAULT_PEER_STORAGE_H_

+ 433 - 0
src/DefaultPieceStorage.cc

@@ -0,0 +1,433 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "DefaultPieceStorage.h"
+#include "LogFactory.h"
+#include "prefs.h"
+#include "DirectDiskAdaptor.h"
+#include "MultiDiskAdaptor.h"
+#include "CopyDiskAdaptor.h"
+#include "DefaultDiskWriter.h"
+#include "MultiDiskWriter.h"
+#include "PreAllocationDiskWriter.h"
+#include "DlAbortEx.h"
+
+DefaultPieceStorage::DefaultPieceStorage(BtContextHandle btContext, const Option* option):
+  btContext(btContext),
+  endGamePieceNum(END_GAME_PIECE_NUM),
+  option(option)
+{
+  bitfieldMan = new BitfieldMan(btContext->getPieceLength(),
+				btContext->getTotalLength());
+  logger = LogFactory::getInstance();
+}
+
+DefaultPieceStorage::~DefaultPieceStorage() {
+  delete bitfieldMan;
+}
+
+bool DefaultPieceStorage::hasMissingPiece(const PeerHandle& peer) {
+  return bitfieldMan->hasMissingPiece(peer->getBitfield(),
+				      peer->getBitfieldLength());
+}
+
+bool DefaultPieceStorage::isEndGame() {
+  return bitfieldMan->countMissingBlock() <= endGamePieceNum;
+}
+
+int DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer) {
+  int index = -1;
+  if(isEndGame()) {
+    index = bitfieldMan->getMissingIndex(peer->getBitfield(),
+					 peer->getBitfieldLength());
+  } else {
+    index = bitfieldMan->getMissingUnusedIndex(peer->getBitfield(),
+					       peer->getBitfieldLength());
+  }
+  return index;
+}
+
+Piece DefaultPieceStorage::checkOutPiece(int index) {
+  if(index == -1) {
+    return Piece::nullPiece;
+  }
+  bitfieldMan->setUseBit(index);
+
+  Piece piece = findUsedPiece(index);
+  if(Piece::isNull(piece)) {
+    Piece piece(index, bitfieldMan->getBlockLength(index));
+    addUsedPiece(piece);
+    return piece;
+  } else {
+    return piece;
+  }
+}
+
+void DefaultPieceStorage::addUsedPiece(const Piece& piece) {
+  // TODO ? if nullPiece
+  usedPieces.push_back(piece);
+}
+
+class FindPiece {
+private:
+  int index;
+public:
+  FindPiece(int index):index(index) {}
+
+  bool operator()(const Piece& piece) {
+    return piece.getIndex() == index;
+  }
+};
+
+Piece DefaultPieceStorage::findUsedPiece(int index) const {
+  Pieces::const_iterator itr = find_if(usedPieces.begin(),
+				       usedPieces.end(),
+				       FindPiece(index));
+  if(itr == usedPieces.end()) {
+    return Piece::nullPiece;
+  } else {
+    return *itr;
+  }
+}
+
+Piece DefaultPieceStorage::getMissingPiece(const PeerHandle& peer) {
+  int index = getMissingPieceIndex(peer);
+  return checkOutPiece(index);
+}
+
+int DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer) {
+  int index = -1;
+  if(peer->isFastExtensionEnabled() && peer->countFastSet() > 0) {
+    BitfieldMan tempBitfield(bitfieldMan->getBlockLength(),
+			     bitfieldMan->getTotalLength());
+    for(Integers::const_iterator itr = peer->getFastSet().begin();
+	itr != peer->getFastSet().end(); itr++) {
+      if(!bitfieldMan->isBitSet(index) && peer->hasPiece(*itr)) {
+	tempBitfield.setBit(*itr);
+      }
+    }
+    if(isEndGame()) {
+      index = bitfieldMan->getMissingIndex(tempBitfield.getBitfield(),
+					   tempBitfield.getBitfieldLength());
+    } else {
+      index = bitfieldMan->getMissingUnusedIndex(tempBitfield.getBitfield(),
+						 tempBitfield.getBitfieldLength());
+    }
+  }
+  return index;
+}
+
+Piece DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer) {
+  int index = getMissingFastPieceIndex(peer);
+  return checkOutPiece(index);
+}
+
+void DefaultPieceStorage::deleteUsedPiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), piece);
+  if(itr != usedPieces.end()) {
+    usedPieces.erase(itr);
+  }
+}
+
+void DefaultPieceStorage::reduceUsedPieces(int delMax) {
+  int toDelete = usedPieces.size()-delMax;
+  if(toDelete <= 0) {
+    return;
+  }
+  int fillRate = 10;
+  while(fillRate < 50) {
+    int deleted = deleteUsedPiecesByFillRate(fillRate, toDelete);
+    if(deleted == 0) {
+      break;
+    }
+    toDelete -= deleted;
+    fillRate += 10;
+  }
+}
+
+int DefaultPieceStorage::deleteUsedPiecesByFillRate(int fillRate,
+							   int toDelete) {
+  int deleted = 0;
+  for(Pieces::iterator itr = usedPieces.begin();
+      itr != usedPieces.end() && deleted < toDelete;) {
+    Piece& piece = *itr;
+    if(!bitfieldMan->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 DefaultPieceStorage::completePiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  deleteUsedPiece(piece);
+  if(!isEndGame()) {
+    reduceUsedPieces(100);
+  }
+  if(downloadFinished()) {
+    return;
+  }
+  bitfieldMan->setBit(piece.getIndex());
+  bitfieldMan->unsetUseBit(piece.getIndex());
+  if(downloadFinished()) {
+    diskAdaptor->onDownloadComplete();
+    if(isSelectiveDownloadingMode()) {
+      logger->notice(_("Download of selected files was complete."));
+      finishSelectiveDownloadingMode();
+    } else {
+      logger->info(_("The download was complete."));
+    }
+  }
+}
+
+bool DefaultPieceStorage::isSelectiveDownloadingMode() {
+  return bitfieldMan->isFilterEnabled();
+}
+
+void DefaultPieceStorage::finishSelectiveDownloadingMode() {
+  bitfieldMan->clearFilter();
+  diskAdaptor->addAllDownloadEntry();
+}
+
+// not unittested
+void DefaultPieceStorage::cancelPiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  updatePiece(piece);
+  bitfieldMan->unsetUseBit(piece.getIndex());
+  if(!isEndGame()) {
+    if(piece.countCompleteBlock() == 0) {
+      deleteUsedPiece(piece);
+    }
+  }
+}
+
+// not unittested
+void DefaultPieceStorage::updatePiece(const Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(),
+			      piece);
+  if(itr != usedPieces.end()) {
+    *itr = piece;
+  }
+}
+
+// not unittested
+void DefaultPieceStorage::syncPiece(Piece& piece) {
+  if(Piece::isNull(piece)) {
+    return;
+  }
+  Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(),
+			      piece);
+  if(itr != usedPieces.end()) {
+    piece = *itr;
+    return;
+  } else {
+    // hasPiece(piece.getIndex()) is true, then set all bit of
+    // piece.bitfield to 1
+    if(hasPiece(piece.getIndex())) {
+      piece.setAllBlock();
+    }
+  }
+}
+
+bool DefaultPieceStorage::hasPiece(int index) {
+  return bitfieldMan->isBitSet(index);
+}
+
+long long int DefaultPieceStorage::getTotalLength() {
+  return bitfieldMan->getTotalLength();
+}
+
+long long int DefaultPieceStorage::getFilteredTotalLength() {
+  return bitfieldMan->getFilteredTotalLength();
+}
+
+long long int DefaultPieceStorage::getCompletedLength() {
+  return bitfieldMan->getCompletedLength();
+}
+
+long long int DefaultPieceStorage::getFilteredCompletedLength() {
+  return bitfieldMan->getFilteredCompletedLength();
+}
+
+// not unittested
+void DefaultPieceStorage::setFileFilter(const Strings& filePaths) {
+  if(btContext->getFileMode() != BtContext::MULTI || filePaths.empty()) {
+    return;
+  }
+  diskAdaptor->removeAllDownloadEntry();
+  for(Strings::const_iterator pitr = filePaths.begin();
+      pitr != filePaths.end(); pitr++) {
+    if(!diskAdaptor->addDownloadEntry(*pitr)) {
+      throw new DlAbortEx("No such file entry %s", (*pitr).c_str());
+    }
+    FileEntryHandle fileEntry = diskAdaptor->getFileEntryFromPath(*pitr);
+    bitfieldMan->addFilter(fileEntry->getOffset(), fileEntry->getLength());
+  }
+  bitfieldMan->enableFilter();
+}
+
+void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) {
+  Strings filePaths;
+  const FileEntries& entries = diskAdaptor->getFileEntries();
+  for(int i = 0; i < (int)entries.size(); i++) {
+    if(find(fileIndexes.begin(), fileIndexes.end(), i+1) != fileIndexes.end()) {
+      logger->debug("index=%d is %s", i+1, entries.at(i)->getPath().c_str());
+      filePaths.push_back(entries.at(i)->getPath());
+    }
+  }
+  setFileFilter(filePaths);
+}
+
+// not unittested
+void DefaultPieceStorage::clearFileFilter() {
+  bitfieldMan->clearFilter();
+  diskAdaptor->addAllDownloadEntry();
+}
+
+// not unittested
+bool DefaultPieceStorage::downloadFinished() {
+  return bitfieldMan->isAllBitSet();
+}
+
+// not unittested
+void DefaultPieceStorage::initStorage() {
+  if(diskAdaptor) {
+    delete diskAdaptor;
+    diskAdaptor = 0;
+  }
+  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
+    if(btContext->getFileMode() == BtContext::SINGLE) {
+      diskAdaptor = new DirectDiskAdaptor(new DefaultDiskWriter(btContext->getTotalLength()));
+    } else {
+      diskAdaptor = new MultiDiskAdaptor(new MultiDiskWriter(btContext->getPieceLength()));
+    }
+  } else {
+    diskAdaptor = new CopyDiskAdaptor(new PreAllocationDiskWriter(btContext->getTotalLength()));
+    ((CopyDiskAdaptor*)diskAdaptor)->setTempFilename(btContext->getName()+".a2tmp");
+  }
+  string storeDir = option->get(PREF_DIR);
+  if(storeDir == "") {
+    storeDir = ".";
+  }
+  if(btContext->getFileMode() == BtContext::MULTI) {
+    storeDir += "/"+btContext->getName();
+  }
+  diskAdaptor->setStoreDir(storeDir);
+  diskAdaptor->setFileEntries(btContext->getFileEntries());
+}
+
+void DefaultPieceStorage::setBitfield(const unsigned char* bitfield,
+				      int bitfieldLength) {
+  bitfieldMan->setBitfield(bitfield, bitfieldLength);
+}
+  
+int DefaultPieceStorage::getBitfieldLength() {
+  return bitfieldMan->getBitfieldLength();
+}
+
+const unsigned char* DefaultPieceStorage::getBitfield() {
+  return bitfieldMan->getBitfield();
+}
+
+DiskAdaptor* DefaultPieceStorage::getDiskAdaptor() {
+  return diskAdaptor;
+}
+
+int DefaultPieceStorage::getPieceLength(int index) {
+  return bitfieldMan->getBlockLength(index);
+}
+
+void DefaultPieceStorage::advertisePiece(int cuid, int index) {
+  HaveEntry entry(cuid, index);
+  haves.push_front(entry);
+}
+
+Integers DefaultPieceStorage::getAdvertisedPieceIndexes(int myCuid,
+							const Time& lastCheckTime) {
+  Integers indexes;
+  for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) {
+    const Haves::value_type& have = *itr;
+    if(have.getCuid() == myCuid) {
+      continue;
+    }
+    if(lastCheckTime.isNewer(have.getRegisteredTime())) {
+      break;
+    }
+    indexes.push_back(have.getIndex());
+  }
+  return indexes;
+}
+
+class FindElapsedHave
+{
+private:
+  int elapsed;
+public:
+  FindElapsedHave(int elapsed):elapsed(elapsed) {}
+
+  bool operator()(const HaveEntry& have) {
+    if(have.getRegisteredTime().elapsed(elapsed)) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+};
+  
+void DefaultPieceStorage::removeAdvertisedPiece(int elapsed) {
+  Haves::iterator itr =
+    find_if(haves.begin(), haves.end(), FindElapsedHave(elapsed));
+  if(itr != haves.end()) {
+    logger->debug("Removed %d have entries.", haves.end()-itr);
+    haves.erase(itr, haves.end());
+  }
+}

+ 158 - 0
src/DefaultPieceStorage.h

@@ -0,0 +1,158 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_DEFAULT_PIECE_STORAGE_H_
+#define _D_DEFAULT_PIECE_STORAGE_H_
+
+#include "PieceStorage.h"
+#include "BtContext.h"
+#include "DiskAdaptor.h"
+#include "BitfieldMan.h"
+#include "Logger.h"
+#include "Option.h"
+#include "Piece.h"
+
+#define END_GAME_PIECE_NUM 20
+
+class HaveEntry {
+private:
+  int cuid;
+  int index;
+  Time registeredTime;
+public:
+  HaveEntry(int cuid, int index):
+    cuid(cuid),
+    index(index) {}
+
+  int getCuid() const { return cuid; }
+
+  int getIndex() const { return index; }
+
+  const Time& getRegisteredTime() const { return registeredTime; }
+};
+
+typedef deque<HaveEntry> Haves;
+
+class DefaultPieceStorage : public PieceStorage {
+private:
+  BtContextHandle btContext;
+  BitfieldMan* bitfieldMan;
+  DiskAdaptor* diskAdaptor;
+  Pieces usedPieces;
+  int endGamePieceNum;
+  Logger* logger;
+  const Option* option;
+  Haves haves;
+
+  int getMissingPieceIndex(const PeerHandle& peer);
+  int getMissingFastPieceIndex(const PeerHandle& peer);
+  Piece checkOutPiece(int index);
+  void addUsedPiece(const Piece& piece);
+  Piece findUsedPiece(int index) const;
+  int deleteUsedPiecesByFillRate(int fillRate, int toDelete);
+  void reduceUsedPieces(int delMax);
+  void deleteUsedPiece(const Piece& piece);
+public:
+  DefaultPieceStorage(BtContextHandle btContext, const Option* option);
+  virtual ~DefaultPieceStorage();
+
+  virtual bool hasMissingPiece(const PeerHandle& peer);
+
+  virtual Piece getMissingPiece(const PeerHandle& peer);
+
+  virtual Piece getMissingFastPiece(const PeerHandle& peer);
+
+  virtual void completePiece(const Piece& piece);
+
+  virtual void cancelPiece(const Piece& piece);
+
+  virtual void updatePiece(const Piece& piece);
+
+  virtual void syncPiece(Piece& piece);
+
+  virtual bool hasPiece(int index);
+
+  virtual long long int getTotalLength();
+
+  virtual long long int getFilteredTotalLength();
+
+  virtual long long int getCompletedLength();
+
+  virtual long long int getFilteredCompletedLength();
+
+  virtual void initStorage();
+
+  virtual void setFileFilter(const Strings& filePaths);
+
+  virtual void setFileFilter(const Integers& fileIndexes);
+
+  virtual void clearFileFilter();
+
+  virtual bool downloadFinished();
+
+  virtual void setBitfield(const unsigned char* bitfield,
+			   int bitfieldLength);
+  
+  virtual int getBitfieldLength();
+
+  virtual const unsigned char* getBitfield();
+
+  void setEndGamePieceNum(int num) {
+    endGamePieceNum = num;
+  }
+
+  int getEndGamePieceNum() const {
+    return endGamePieceNum;
+  }
+
+  virtual bool isSelectiveDownloadingMode();
+
+  virtual void finishSelectiveDownloadingMode();
+
+  virtual bool isEndGame();
+  
+  virtual DiskAdaptor* getDiskAdaptor();
+
+  virtual int getPieceLength(int index);
+
+  virtual void advertisePiece(int cuid, int index);
+
+  virtual Integers getAdvertisedPieceIndexes(int myCuid,
+					     const Time& lastCheckTime);
+
+  virtual void removeAdvertisedPiece(int elapsed);
+
+};
+
+#endif // _D_DEFAULT_PIECE_STORAGE_H_

+ 1 - 0
src/DelegatingPeerListProcessor.cc

@@ -54,4 +54,5 @@ bool DelegatingPeerListProcessor::canHandle(const MetaEntry* peersEntry) const {
       return true;
     }
   }
+  return false;
 }

+ 1 - 1
src/DirectDiskAdaptor.cc

@@ -39,7 +39,7 @@ DirectDiskAdaptor::DirectDiskAdaptor(DiskWriter* diskWriter):DiskAdaptor(diskWri
 DirectDiskAdaptor::~DirectDiskAdaptor() {}
 
 string DirectDiskAdaptor::getFilePath() const {
-  return storeDir+"/"+fileEntries.front().path;
+  return storeDir+"/"+fileEntries.front()->getPath();
 }
 
 void DirectDiskAdaptor::onDownloadComplete() {

+ 5 - 0
src/Directory.cc

@@ -42,6 +42,8 @@
 
 Directory::Directory(const string& name):name(name) {}
 
+Directory::Directory() {}
+
 Directory::~Directory() {
   for(Files::iterator itr = files.begin(); itr != files.end(); itr++) {
     delete *itr;
@@ -49,6 +51,9 @@ Directory::~Directory() {
 }
 
 void Directory::createDir(const string& parentDir, bool recursive) const {
+  if(name.size() == 0) {
+    return;
+  }
   string path = parentDir+"/"+name;
   File f(path);
   if(f.exists()) {

+ 3 - 0
src/Directory.h

@@ -48,10 +48,13 @@ private:
   Files files;
 public:
   Directory(const string& name);
+  Directory();
   ~Directory();
 
   void createDir(const string& parentDir, bool recursive) const;
   void addFile(Directory* directory);
 };
 
+typedef SharedHandle<Directory> DirectoryHandle;
+
 #endif // _D_DIRECTORY_H_

+ 8 - 11
src/DiskAdaptor.cc

@@ -36,15 +36,12 @@
 #include "DlAbortEx.h"
 #include "LogFactory.h"
 
-DiskAdaptor::DiskAdaptor(DiskWriter* diskWriter):diskWriter(diskWriter), topDir(NULL) {
+DiskAdaptor::DiskAdaptor(DiskWriter* diskWriter):diskWriter(diskWriter) {
   logger = LogFactory::getInstance();
 }
 
 DiskAdaptor::~DiskAdaptor() {
   delete diskWriter;
-  if(topDir != NULL) {
-    delete topDir;
-  }
 }
 
 void DiskAdaptor::openFile() {
@@ -75,10 +72,10 @@ string DiskAdaptor::sha1Sum(long long int offset, long long int length) {
   return diskWriter->sha1Sum(offset, length);
 }
 
-FileEntry DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const {
+FileEntryHandle DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const {
   for(FileEntries::const_iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
-    if(itr->path == fileEntryPath) {
+    if((*itr)->getPath() == fileEntryPath) {
       return *itr;
     }
   }
@@ -88,8 +85,8 @@ FileEntry DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const {
 bool DiskAdaptor::addDownloadEntry(const string& fileEntryPath) {
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
-    if(itr->path == fileEntryPath) {
-      itr->requested = true;
+    if((*itr)->getPath() == fileEntryPath) {
+      (*itr)->setRequested(true);
       return true;
     }
   }
@@ -100,20 +97,20 @@ bool DiskAdaptor::addDownloadEntry(int index) {
   if(fileEntries.size() <= (unsigned int)index) {
     return false;
   }
-  fileEntries.at(index).requested = true;
+  fileEntries.at(index)->setRequested(true);
   return true;
 }
 
 void DiskAdaptor::addAllDownloadEntry() {
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
-    itr->requested = true;
+    (*itr)->setRequested(true);
   }
 }
 
 void DiskAdaptor::removeAllDownloadEntry() {
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
-    itr->requested = false;
+    (*itr)->setRequested(false);
   }
 }

+ 5 - 10
src/DiskAdaptor.h

@@ -40,13 +40,13 @@
 #include "Directory.h"
 #include "DiskWriter.h"
 #include "Logger.h"
+#include "FileEntry.h"
 
 class DiskAdaptor {
 protected:
   DiskWriter* diskWriter;
   string storeDir;
   FileEntries fileEntries;
-  const Directory* topDir;
   const Logger* logger;
   virtual string getFilePath() const = 0;
 public:
@@ -66,7 +66,9 @@ public:
   void setFileEntries(const FileEntries& fileEntries) {
     this->fileEntries = fileEntries;
   }
-  FileEntry getFileEntryFromPath(const string& fileEntryPath) const;
+
+  FileEntryHandle getFileEntryFromPath(const string& fileEntryPath) const;
+
   const FileEntries& getFileEntries() const { return fileEntries; }
 
   bool addDownloadEntry(const string& fileEntryPath);
@@ -75,15 +77,8 @@ public:
   void removeAllDownloadEntry();
 
   void setStoreDir(const string& storeDir) { this->storeDir = storeDir; }
-  string getStoreDir() const { return this->storeDir; }
 
-  void setTopDir(const Directory* dirctory) {
-    if(this->topDir != NULL) {
-      delete topDir;
-    }
-    this->topDir = dirctory;
-  }
-  const Directory* getTopDir() const { return this->topDir; }
+  string getStoreDir() const { return this->storeDir; }
 };
 
 #endif // _D_DISK_ADAPTOR_H_

+ 57 - 20
src/DownloadEngineFactory.cc

@@ -49,6 +49,10 @@
 # include "UnionSeedCriteria.h"
 # include "TimeSeedCriteria.h"
 # include "ShareRatioSeedCriteria.h"
+# include "DefaultPieceStorage.h"
+# include "DefaultPeerStorage.h"
+# include "DefaultBtAnnounce.h"
+# include "DefaultBtProgressInfoFile.h"
 #endif // ENABLE_BITTORRENT
 
 ConsoleDownloadEngine*
@@ -76,8 +80,8 @@ DownloadEngineFactory::newConsoleEngine(const Option* op,
 
 #ifdef ENABLE_BITTORRENT
 TorrentConsoleDownloadEngine*
-DownloadEngineFactory::newTorrentConsoleEngine(const Option* op,
-					       const string& torrentFile,
+DownloadEngineFactory::newTorrentConsoleEngine(const BtContextHandle& btContext,
+					       const Option* op,
 					       const Strings& targetFiles)
 {
   TorrentConsoleDownloadEngine* te = new TorrentConsoleDownloadEngine();
@@ -86,19 +90,44 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op,
   te->segmentMan = new SegmentMan();
   te->segmentMan->diskWriter = byteArrayDiskWriter;
   te->segmentMan->option = op;
-  te->torrentMan = new TorrentMan();
-  te->torrentMan->setStoreDir(op->get(PREF_DIR));
-  te->torrentMan->option = op;
+  BtRuntimeHandle btRuntime(new BtRuntime());
+  BtRegistry::registerBtRuntime(btContext->getInfoHashAsString(), btRuntime);
+
+  PieceStorageHandle pieceStorage(new DefaultPieceStorage(btContext, op));
+  BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), pieceStorage);
+
+  PeerStorageHandle peerStorage(new DefaultPeerStorage(btContext, op));
+  BtRegistry::registerPeerStorage(btContext->getInfoHashAsString(), peerStorage);
+
+  BtAnnounceHandle btAnnounce(new DefaultBtAnnounce(btContext, op));
+  BtRegistry::registerBtAnnounce(btContext->getInfoHashAsString(), btAnnounce);
+  btAnnounce->shuffleAnnounce();
+
+  BtProgressInfoFileHandle btProgressInfoFile(new DefaultBtProgressInfoFile(btContext, op));
+  BtRegistry::registerBtProgressInfoFile(btContext->getInfoHashAsString(),
+					 btProgressInfoFile);
+
+  te->setBtContext(btContext);
+  // initialize file storage
+  pieceStorage->initStorage();
+  if(btProgressInfoFile->exists()) {
+    // load .aria2 file if it exists.
+    btProgressInfoFile->load();
+    pieceStorage->getDiskAdaptor()->openExistingFile();
+  } else {
+    pieceStorage->getDiskAdaptor()->initAndOpenFile();
+  }
+
   Integers selectIndexes;
   Util::unfoldRange(op->get(PREF_SELECT_FILE), selectIndexes);
   if(selectIndexes.size()) {
-    te->torrentMan->setup(torrentFile, selectIndexes);
+    pieceStorage->setFileFilter(selectIndexes);
   } else {
-    te->torrentMan->setup(torrentFile, targetFiles);
+    pieceStorage->setFileFilter(targetFiles);
   }
 
   PeerListenCommand* listenCommand =
-    new PeerListenCommand(te->torrentMan->getNewCuid(), te);
+    new PeerListenCommand(btRuntime->getNewCuid(), te, btContext);
   int port;
   int listenPort = op->getAsInt(PREF_LISTEN_PORT);
   if(listenPort == -1) {
@@ -110,31 +139,39 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op,
     printf(_("Errors occurred while binding port.\n"));
     exit(EXIT_FAILURE);
   }
-  te->torrentMan->setPort(port);
+  btRuntime->setListenPort(port);
   te->commands.push_back(listenCommand);
   
-  te->commands.push_back(new TrackerWatcherCommand(te->torrentMan->getNewCuid(),
-						   te));
-  te->commands.push_back(new TrackerUpdateCommand(te->torrentMan->getNewCuid(),
-						  te));
-  te->commands.push_back(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(),
+  te->commands.push_back(new TrackerWatcherCommand(btRuntime->getNewCuid(),
+						   te,
+						   btContext));
+  te->commands.push_back(new TrackerUpdateCommand(btRuntime->getNewCuid(),
+						  te,
+						  btContext));
+  te->commands.push_back(new TorrentAutoSaveCommand(btRuntime->getNewCuid(),
 						    te,
+						    btContext,
 						    op->getAsInt(PREF_AUTO_SAVE_INTERVAL)));
-  te->commands.push_back(new PeerChokeCommand(te->torrentMan->getNewCuid(),
-					      te, 10));
-  te->commands.push_back(new HaveEraseCommand(te->torrentMan->getNewCuid(),
-					      te, 10));
+  te->commands.push_back(new PeerChokeCommand(btRuntime->getNewCuid(),
+					      te,
+					      btContext,
+					      10));
+  te->commands.push_back(new HaveEraseCommand(btRuntime->getNewCuid(),
+					      te,
+					      btContext,
+					      10));
 
   SharedHandle<UnionSeedCriteria> unionCri = new UnionSeedCriteria();
   if(op->defined(PREF_SEED_TIME)) {
     unionCri->addSeedCriteria(new TimeSeedCriteria(op->getAsInt(PREF_SEED_TIME)*60));
   }
   if(op->defined(PREF_SEED_RATIO)) {
-    unionCri->addSeedCriteria(new ShareRatioSeedCriteria(op->getAsDouble(PREF_SEED_RATIO), te->torrentMan));
+    unionCri->addSeedCriteria(new ShareRatioSeedCriteria(op->getAsDouble(PREF_SEED_RATIO), btContext));
   }
   if(unionCri->getSeedCriterion().size() > 0) {
-    te->commands.push_back(new SeedCheckCommand(te->torrentMan->getNewCuid(),
+    te->commands.push_back(new SeedCheckCommand(btRuntime->getNewCuid(),
 						te,
+						btContext,
 						unionCri));
   }
   return te;

+ 2 - 2
src/DownloadEngineFactory.h

@@ -50,8 +50,8 @@ public:
 
 #ifdef ENABLE_BITTORRENT
   static TorrentConsoleDownloadEngine*
-  newTorrentConsoleEngine(const Option* option,
-			  const string& torrentFile,
+  newTorrentConsoleEngine(const BtContextHandle& btContext,
+			  const Option* option, 
 			  const Strings& targetFiles);
 #endif // ENABLE_BITTORRENT
 };

+ 28 - 0
src/File.cc

@@ -33,6 +33,7 @@
  */
 /* copyright --> */
 #include "File.h"
+#include "Util.h"
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -83,3 +84,30 @@ long long int File::size() {
   }
   return fstat.st_size;
 }
+
+bool File::mkdirs() {
+  if(isDir()) {
+    return false;
+  }
+  Strings dirs;
+  Util::slice(dirs, name, '/');
+  if(!dirs.size()) {
+    return true;
+  }
+  string accDir;
+  if(Util::startsWith(name, "/")) {
+    accDir = "/";
+  }
+  mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR;
+  for(Strings::const_iterator itr = dirs.begin(); itr != dirs.end();
+      itr++, accDir += "/") {
+    accDir += *itr;
+    if(File(accDir).isDir()) {
+      continue;
+    }
+    if(mkdir(accDir.c_str(), mode) == -1) {
+      return false;
+    }
+  }
+  return true;
+}

+ 9 - 0
src/File.h

@@ -72,6 +72,15 @@ public:
    */
   bool remove();
 
+  /**
+   * Creates the directory denoted by name.
+   * This method creates complete directory structure.
+   * Returns true if the directory is created successfully, otherwise returns
+   * false.
+   * If the directory already exists, then returns false.
+   */
+  bool mkdirs();
+
   long long int size();
 };
 

+ 64 - 0
src/FileEntry.cc

@@ -0,0 +1,64 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "FileEntry.h"
+#include "File.h"
+#include "DlAbortEx.h"
+#include <libgen.h>
+
+FileEntry::FileEntry(const string& path,
+		     long long int length,
+		     long long int offset):
+  path(path), length(length), offset(offset),
+  extracted(false), requested(true) {}
+
+FileEntry::~FileEntry() {}
+
+void FileEntry::setupDir(const string& parentDir) {
+  string absPath = parentDir+"/"+path;
+  char* temp = strdup(absPath.c_str());
+  string dir = string(dirname(temp));
+  free(temp);
+  if(!dir.size()) {
+    return;
+  }
+  File f(dir);
+  if(f.isDir()) {
+    // nothing to do
+  } else if(f.exists()) {
+    throw new DlAbortEx("%s is not a directory.", dir.c_str());
+  } else if(!f.mkdirs()) {
+    throw new DlAbortEx("Failed to create directory %s.", dir.c_str());
+  }  
+}

+ 29 - 6
src/FileEntry.h

@@ -38,18 +38,41 @@
 #include "common.h"
 
 class FileEntry {
-public:
+private:
   string path;
   long long int length;
   long long int offset;
   bool extracted;
   bool requested;
-  FileEntry(const string& path, long long int length, long long int offset):
-    path(path), length(length), offset(offset),
-    extracted(false), requested(true) {}
-  ~FileEntry() {}
+public:
+  FileEntry(const string& path, long long int length, long long int offset);
+
+  ~FileEntry();
+
+  const string& getPath() const { return path; }
+
+  void setPath(const string& path) { this->path = path; }
+
+  long long int getLength() const { return length; }
+
+  void setLength(long long int length) { this->length = length; }
+
+  long long int getOffset() const { return offset; }
+
+  void setOffset(long long int offset) { this->offset = offset; }
+
+  bool isExtracted() const { return extracted; }
+
+  void setExtracted(bool flag) { this->extracted = flag; }
+
+  bool isRequested() const { return requested; }
+
+  void setRequested(bool flag) { this->requested = flag; }
+
+  void setupDir(const string& parentDir);
 };
 
-typedef deque<FileEntry> FileEntries;
+typedef SharedHandle<FileEntry> FileEntryHandle;
+typedef deque<FileEntryHandle> FileEntries;
 
 #endif // _D_FILE_ENTRY_H_

+ 1 - 1
src/HandshakeMessage.cc

@@ -93,7 +93,7 @@ string HandshakeMessage::toString() const {
 
 void HandshakeMessage::check() const {
   PeerMessageUtil::checkHandshake(this,
-				  peerInteraction->getTorrentMan()->getInfoHash());
+				  peerInteraction->getBtContext()->getInfoHash());
 }
 
 bool HandshakeMessage::isFastExtensionSupported() const {

+ 0 - 1
src/HandshakeMessage.h

@@ -36,7 +36,6 @@
 #define _D_HANDSHAKE_MESSAGE_H_
 
 #include "SimplePeerMessage.h"
-#include "TorrentMan.h"
 
 #define PSTR "BitTorrent protocol"
 #define HANDSHAKE_MESSAGE_LENGTH 68

+ 10 - 2
src/HaveEraseCommand.cc

@@ -34,13 +34,21 @@
 /* copyright --> */
 #include "HaveEraseCommand.h"
 
+HaveEraseCommand::HaveEraseCommand(int cuid,
+				   TorrentDownloadEngine* e,
+				   const BtContextHandle& btContext,
+				   int interval)
+  :BtContextAwareCommand(cuid, btContext),
+   e(e),
+   interval(interval) {}
+
 bool HaveEraseCommand::execute() {
-  if(e->torrentMan->isHalt()) {
+  if(btRuntime->isHalt()) {
     return true;
   }
   if(cp.elapsed(interval)) {
     cp.reset();
-    e->torrentMan->removeAdvertisedPiece(5);
+    pieceStorage->removeAdvertisedPiece(5);
   }
   e->commands.push_back(this);
   return false;

+ 6 - 6
src/HaveEraseCommand.h

@@ -35,19 +35,19 @@
 #ifndef _D_HAVE_ERASE_COMMAND_H_
 #define _D_HAVE_ERASE_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 
-class HaveEraseCommand : public Command {
+class HaveEraseCommand : public BtContextAwareCommand {
 private:
   TorrentDownloadEngine* e;
   Time cp;
   int interval;
 public:
-  HaveEraseCommand(int cuid, TorrentDownloadEngine* e, int interval)
-    :Command(cuid),
-     e(e),
-     interval(interval) {}
+  HaveEraseCommand(int cuid,
+		   TorrentDownloadEngine* e,
+		   const BtContextHandle& btContext,
+		   int interval);
 
   virtual ~HaveEraseCommand() {}
 

+ 16 - 3
src/Makefile.am

@@ -69,7 +69,6 @@ SRCS += MetaEntry.h\
 	MetaFileUtil.cc MetaFileUtil.h\
 	MetaEntryVisitor.h\
 	ShaVisitor.cc ShaVisitor.h\
-	TorrentMan.cc TorrentMan.h\
 	PeerConnection.cc PeerConnection.h\
 	PeerMessageUtil.cc PeerMessageUtil.h\
 	PeerAbstractCommand.cc PeerAbstractCommand.h\
@@ -92,7 +91,7 @@ SRCS += MetaEntry.h\
 	CopyDiskAdaptor.cc CopyDiskAdaptor.h\
 	DirectDiskAdaptor.cc DirectDiskAdaptor.h\
 	MultiDiskAdaptor.cc MultiDiskAdaptor.h\
-	FileEntry.h\
+	FileEntry.cc FileEntry.h\
 	TrackerUpdateCommand.cc TrackerUpdateCommand.h\
 	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\
 	PeerChokeCommand.cc PeerChokeCommand.h\
@@ -125,7 +124,21 @@ SRCS += MetaEntry.h\
 	DefaultPeerListProcessor.cc DefaultPeerListProcessor.h\
 	CompactPeerListProcessor.cc CompactPeerListProcessor.h\
 	DelegatingPeerListProcessor.cc DelegatingPeerListProcessor.h\
-	AnnounceList.h AnnounceList.cc
+	AnnounceTier.h\
+	AnnounceList.h AnnounceList.cc\
+	BtContext.h\
+	DefaultBtContext.cc DefaultBtContext.h\
+	PieceStorage.h\
+	DefaultPieceStorage.cc DefaultPieceStorage.h\
+	PeerService.h\
+	DefaultPeerStorage.cc DefaultPeerStorage.h\
+	BtAnnounce.h\
+	DefaultBtAnnounce.cc DefaultBtAnnounce.h\
+	BtRegistry.cc BtRegistry.h\
+	BtRuntime.h\
+	BtProgressInfoFile.h\
+	DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\
+	BtContextAwareCommand.cc BtContextAwareCommand.h
 endif # ENABLE_BITTORRENT
 
 if ENABLE_METALINK

+ 52 - 18
src/Makefile.in

@@ -46,7 +46,6 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_BITTORRENT_TRUE@	MetaFileUtil.cc MetaFileUtil.h\
 @ENABLE_BITTORRENT_TRUE@	MetaEntryVisitor.h\
 @ENABLE_BITTORRENT_TRUE@	ShaVisitor.cc ShaVisitor.h\
-@ENABLE_BITTORRENT_TRUE@	TorrentMan.cc TorrentMan.h\
 @ENABLE_BITTORRENT_TRUE@	PeerConnection.cc PeerConnection.h\
 @ENABLE_BITTORRENT_TRUE@	PeerMessageUtil.cc PeerMessageUtil.h\
 @ENABLE_BITTORRENT_TRUE@	PeerAbstractCommand.cc PeerAbstractCommand.h\
@@ -69,7 +68,7 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_BITTORRENT_TRUE@	CopyDiskAdaptor.cc CopyDiskAdaptor.h\
 @ENABLE_BITTORRENT_TRUE@	DirectDiskAdaptor.cc DirectDiskAdaptor.h\
 @ENABLE_BITTORRENT_TRUE@	MultiDiskAdaptor.cc MultiDiskAdaptor.h\
-@ENABLE_BITTORRENT_TRUE@	FileEntry.h\
+@ENABLE_BITTORRENT_TRUE@	FileEntry.cc FileEntry.h\
 @ENABLE_BITTORRENT_TRUE@	TrackerUpdateCommand.cc TrackerUpdateCommand.h\
 @ENABLE_BITTORRENT_TRUE@	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\
 @ENABLE_BITTORRENT_TRUE@	PeerChokeCommand.cc PeerChokeCommand.h\
@@ -102,7 +101,21 @@ bin_PROGRAMS = aria2c$(EXEEXT)
 @ENABLE_BITTORRENT_TRUE@	DefaultPeerListProcessor.cc DefaultPeerListProcessor.h\
 @ENABLE_BITTORRENT_TRUE@	CompactPeerListProcessor.cc CompactPeerListProcessor.h\
 @ENABLE_BITTORRENT_TRUE@	DelegatingPeerListProcessor.cc DelegatingPeerListProcessor.h\
-@ENABLE_BITTORRENT_TRUE@	AnnounceList.h AnnounceList.cc
+@ENABLE_BITTORRENT_TRUE@	AnnounceTier.h\
+@ENABLE_BITTORRENT_TRUE@	AnnounceList.h AnnounceList.cc\
+@ENABLE_BITTORRENT_TRUE@	BtContext.h\
+@ENABLE_BITTORRENT_TRUE@	DefaultBtContext.cc DefaultBtContext.h\
+@ENABLE_BITTORRENT_TRUE@	PieceStorage.h\
+@ENABLE_BITTORRENT_TRUE@	DefaultPieceStorage.cc DefaultPieceStorage.h\
+@ENABLE_BITTORRENT_TRUE@	PeerService.h\
+@ENABLE_BITTORRENT_TRUE@	DefaultPeerStorage.cc DefaultPeerStorage.h\
+@ENABLE_BITTORRENT_TRUE@	BtAnnounce.h\
+@ENABLE_BITTORRENT_TRUE@	DefaultBtAnnounce.cc DefaultBtAnnounce.h\
+@ENABLE_BITTORRENT_TRUE@	BtRegistry.cc BtRegistry.h\
+@ENABLE_BITTORRENT_TRUE@	BtRuntime.h\
+@ENABLE_BITTORRENT_TRUE@	BtProgressInfoFile.h\
+@ENABLE_BITTORRENT_TRUE@	DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\
+@ENABLE_BITTORRENT_TRUE@	BtContextAwareCommand.cc BtContextAwareCommand.h
 
 @ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\
 @ENABLE_METALINK_TRUE@	MetalinkEntry.cc MetalinkEntry.h\
@@ -172,10 +185,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	BitfieldMan.cc BitfieldMan.h NameResolver.cc NameResolver.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 TorrentMan.cc TorrentMan.h \
-	PeerConnection.cc PeerConnection.h PeerMessageUtil.cc \
-	PeerMessageUtil.h PeerAbstractCommand.cc PeerAbstractCommand.h \
-	PeerInitiateConnectionCommand.cc \
+	ShaVisitor.cc ShaVisitor.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 \
 	TorrentDownloadEngine.cc TorrentDownloadEngine.h \
@@ -189,11 +201,11 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	MultiDiskWriter.h DiskAdaptor.cc DiskAdaptor.h \
 	CopyDiskAdaptor.cc CopyDiskAdaptor.h DirectDiskAdaptor.cc \
 	DirectDiskAdaptor.h MultiDiskAdaptor.cc MultiDiskAdaptor.h \
-	FileEntry.h TrackerUpdateCommand.cc TrackerUpdateCommand.h \
-	ByteArrayDiskWriter.cc ByteArrayDiskWriter.h \
-	PeerChokeCommand.cc PeerChokeCommand.h ChokeMessage.cc \
-	ChokeMessage.h UnchokeMessage.cc UnchokeMessage.h \
-	InterestedMessage.cc InterestedMessage.h \
+	FileEntry.cc FileEntry.h TrackerUpdateCommand.cc \
+	TrackerUpdateCommand.h ByteArrayDiskWriter.cc \
+	ByteArrayDiskWriter.h PeerChokeCommand.cc PeerChokeCommand.h \
+	ChokeMessage.cc ChokeMessage.h UnchokeMessage.cc \
+	UnchokeMessage.h InterestedMessage.cc InterestedMessage.h \
 	NotInterestedMessage.cc NotInterestedMessage.h HaveMessage.cc \
 	HaveMessage.h BitfieldMessage.cc BitfieldMessage.h \
 	RequestMessage.cc RequestMessage.h PieceMessage.cc \
@@ -211,9 +223,17 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	PeerListProcessor.h DefaultPeerListProcessor.cc \
 	DefaultPeerListProcessor.h CompactPeerListProcessor.cc \
 	CompactPeerListProcessor.h DelegatingPeerListProcessor.cc \
-	DelegatingPeerListProcessor.h AnnounceList.h AnnounceList.cc \
-	Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \
-	MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \
+	DelegatingPeerListProcessor.h AnnounceTier.h AnnounceList.h \
+	AnnounceList.cc BtContext.h DefaultBtContext.cc \
+	DefaultBtContext.h PieceStorage.h DefaultPieceStorage.cc \
+	DefaultPieceStorage.h PeerService.h DefaultPeerStorage.cc \
+	DefaultPeerStorage.h BtAnnounce.h DefaultBtAnnounce.cc \
+	DefaultBtAnnounce.h BtRegistry.cc BtRegistry.h BtRuntime.h \
+	BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \
+	DefaultBtProgressInfoFile.h BtContextAwareCommand.cc \
+	BtContextAwareCommand.h Metalinker.cc Metalinker.h \
+	MetalinkEntry.cc MetalinkEntry.h MetalinkResource.cc \
+	MetalinkResource.h MetalinkProcessor.h \
 	Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h \
 	MetalinkRequestInfo.cc MetalinkRequestInfo.h
 @ENABLE_ASYNC_DNS_TRUE@am__objects_1 = NameResolver.$(OBJEXT)
@@ -221,7 +241,6 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 @ENABLE_BITTORRENT_TRUE@	Dictionary.$(OBJEXT) List.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	MetaFileUtil.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	ShaVisitor.$(OBJEXT) \
-@ENABLE_BITTORRENT_TRUE@	TorrentMan.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	PeerConnection.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	PeerMessageUtil.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	PeerAbstractCommand.$(OBJEXT) \
@@ -243,6 +262,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 @ENABLE_BITTORRENT_TRUE@	CopyDiskAdaptor.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	DirectDiskAdaptor.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	MultiDiskAdaptor.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	FileEntry.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	TrackerUpdateCommand.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	ByteArrayDiskWriter.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	PeerChokeCommand.$(OBJEXT) \
@@ -270,7 +290,14 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 @ENABLE_BITTORRENT_TRUE@	DefaultPeerListProcessor.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	CompactPeerListProcessor.$(OBJEXT) \
 @ENABLE_BITTORRENT_TRUE@	DelegatingPeerListProcessor.$(OBJEXT) \
-@ENABLE_BITTORRENT_TRUE@	AnnounceList.$(OBJEXT)
+@ENABLE_BITTORRENT_TRUE@	AnnounceList.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	DefaultBtContext.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	DefaultPieceStorage.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	DefaultPeerStorage.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	DefaultBtAnnounce.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	BtRegistry.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	DefaultBtProgressInfoFile.$(OBJEXT) \
+@ENABLE_BITTORRENT_TRUE@	BtContextAwareCommand.$(OBJEXT)
 @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkEntry.$(OBJEXT) \
 @ENABLE_METALINK_TRUE@	MetalinkResource.$(OBJEXT) \
@@ -598,6 +625,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMessage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtContextAwareCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CancelMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChokeMessage.Po@am__quote@
@@ -608,8 +637,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBox.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyDiskAdaptor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounce.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtContext.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtProgressInfoFile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerStorage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DelegatingPeerListProcessor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dictionary.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectDiskAdaptor.Po@am__quote@
@@ -620,6 +654,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadEngineFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfig.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/File.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpConnection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpDownloadCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpInitiateConnectionCommand.Po@am__quote@
@@ -687,7 +722,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentAutoSaveCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentConsoleDownloadEngine.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentDownloadEngine.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentRequestInfo.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerUpdateCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@

+ 9 - 2
src/MultiDiskAdaptor.cc

@@ -46,14 +46,21 @@ string MultiDiskAdaptor::getFilePath() const {
   return storeDir;
 }
 
+void MultiDiskAdaptor::mkdir() const {
+  for(FileEntries::const_iterator itr = fileEntries.begin();
+      itr != fileEntries.end(); itr++) {
+    (*itr)->setupDir(storeDir);
+  }
+}
+
 void MultiDiskAdaptor::openFile() {
-  topDir->createDir(storeDir, true);
+  mkdir();
   setDiskWriterFileEntries();
   DiskAdaptor::openFile();
 }
 
 void MultiDiskAdaptor::initAndOpenFile() {
-  topDir->createDir(storeDir, true);
+  mkdir();
   setDiskWriterFileEntries();
   DiskAdaptor::initAndOpenFile();
 }

+ 1 - 0
src/MultiDiskAdaptor.h

@@ -41,6 +41,7 @@
 class MultiDiskAdaptor : public DiskAdaptor {
 private:
   void setDiskWriterFileEntries();
+  void mkdir() const;
 protected:
   virtual string getFilePath() const;
 public:

+ 10 - 10
src/MultiDiskWriter.cc

@@ -68,7 +68,7 @@ void MultiDiskWriter::setFileEntries(const FileEntries& fileEntries) {
 void MultiDiskWriter::openFile(const string& filename) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry.path);
+    (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry->getPath());
   }
 }
 
@@ -76,7 +76,7 @@ void MultiDiskWriter::openFile(const string& filename) {
 void MultiDiskWriter::initAndOpenFile(const string& filename) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry.path);
+    (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry->getPath());
   }
 }
 
@@ -90,7 +90,7 @@ void MultiDiskWriter::closeFile() {
 void MultiDiskWriter::openExistingFile(const string& filename) {
   for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
       itr != diskWriterEntries.end(); itr++) {
-    (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry.path);
+    (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry->getPath());
   }
 }
 
@@ -107,7 +107,7 @@ void MultiDiskWriter::writeData(const char* data, int len, long long int offset)
       writing = true;
       fileOffset = 0;
     } else {
-      fileOffset -= (*itr)->fileEntry.length;
+      fileOffset -= (*itr)->fileEntry->getLength();
     }
   }
   if(!writing) {
@@ -116,14 +116,14 @@ void MultiDiskWriter::writeData(const char* data, int len, long long int offset)
 }
 
 bool MultiDiskWriter::isInRange(const DiskWriterEntry* entry, long long int offset) const {
-  return entry->fileEntry.offset <= offset &&
-    offset < entry->fileEntry.offset+entry->fileEntry.length;
+  return entry->fileEntry->getOffset() <= offset &&
+    offset < entry->fileEntry->getOffset()+entry->fileEntry->getLength();
 }
 
 int MultiDiskWriter::calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const {
   int length;
-  if(entry->fileEntry.length < fileOffset+rem) {
-    length = entry->fileEntry.length-fileOffset;
+  if(entry->fileEntry->getLength() < fileOffset+rem) {
+    length = entry->fileEntry->getLength()-fileOffset;
   } else {
     length = rem;
   }
@@ -144,7 +144,7 @@ int MultiDiskWriter::readData(char* data, int len, long long int offset) {
       reading = true;
       fileOffset = 0;
     } else {
-      fileOffset -= (*itr)->fileEntry.length;
+      fileOffset -= (*itr)->fileEntry->getLength();
     }
   }
   if(!reading) {
@@ -187,7 +187,7 @@ string MultiDiskWriter::sha1Sum(long long int offset, long long int length) {
 	reading = true;
 	fileOffset = 0;
       } else {
-	fileOffset -= (*itr)->fileEntry.length;
+	fileOffset -= (*itr)->fileEntry->getLength();
       }
     }
     if(!reading) {

+ 4 - 4
src/MultiDiskWriter.h

@@ -36,16 +36,16 @@
 #define _D_MULTI_DISK_WRITER_H_
 
 #include "DefaultDiskWriter.h"
-#include "TorrentMan.h"
 #include "messageDigest.h"
+#include "FileEntry.h"
 
 class DiskWriterEntry {
 public:
-  FileEntry fileEntry;
+  FileEntryHandle fileEntry;
   DiskWriter* diskWriter;
 public:
-  DiskWriterEntry(const FileEntry& fileEntry):fileEntry(fileEntry) {
-    diskWriter = new DefaultDiskWriter(this->fileEntry.length);
+  DiskWriterEntry(const FileEntryHandle& fileEntry):fileEntry(fileEntry) {
+    diskWriter = new DefaultDiskWriter(this->fileEntry->getLength());
   }
   ~DiskWriterEntry() {
     delete diskWriter;

+ 11 - 3
src/Peer.h

@@ -75,11 +75,12 @@ private:
   long long int sessionDownloadLength;
   int pieceLength;
   int latency;
+  bool active;
 public:
-  Peer(string ipaddr, int port, int pieceLength, long long int totalLength)
-    :entryId(0), ipaddr(ipaddr), port(port), error(0),
+  Peer(string ipaddr, int port, int pieceLength, long long int totalLength):
+    entryId(0), ipaddr(ipaddr), port(port), error(0),
     sessionUploadLength(0), sessionDownloadLength(0),
-    pieceLength(pieceLength)
+    pieceLength(pieceLength), active(false)
   {
     resetStatus();
     this->bitfield = new BitfieldMan(pieceLength, totalLength);
@@ -148,10 +149,16 @@ public:
 
   void activate() {
     peerStat.downloadStart();
+    active = true;
   }
 
   void deactivate() {
     peerStat.downloadStop();
+    active = false;
+  }
+
+  bool isActive() const {
+    return active;
   }
 
   void setPeerId(const char* peerId) {
@@ -193,5 +200,6 @@ public:
 };
 
 typedef SharedHandle<Peer> PeerHandle;
+typedef deque<PeerHandle> Peers;
 
 #endif // _D_PEER_H_

+ 8 - 6
src/PeerAbstractCommand.cc

@@ -41,23 +41,25 @@
 
 PeerAbstractCommand::PeerAbstractCommand(int cuid, const PeerHandle& peer,
 					 TorrentDownloadEngine* e,
+					 const BtContextHandle& btContext,
 					 const SocketHandle& s)
-  :Command(cuid), e(e), socket(s), peer(peer),
-  checkSocketIsReadable(false), checkSocketIsWritable(false),
-  uploadLimitCheck(false), uploadLimit(0), noCheck(false) {
+  :BtContextAwareCommand(cuid, btContext), e(e), socket(s), peer(peer),
+   checkSocketIsReadable(false), checkSocketIsWritable(false),
+   uploadLimitCheck(false), uploadLimit(0), noCheck(false)
+{
   setReadCheckSocket(socket);
   timeout = e->option->getAsInt(PREF_TIMEOUT);
-  e->torrentMan->connections++;
+  btRuntime->increaseConnections();
 }
 
 PeerAbstractCommand::~PeerAbstractCommand() {
   disableReadCheckSocket();
   disableWriteCheckSocket();
-  e->torrentMan->connections--;
+  btRuntime->decreaseConnections();
 }
 
 bool PeerAbstractCommand::execute() {
-  if(e->torrentMan->isHalt()) {
+  if(btRuntime->isHalt()) {
     return true;
   }
   try {

+ 4 - 2
src/PeerAbstractCommand.h

@@ -35,12 +35,12 @@
 #ifndef _D_PEER_ABSTRACT_COMMAND_H_
 #define _D_PEER_ABSTRACT_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "Request.h"
 #include "TorrentDownloadEngine.h"
 #include "TimeA2.h"
 
-class PeerAbstractCommand : public Command {
+class PeerAbstractCommand : public BtContextAwareCommand {
 private:
   Time checkPoint;
   int timeout;
@@ -48,6 +48,7 @@ protected:
   TorrentDownloadEngine* e;
   SocketHandle socket;
   PeerHandle peer;
+
   void setTimeout(int timeout) { this->timeout = timeout; }
   virtual bool prepareForNextPeer(int wait);
   virtual bool prepareForRetry(int wait);
@@ -71,6 +72,7 @@ private:
 public:
   PeerAbstractCommand(int cuid, const PeerHandle& peer,
 		      TorrentDownloadEngine* e,
+		      const BtContextHandle& btContext,
 		      const SocketHandle& s = SocketHandle());
   virtual ~PeerAbstractCommand();
   bool execute();

+ 13 - 6
src/PeerChokeCommand.cc

@@ -35,7 +35,14 @@
 #include "PeerChokeCommand.h"
 #include "Util.h"
 
-PeerChokeCommand::PeerChokeCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), interval(interval), e(e), rotate(0) {}
+PeerChokeCommand::PeerChokeCommand(int cuid,
+				   TorrentDownloadEngine* e,
+				   const BtContextHandle& btContext,
+				   int interval):
+  BtContextAwareCommand(cuid, btContext),
+  interval(interval),
+  e(e),
+  rotate(0) {}
 
 PeerChokeCommand::~PeerChokeCommand() {}
 
@@ -89,14 +96,14 @@ void PeerChokeCommand::orderByDownloadRate(Peers& peers) const {
 }
 
 bool PeerChokeCommand::execute() {
-  if(e->torrentMan->isHalt()) {
+  if(btRuntime->isHalt()) {
     return true;
   }
   if(checkPoint.elapsed(interval)) {
     checkPoint.reset();
-    Peers peers = e->torrentMan->getActivePeers();
+    Peers peers = peerStorage->getActivePeers();
     for_each(peers.begin(), peers.end(), ChokePeer());
-    if(e->torrentMan->downloadComplete()) {
+    if(pieceStorage->downloadFinished()) {
       orderByUploadRate(peers);
     } else {
       orderByDownloadRate(peers);
@@ -109,7 +116,7 @@ bool PeerChokeCommand::execute() {
 	peer->chokingRequired = false;
 	peer->optUnchoking = false;
 	itr = peers.erase(itr);
-	if(e->torrentMan->downloadComplete()) {
+	if(pieceStorage->downloadFinished()) {
 	  logger->debug("cat01, unchoking %s, upload speed=%d",
 			peer->ipaddr.c_str(),
 			peer->calculateUploadSpeed());
@@ -128,7 +135,7 @@ bool PeerChokeCommand::execute() {
 	peer->chokingRequired = false;
 	peer->optUnchoking = false;
 	itr = peers.erase(itr);
-	if(e->torrentMan->downloadComplete()) {
+	if(pieceStorage->downloadFinished()) {
 	  logger->debug("cat01, unchoking %s, upload speed=%d",
 			peer->ipaddr.c_str(),
 			peer->calculateUploadSpeed());

+ 7 - 3
src/PeerChokeCommand.h

@@ -35,11 +35,11 @@
 #ifndef _D_PEER_CHOKE_COMMAND_H_
 #define _D_PEER_CHOKE_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 #include "TimeA2.h"
 
-class PeerChokeCommand : public Command {
+class PeerChokeCommand : public BtContextAwareCommand {
 private:
   int interval;
   TorrentDownloadEngine* e;
@@ -51,7 +51,11 @@ private:
   void optUnchokingPeer(Peers& peers) const;
 
 public:
-  PeerChokeCommand(int cuid, TorrentDownloadEngine* e, int interval);
+  PeerChokeCommand(int cuid,
+		   TorrentDownloadEngine* e,
+		   const BtContextHandle& btContext,
+		   int interval);
+
   virtual ~PeerChokeCommand();
 
   bool execute();

+ 0 - 1
src/PeerConnection.h

@@ -38,7 +38,6 @@
 #include "Option.h"
 #include "Socket.h"
 #include "Logger.h"
-#include "TorrentMan.h"
 #include "PeerMessage.h"
 #include "common.h"
 

+ 22 - 8
src/PeerInitiateConnectionCommand.cc

@@ -41,8 +41,9 @@
 
 PeerInitiateConnectionCommand::PeerInitiateConnectionCommand(int cuid,
 							     const PeerHandle& peer,
-							     TorrentDownloadEngine* e)
-  :PeerAbstractCommand(cuid, peer, e) {}
+							     TorrentDownloadEngine* e,
+							     const BtContextHandle& btContext)
+  :PeerAbstractCommand(cuid, peer, e, btContext) {}
 
 PeerInitiateConnectionCommand::~PeerInitiateConnectionCommand() {}
 
@@ -51,7 +52,13 @@ bool PeerInitiateConnectionCommand::executeInternal() {
   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);
+  command =
+    new PeerInteractionCommand(cuid,
+			       peer,
+			       e,
+			       btContext,
+			       socket,
+			       PeerInteractionCommand::INITIATOR_SEND_HANDSHAKE);
 
   e->commands.push_back(command);
   return true;
@@ -59,19 +66,26 @@ bool PeerInitiateConnectionCommand::executeInternal() {
 
 // TODO this method removed when PeerBalancerCommand is implemented
 bool PeerInitiateConnectionCommand::prepareForNextPeer(int wait) {
-  if(e->torrentMan->isPeerAvailable()) {
-    PeerHandle peer = e->torrentMan->getPeer();
-    int newCuid = e->torrentMan->getNewCuid();
+  if(peerStorage->isPeerAvailable() && btRuntime->lessThanEqMinPeer()) {
+    PeerHandle peer = peerStorage->getUnusedPeer();
+    int newCuid = btRuntime->getNewCuid();
     peer->cuid = newCuid;
     PeerInitiateConnectionCommand* command =
-      new PeerInitiateConnectionCommand(newCuid, peer, e);
+      new PeerInitiateConnectionCommand(newCuid,
+					peer,
+					e,
+					btContext);
     e->commands.push_back(command);
   }
   return true;
 }
 
 bool PeerInitiateConnectionCommand::prepareForRetry(int wait) {
-  PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(cuid, peer, e);
+  PeerInitiateConnectionCommand* command =
+    new PeerInitiateConnectionCommand(cuid,
+				      peer,
+				      e,
+				      btContext);
   e->commands.push_back(command);
   return true;
 }

+ 5 - 2
src/PeerInitiateConnectionCommand.h

@@ -43,8 +43,11 @@ protected:
   bool prepareForRetry(int wait);
   bool prepareForNextPeer(int wait);
 public:
-  PeerInitiateConnectionCommand(int cuid,  const PeerHandle& peer,
-				TorrentDownloadEngine* e);
+  PeerInitiateConnectionCommand(int cuid,
+				const PeerHandle& peer,
+				TorrentDownloadEngine* e,
+				const BtContextHandle& btContext);
+
   ~PeerInitiateConnectionCommand();
 };
 

+ 28 - 22
src/PeerInteraction.cc

@@ -39,20 +39,24 @@
 #include "PeerMessageUtil.h"
 #include "Util.h"
 #include "prefs.h"
+#include "BtRegistry.h"
 #include <netinet/in.h>
 
 PeerInteraction::PeerInteraction(int cuid,
 				 const PeerHandle& peer,
 				 const SocketHandle& socket,
 				 const Option* op,
-				 TorrentMan* torrentMan)
+				 const BtContextHandle& btContext)
   :cuid(cuid),
    option(op),
-   torrentMan(torrentMan),
+   btContext(btContext),
+   peerStorage(PEER_STORAGE(btContext)),
+   pieceStorage(PIECE_STORAGE(btContext)),
+   btAnnounce(BT_ANNOUNCE(btContext)),
    peer(peer),
    quickReplied(false) {
   peerConnection = new PeerConnection(cuid, socket, op);
-  peerMessageFactory = new PeerMessageFactory(cuid, this, peer);
+  peerMessageFactory = new PeerMessageFactory(cuid, btContext, this, peer);
   logger = LogFactory::getInstance();
 }
 
@@ -78,7 +82,7 @@ void PeerInteraction::sendMessages() {
     PeerMessageHandle msg = messageQueue.front();
     messageQueue.pop_front();
     if(uploadLimit > 0) {
-      TransferStat stat = torrentMan->calculateStat();
+      TransferStat stat = peerStorage->calculateStat();
       if(uploadLimit < stat.uploadSpeed &&
 	 msg->isUploading() && !msg->isInProgress()) {
 	tempQueue.push_back(msg);
@@ -155,7 +159,7 @@ void PeerInteraction::abortPiece(Piece& piece) {
 	itr++;
       }
     }
-    torrentMan->cancelPiece(piece);
+    pieceStorage->cancelPiece(piece);
   }
 }
 
@@ -184,7 +188,7 @@ void PeerInteraction::checkRequestSlot() {
     } else {
       Piece piece = getDownloadPiece(slot.getIndex());
       if(piece.hasBlock(slot.getBlockIndex()) ||
-	 torrentMan->hasPiece(piece.getIndex())) {
+	 pieceStorage->hasPiece(piece.getIndex())) {
 	logger->debug("CUID#%d - Deleting request slot blockIndex=%d because"
 		      " the block has been acquired.", cuid,
 		      slot.getBlockIndex());
@@ -242,7 +246,7 @@ PeerMessageHandle PeerInteraction::receiveHandshake(bool quickReply) {
   if(!quickReplied && quickReply && msgLength >= 48) {
     quickReplied = true;
     // check info_hash
-    if(memcmp(torrentMan->getInfoHash(), &msg[28], INFO_HASH_LENGTH) == 0) {
+    if(memcmp(btContext->getInfoHash(), &msg[28], INFO_HASH_LENGTH) == 0) {
       sendHandshake();
     }
   }
@@ -272,18 +276,18 @@ PeerMessageHandle PeerInteraction::receiveMessage() {
 
 void PeerInteraction::syncPiece() {
   for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) {
-    torrentMan->syncPiece(*itr);
+    pieceStorage->syncPiece(*itr);
   }
 }
 
 void PeerInteraction::updatePiece() {
   for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) {
-    torrentMan->updatePiece(*itr);
+    pieceStorage->updatePiece(*itr);
   }
 }
 
 void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) {
-  if(pieces.empty() && !torrentMan->hasMissingPiece(peer)) {
+  if(pieces.empty() && !pieceStorage->hasMissingPiece(peer)) {
     if(peer->amInterested) {
       logger->debug("CUID#%d - Not interested in the peer", cuid);
       addMessage(peerMessageFactory->createNotInterestedMessage());
@@ -293,7 +297,7 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) {
       onChoked();
       if(peer->isFastExtensionEnabled()) {
 	while((int)pieces.size() < pieceNum) {
-	  Piece piece = torrentMan->getMissingFastPiece(peer);
+	  Piece piece = pieceStorage->getMissingFastPiece(peer);
 	  if(Piece::isNull(piece)) {
 	    break;
 	  } else {
@@ -303,7 +307,7 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) {
       }
     } else {
       while((int)pieces.size() < pieceNum) {
-	Piece piece = torrentMan->getMissingPiece(peer);
+	Piece piece = pieceStorage->getMissingPiece(peer);
 	if(Piece::isNull(piece)) {
 	  break;
 	} else {
@@ -338,16 +342,16 @@ void PeerInteraction::addRequests() {
     MAX_PENDING_REQUEST = 6;
   }
   int pieceNum;
-  if(torrentMan->isEndGame()) {
+  if(pieceStorage->isEndGame()) {
     pieceNum = 1;
   } else {
-    int blocks = DIV_FLOOR(torrentMan->pieceLength, BLOCK_LENGTH);
+    int blocks = DIV_FLOOR(btContext->getPieceLength(), BLOCK_LENGTH);
     pieceNum = DIV_FLOOR(MAX_PENDING_REQUEST, blocks);
   }
   getNewPieceAndSendInterest(pieceNum);
   for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) {
     Piece& piece = *itr;
-    if(torrentMan->isEndGame()) {
+    if(pieceStorage->isEndGame()) {
       BlockIndexes missingBlockIndexes = piece.getAllMissingBlockIndexes();
       random_shuffle(missingBlockIndexes.begin(), missingBlockIndexes.end());
       int count = countRequestSlot();
@@ -380,23 +384,23 @@ void PeerInteraction::addRequests() {
 
 void PeerInteraction::sendHandshake() {
   PeerMessageHandle handle =
-    peerMessageFactory->createHandshakeMessage(torrentMan->getInfoHash(),
-					       torrentMan->peerId.c_str());
+    peerMessageFactory->createHandshakeMessage(btContext->getInfoHash(),
+					       btAnnounce->getPeerId().c_str());
   addMessage(handle);
   sendMessages();
 }
 
 void PeerInteraction::sendBitfield() {
   if(peer->isFastExtensionEnabled()) {
-    if(torrentMan->hasAllPieces()) {
+    if(pieceStorage->downloadFinished()) {
       addMessage(peerMessageFactory->createHaveAllMessage());
-    } else if(torrentMan->getDownloadLength() > 0) {
+    } else if(pieceStorage->getCompletedLength() > 0) {
       addMessage(peerMessageFactory->createBitfieldMessage());
     } else {
       addMessage(peerMessageFactory->createHaveNoneMessage());
     }
   } else {
-    if(torrentMan->getDownloadLength() > 0) {
+    if(pieceStorage->getCompletedLength() > 0) {
       addMessage(peerMessageFactory->createBitfieldMessage());
     }
   }
@@ -405,8 +409,10 @@ void PeerInteraction::sendBitfield() {
 
 void PeerInteraction::sendAllowedFast() {
   if(peer->isFastExtensionEnabled()) {
-    Integers fastSet = Util::computeFastSet(peer->ipaddr, torrentMan->getInfoHash(),
-				   torrentMan->pieces, ALLOWED_FAST_SET_SIZE);
+    Integers fastSet = Util::computeFastSet(peer->ipaddr,
+					    btContext->getInfoHash(),
+					    btContext->getNumPieces(),
+					    ALLOWED_FAST_SET_SIZE);
     for(Integers::const_iterator itr = fastSet.begin();
 	itr != fastSet.end(); itr++) {
       addMessage(peerMessageFactory->createAllowedFastMessage(*itr));

+ 15 - 4
src/PeerInteraction.h

@@ -37,9 +37,13 @@
 
 #include "common.h"
 #include "PeerConnection.h"
+#include "PeerMessageFactory.h"
 #include "RequestSlot.h"
 #include "SharedHandle.h"
-#include "PeerMessageFactory.h"
+#include "BtContext.h"
+#include "PeerStorage.h"
+#include "PieceStorage.h"
+#include "BtAnnounce.h"
 
 #define REQUEST_TIME_OUT 60
 #define ALLOWED_FAST_SET_SIZE 10
@@ -53,7 +57,10 @@ private:
   RequestSlots requestSlots;
   MessageQueue messageQueue;
   const Option* option;
-  TorrentMan* torrentMan;
+  BtContextHandle btContext;
+  PeerStorageHandle peerStorage;
+  PieceStorageHandle pieceStorage;
+  BtAnnounceHandle btAnnounce;
   PeerConnection* peerConnection;
   PeerHandle peer;
   Pieces pieces;
@@ -70,7 +77,7 @@ public:
 		  const PeerHandle& peer,
 		  const SocketHandle& socket,
 		  const Option* op,
-		  TorrentMan* torrentMan);
+		  const BtContextHandle& btContext);
   ~PeerInteraction();
 
   void addMessage(const PeerMessageHandle& peerMessage);
@@ -89,16 +96,20 @@ public:
 
   int countMessageInQueue() const;
 
-  TorrentMan* getTorrentMan() const { return torrentMan; }
+  BtContextHandle getBtContext() const { return btContext; }
+
   PeerConnection* getPeerConnection() const { return peerConnection; }
+
   // If this object has nullPiece, then return false, otherwise true
   bool hasDownloadPiece(int index) const;
+
   // If the piece which this object has is nullPiece, then throws an exception.
   // So before calling this function, call hasDownloadPiece and make sure
   // this has valid piece, not nullPiece.
   Piece& getDownloadPiece(int index);
   
   bool isInFastSet(int index) const;
+
   void addFastSetIndex(int index);
 
   void syncPiece();

+ 18 - 14
src/PeerInteractionCommand.cc

@@ -49,26 +49,27 @@
 PeerInteractionCommand::PeerInteractionCommand(int cuid,
 					       const PeerHandle& p,
 					       TorrentDownloadEngine* e,
+					       const BtContextHandle& btContext,
 					       const SocketHandle& s,
 					       int sequence)
-  :PeerAbstractCommand(cuid, p, e, s), sequence(sequence) {
+  :PeerAbstractCommand(cuid, p, e, btContext, s), sequence(sequence) {
   if(sequence == INITIATOR_SEND_HANDSHAKE) {
     disableReadCheckSocket();
     setWriteCheckSocket(socket);
     setTimeout(e->option->getAsInt(PREF_PEER_CONNECTION_TIMEOUT));
   }
   peerInteraction = new PeerInteraction(cuid, peer, socket, e->option,
-					e->torrentMan);
+					btContext);
   setUploadLimit(e->option->getAsInt(PREF_MAX_UPLOAD_LIMIT));
   chokeUnchokeCount = 0;
   haveCount = 0;
   keepAliveCount = 0;
-  e->torrentMan->addActivePeer(peer);
+  peer->activate();
 }
 
 PeerInteractionCommand::~PeerInteractionCommand() {
   delete peerInteraction;
-  e->torrentMan->deleteActivePeer(peer);
+  peer->deactivate();
 }
 
 bool PeerInteractionCommand::executeInternal() {
@@ -173,7 +174,7 @@ void PeerInteractionCommand::detectMessageFlooding() {
 
 /*
 void PeerInteractionCommand::checkLongTimePeerChoking() {
-  if(e->torrentMan->downloadComplete()) {
+  if(pieceStorage->downloadFinished()) {
     return;
   }    
   if(peer->amInterested && peer->peerChoking) {
@@ -205,7 +206,7 @@ void PeerInteractionCommand::receiveMessages() {
   for(int i = 0; i < 50; i++) {
     int maxSpeedLimit = e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT);
     if(maxSpeedLimit > 0) {
-      TransferStat stat = e->torrentMan->calculateStat();
+      TransferStat stat = peerStorage->calculateStat();
       if(maxSpeedLimit < stat.downloadSpeed) {
 	disableReadCheckSocket();
 	setNoCheck(true);
@@ -245,12 +246,15 @@ void PeerInteractionCommand::receiveMessages() {
 
 // TODO this method removed when PeerBalancerCommand is implemented
 bool PeerInteractionCommand::prepareForNextPeer(int wait) {
-  if(e->torrentMan->isPeerAvailable()) {
-    PeerHandle peer = e->torrentMan->getPeer();
-    int newCuid = e->torrentMan->getNewCuid();
+  if(peerStorage->isPeerAvailable() && btRuntime->lessThanEqMinPeer()) {
+    PeerHandle peer = peerStorage->getUnusedPeer();
+    int newCuid = btRuntime->getNewCuid();
     peer->cuid = newCuid;
     PeerInitiateConnectionCommand* command =
-      new PeerInitiateConnectionCommand(newCuid, peer, e);
+      new PeerInitiateConnectionCommand(newCuid,
+					peer,
+					e,
+					btContext);
     e->commands.push_back(command);
   }
   return true;
@@ -278,12 +282,12 @@ void PeerInteractionCommand::sendKeepAlive() {
 }
 
 void PeerInteractionCommand::checkHave() {
-  PieceIndexes indexes =
-    e->torrentMan->getAdvertisedPieceIndexes(cuid, haveCheckTime);
+  Integers indexes =
+    pieceStorage->getAdvertisedPieceIndexes(cuid, haveCheckTime);
   haveCheckTime.reset();
   if(indexes.size() >= 20) {
     if(peer->isFastExtensionEnabled()) {
-      if(e->torrentMan->hasAllPieces()) {
+      if(pieceStorage->downloadFinished()) {
 	peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()->
 				    createHaveAllMessage());
       } else {
@@ -295,7 +299,7 @@ void PeerInteractionCommand::checkHave() {
 				  createBitfieldMessage());
     }
   } else {
-    for(PieceIndexes::iterator itr = indexes.begin(); itr != indexes.end(); itr++) {
+    for(Integers::iterator itr = indexes.begin(); itr != indexes.end(); itr++) {
       peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()->
 				  createHaveMessage(*itr));
     }

+ 2 - 0
src/PeerInteractionCommand.h

@@ -73,7 +73,9 @@ protected:
 public:
   PeerInteractionCommand(int cuid, const PeerHandle& peer,
 			 TorrentDownloadEngine* e,
+			 const BtContextHandle& btContext,
 			 const SocketHandle& s, int sequence);
+
   ~PeerInteractionCommand();
 
   enum Seq {

+ 0 - 2
src/PeerListProcessor.h

@@ -40,8 +40,6 @@
 #include "Peer.h"
 #include "SharedHandle.h"
 
-typedef deque<PeerHandle> Peers;
-
 class PeerListProcessor {
 public:
   virtual ~PeerListProcessor() {}

+ 14 - 9
src/PeerListenCommand.cc

@@ -35,8 +35,11 @@
 #include "PeerListenCommand.h"
 #include "PeerInteractionCommand.h"
 
-PeerListenCommand::PeerListenCommand(int cuid, TorrentDownloadEngine* e)
-  :Command(cuid), e(e) {}
+PeerListenCommand::PeerListenCommand(int cuid,
+				     TorrentDownloadEngine* e,
+				     const BtContextHandle& btContext)
+  :BtContextAwareCommand(cuid, btContext),
+   e(e) {}
 
 PeerListenCommand::~PeerListenCommand() {}
 
@@ -61,7 +64,7 @@ int PeerListenCommand::bindPort(int portRangeStart, int portRangeEnd) {
 }
 
 bool PeerListenCommand::execute() {
-  if(e->torrentMan->isHalt()) {
+  if(btRuntime->isHalt()) {
     return true;
   }
   for(int i = 0; i < 3 && socket->isReadable(0); i++) {
@@ -73,15 +76,17 @@ bool PeerListenCommand::execute() {
       pair<string, int> localInfo;
       peerSocket->getAddrInfo(localInfo);
       if(peerInfo.first != localInfo.first &&
-	 e->torrentMan->connections < MAX_PEERS) {
+	 btRuntime->getConnections() < MAX_PEERS) {
 	PeerHandle peer = PeerHandle(new Peer(peerInfo.first, peerInfo.second,
-					      e->torrentMan->pieceLength,
-					      e->torrentMan->getTotalLength()));
-	if(e->torrentMan->addPeer(peer)) {
-	  int newCuid =  e->torrentMan->getNewCuid();
+					      btContext->getPieceLength(),
+					      btContext->getTotalLength()));
+	if(peerStorage->addPeer(peer)) {
+	  int newCuid =  btRuntime->getNewCuid();
 	  peer->cuid = newCuid;
 	  PeerInteractionCommand* command =
-	    new PeerInteractionCommand(newCuid, peer, e, peerSocket,
+	    new PeerInteractionCommand(newCuid, peer, e,
+				       btContext,
+				       peerSocket,
 				       PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE);
 	  e->commands.push_back(command);
 	  logger->debug("CUID#%d - incoming connection, adding new command CUID#%d", cuid, newCuid);

+ 6 - 3
src/PeerListenCommand.h

@@ -35,15 +35,18 @@
 #ifndef _D_PEER_LISTEN_COMMAND_H_
 #define _D_PEER_LISTEN_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 
-class PeerListenCommand : public Command {
+class PeerListenCommand : public BtContextAwareCommand {
 private:
   TorrentDownloadEngine* e;
   SocketHandle socket;
 public:
-  PeerListenCommand(int cuid, TorrentDownloadEngine* e);
+  PeerListenCommand(int cuid,
+		    TorrentDownloadEngine* e,
+		    const BtContextHandle& btContext);
+
   ~PeerListenCommand();
   
   bool execute();

+ 5 - 1
src/PeerMessage.cc

@@ -38,6 +38,10 @@
 PeerMessage::PeerMessage()
   :inProgress(false),
    invalidate(false),
-   uploading(false) {
+   uploading(false),
+   btContext(0),
+   peerStorage(0),
+   pieceStorage(0)
+ {
   logger = LogFactory::getInstance();
 }

+ 18 - 1
src/PeerMessage.h

@@ -39,7 +39,10 @@
 #include "Logger.h"
 #include "Peer.h"
 #include "Piece.h"
-#include "SharedHandle.h"
+#include "BtContext.h"
+#include "PeerStorage.h"
+#include "PieceStorage.h"
+#include "BtRegistry.h"
 #include <string>
 
 class PeerInteraction;
@@ -53,6 +56,9 @@ protected:
   PeerHandle peer;
   PeerInteraction* peerInteraction;
   const Logger* logger;
+  BtContextHandle btContext;
+  PeerStorageHandle peerStorage;
+  PieceStorageHandle pieceStorage;
 public:
   PeerMessage();
 
@@ -63,18 +69,29 @@ public:
   bool isUploading() const { return uploading; }
 
   int getCuid() const { return cuid; }
+
   void setCuid(int cuid) {
     this->cuid = cuid;
   }
+
   PeerHandle getPeer() const { return this->peer; }
+
   void setPeer(const PeerHandle& peer) {
     this->peer = peer;
   }
+
   PeerInteraction* getPeerInteraction() const { return peerInteraction; }
+
   void setPeerInteraction(PeerInteraction* peerInteraction) {
     this->peerInteraction = peerInteraction;
   }
 
+  void setBtContext(const BtContextHandle& btContext) {
+    this->btContext = btContext;
+    pieceStorage = PIECE_STORAGE(btContext);
+    peerStorage = PEER_STORAGE(btContext);
+  }
+
   virtual int getId() const = 0;
   virtual void receivedAction() = 0;
   virtual void send() = 0;

+ 20 - 20
src/PeerMessageFactory.cc

@@ -33,7 +33,6 @@
  */
 /* copyright --> */
 #include "PeerMessageFactory.h"
-#include "PeerInteraction.h"
 #include "PeerMessageUtil.h"
 #include "ChokeMessage.h"
 #include "UnchokeMessage.h"
@@ -54,11 +53,16 @@
 #include "SuggestPieceMessage.h"
 #include "RequestSlot.h"
 #include "DlAbortEx.h"
+#include "BtRegistry.h"
+#include "PeerInteraction.h"
 
 PeerMessageFactory::PeerMessageFactory(int cuid,
+				       const BtContextHandle& btContext,
 				       PeerInteraction* peerInteraction,
 				       const PeerHandle& peer)
   :cuid(cuid),
+   btContext(btContext),
+   pieceStorage(PIECE_STORAGE(btContext)),
    peerInteraction(peerInteraction),
    peer(peer) {}
 
@@ -86,29 +90,26 @@ PeerMessageHandle PeerMessageFactory::createPeerMessage(const char* msg, int msg
       break;
     case HaveMessage::ID:
       peerMessage = HaveMessage::create(msg, msgLength);
-      ((HaveMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->
-					     pieces);
+      ((HaveMessage*)peerMessage)->setPieces(btContext->getNumPieces());
       break;
     case BitfieldMessage::ID:
       peerMessage = BitfieldMessage::create(msg, msgLength);
-      ((BitfieldMessage*)peerMessage)->setPieces(peerInteraction->
-						 getTorrentMan()->pieces);
+      ((BitfieldMessage*)peerMessage)->setPieces(btContext->getNumPieces());
       break;
     case RequestMessage::ID:
       peerMessage = RequestMessage::create(msg, msgLength);
-      ((RequestMessage*)peerMessage)->setPieces(peerInteraction->
-						getTorrentMan()->pieces);
-      ((RequestMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((RequestMessage*)peerMessage)->getIndex()));
+      ((RequestMessage*)peerMessage)->setPieces(btContext->getNumPieces());
+      ((RequestMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((RequestMessage*)peerMessage)->getIndex()));
       break;
     case CancelMessage::ID:
       peerMessage = CancelMessage::create(msg, msgLength);
-      ((CancelMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces);
-      ((CancelMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((CancelMessage*)peerMessage)->getIndex()));
+      ((CancelMessage*)peerMessage)->setPieces(btContext->getNumPieces());
+      ((CancelMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((CancelMessage*)peerMessage)->getIndex()));
       break;
     case PieceMessage::ID:
       peerMessage = PieceMessage::create(msg, msgLength);
-      ((PieceMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces);
-      ((PieceMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((PieceMessage*)peerMessage)->getIndex()));
+      ((PieceMessage*)peerMessage)->setPieces(btContext->getNumPieces());
+      ((PieceMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((PieceMessage*)peerMessage)->getIndex()));
       break;
     case PortMessage::ID:
       peerMessage = PortMessage::create(msg, msgLength);
@@ -121,16 +122,16 @@ PeerMessageHandle PeerMessageFactory::createPeerMessage(const char* msg, int msg
       break;
     case RejectMessage::ID:
       peerMessage = RejectMessage::create(msg, msgLength);
-      ((RejectMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces);
-      ((RejectMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((RejectMessage*)peerMessage)->getIndex()));
+      ((RejectMessage*)peerMessage)->setPieces(btContext->getNumPieces());
+      ((RejectMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((RejectMessage*)peerMessage)->getIndex()));
       break;
     case SuggestPieceMessage::ID:
       peerMessage = SuggestPieceMessage::create(msg, msgLength);
-      ((SuggestPieceMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces);
+      ((SuggestPieceMessage*)peerMessage)->setPieces(btContext->getNumPieces());
       break;
     case AllowedFastMessage::ID:
       peerMessage = AllowedFastMessage::create(msg, msgLength);
-      ((AllowedFastMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces);
+      ((AllowedFastMessage*)peerMessage)->setPieces(btContext->getNumPieces());
       break;
     default:
       throw new DlAbortEx("Invalid message id. id = %d", id);
@@ -167,6 +168,7 @@ PeerMessageFactory::setPeerMessageCommonProperty(PeerMessageHandle& peerMessage)
   peerMessage->setPeer(peer);
   peerMessage->setCuid(cuid);
   peerMessage->setPeerInteraction(peerInteraction);
+  peerMessage->setBtContext(btContext);
 }
 
 PeerMessageHandle PeerMessageFactory::createRequestMessage(const Piece& piece,
@@ -235,10 +237,8 @@ PeerMessageHandle PeerMessageFactory::createNotInterestedMessage() const {
 
 PeerMessageHandle PeerMessageFactory::createBitfieldMessage() const {
   PeerMessageHandle handle =
-    PeerMessageHandle(new BitfieldMessage(peerInteraction->getTorrentMan()->
-					  getBitfield(),
-					  peerInteraction->getTorrentMan()->
-					  getBitfieldLength()));
+    PeerMessageHandle(new BitfieldMessage(pieceStorage->getBitfield(),
+					  pieceStorage->getBitfieldLength()));
   setPeerMessageCommonProperty(handle);
   return handle;
 }

+ 5 - 0
src/PeerMessageFactory.h

@@ -38,18 +38,23 @@
 #include "common.h"
 #include "PeerMessage.h"
 #include "HandshakeMessage.h"
+#include "BtContext.h"
+#include "PieceStorage.h"
 
 class PeerInteraction;
 
 class PeerMessageFactory {
 private:
   int cuid;
+  BtContextHandle btContext;
+  PieceStorageHandle pieceStorage;
   PeerInteraction* peerInteraction;
   PeerHandle peer;
 
   void setPeerMessageCommonProperty(PeerMessageHandle& peerMessage) const;
 public:
   PeerMessageFactory(int cuid,
+		     const BtContextHandle& btContext,
 		     PeerInteraction* peerInteraction,
 		     const PeerHandle& peer);
 

+ 128 - 0
src/PeerStorage.h

@@ -0,0 +1,128 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_PEER_STORAGE_H_
+#define _D_PEER_STORAGE_H_
+
+#include "common.h"
+#include "Peer.h"
+
+class TransferStat {
+public:
+  int downloadSpeed;
+  int uploadSpeed;
+  long long int sessionDownloadLength;
+  long long int sessionUploadLength;
+public:
+  TransferStat():downloadSpeed(0), uploadSpeed(0),
+		 sessionDownloadLength(0), sessionUploadLength(0) {}
+
+  int getDownloadSpeed() const {
+    return downloadSpeed;
+  }
+
+  void setDownloadSpeed(int s) { downloadSpeed = s; }
+
+  int getUploadSpeed() const {
+    return uploadSpeed;
+  }
+
+  void setUploadSpeed(int s) { uploadSpeed = s; }
+
+  /**
+   * Returns the number of bytes downloaded since the program started.
+   * This is not the total number of bytes downloaded.
+   */
+  long long int getSessionDownloadLength() const {
+    return sessionDownloadLength;
+  }
+
+  void setSessionDownloadLength(long long int s) { sessionDownloadLength = s; }
+
+  /**
+   * Returns the number of bytes uploaded since the program started.
+   * This is not the total number of bytes uploaded.
+   */
+  long long int getSessionUploadLength() const {
+    return sessionUploadLength;
+  }
+
+  void setSessionUploadLength(long long int s) { sessionUploadLength = s; }
+};
+
+class PeerStorage {
+public:
+  virtual ~PeerStorage() {}
+
+  /**
+   * Adds new peer to internal peer list.
+   * If the peer is added successfully, returns true. Otherwise returns false.
+   */
+  virtual bool addPeer(const PeerHandle& peer) = 0;
+
+  /**
+   * Adds all peers in peers to internal peer list.
+   */
+  virtual void addPeer(const Peers& peers) = 0;
+
+  /**
+   * Returns internal peer list.
+   */
+  virtual const Peers& getPeers() = 0;
+
+  /**
+   * Returns one of the unused peers.
+   */
+  virtual PeerHandle getUnusedPeer() = 0;
+
+  /**
+   * Returns true if at least one unused peer exists.
+   * Otherwise returns false.
+   */
+  virtual bool isPeerAvailable() = 0;
+  
+  /**
+   * Returns the list of peers which are currently connected from localhost.
+   */
+  virtual Peers getActivePeers() = 0;
+
+  /**
+   * Calculates current download/upload statistics.
+   */
+  virtual TransferStat calculateStat() = 0;
+};
+
+typedef SharedHandle<PeerStorage> PeerStorageHandle;
+
+#endif // _D_PEER_STORAGE_H_

+ 5 - 0
src/Piece.cc

@@ -33,6 +33,7 @@
  */
 /* copyright --> */
 #include "Piece.h"
+#include "Util.h"
 
 Piece Piece::nullPiece;
 
@@ -79,3 +80,7 @@ int Piece::getMissingBlockIndex() const {
 BlockIndexes Piece::getAllMissingBlockIndexes() const {
   return bitfield->getAllMissingIndexes();
 }
+
+string Piece::toString() const {
+  return "piece: index="+Util::itos(index)+", length="+Util::itos(length);
+}

+ 4 - 0
src/Piece.h

@@ -117,10 +117,14 @@ public:
   void clearAllBlock();
   void setAllBlock();
 
+  string toString() const;
+
   static Piece nullPiece;
   static bool isNull(const Piece& piece) {
     return piece.index == 0 && piece.length == 0;
   }
 };
 
+typedef deque<Piece> Pieces;
+
 #endif // _D_PIECE_H_

+ 18 - 26
src/PieceMessage.cc

@@ -65,7 +65,6 @@ PieceMessage* PieceMessage::create(const char* data, int dataLength) {
 }
 
 void PieceMessage::receivedAction() {
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   RequestSlot slot = peerInteraction->getCorrespondingRequestSlot(index,
 								  begin,
 								  blockLength);
@@ -77,15 +76,15 @@ void PieceMessage::receivedAction() {
     peer->updateLatency(slot.getLatencyInMillis());
     Piece& piece = peerInteraction->getDownloadPiece(slot.getIndex());
     long long int offset =
-      ((long long int)index)*torrentMan->pieceLength+begin;
+      ((long long int)index)*btContext->getPieceLength()+begin;
     logger->debug("CUID#%d - Writing the block length=%d, offset=%lld",
 		  cuid, blockLength, offset);      
-    torrentMan->diskAdaptor->writeData(block,
-				       blockLength,
-				       offset);
+    pieceStorage->getDiskAdaptor()->writeData(block,
+					      blockLength,
+					      offset);
     piece.completeBlock(slot.getBlockIndex());
     peerInteraction->deleteRequestSlot(slot);
-    torrentMan->updatePiece(piece);
+    pieceStorage->updatePiece(piece);
     logger->debug("CUID#%d - Setting piece block index=%d",
 		  cuid, slot.getBlockIndex());
     if(piece.pieceComplete()) {
@@ -123,7 +122,6 @@ void PieceMessage::send() {
   if(invalidate) {
     return;
   }
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   PeerConnection* peerConnection = peerInteraction->getPeerConnection();
   if(!headerSent) {
     if(!inProgress) {
@@ -146,13 +144,11 @@ void PieceMessage::send() {
   }
   if(headerSent) {
     inProgress = false;
-    int pieceLength = torrentMan->pieceLength;
     long long int pieceDataOffset =
-      ((long long int)index)*pieceLength+begin+blockLength-leftDataLength;
+      ((long long int)index)*btContext->getPieceLength()+begin+blockLength-leftDataLength;
     int writtenLength =
       sendPieceData(pieceDataOffset, leftDataLength);
     peer->updateUploadLength(writtenLength);
-    torrentMan->addUploadLength(writtenLength);
     if(writtenLength != leftDataLength) {
       inProgress = true;
     }
@@ -165,10 +161,9 @@ int PieceMessage::sendPieceData(long long int offset, int length) const {
   char buf[BUF_SIZE];
   int iteration = length/BUF_SIZE;
   int writtenLength = 0;
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   PeerConnection* peerConnection = peerInteraction->getPeerConnection();
   for(int i = 0; i < iteration; i++) {
-    if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
+    if(pieceStorage->getDiskAdaptor()->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
       throw new DlAbortEx("Failed to read data from disk.");
     }
     int ws = peerConnection->sendMessage(buf, BUF_SIZE);
@@ -181,7 +176,7 @@ int PieceMessage::sendPieceData(long long int offset, int length) const {
 
   int rem = length%BUF_SIZE;
   if(rem > 0) {
-    if(torrentMan->diskAdaptor->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
+    if(pieceStorage->getDiskAdaptor()->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
       throw new DlAbortEx("Failed to read data from disk.");
     }
     int ws = peerConnection->sendMessage(buf, rem);
@@ -202,42 +197,39 @@ string PieceMessage::toString() const {
 }
 
 bool PieceMessage::checkPieceHash(const Piece& piece) {
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   long long int offset =
-    ((long long int)piece.getIndex())*torrentMan->pieceLength;
-  return torrentMan->diskAdaptor->sha1Sum(offset, piece.getLength()) ==
-    torrentMan->getPieceHash(piece.getIndex());
+    ((long long int)piece.getIndex())*btContext->getPieceLength();
+  return pieceStorage->getDiskAdaptor()->sha1Sum(offset, piece.getLength()) ==
+    btContext->getPieceHash(piece.getIndex());
 }
 
 void PieceMessage::onGotNewPiece(Piece& piece) {
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   logger->info(MSG_GOT_NEW_PIECE, cuid, piece.getIndex());
-  torrentMan->completePiece(piece);
-  torrentMan->advertisePiece(cuid, piece.getIndex());
+  pieceStorage->completePiece(piece);
+  pieceStorage->advertisePiece(cuid, piece.getIndex());
 }
 
 void PieceMessage::onGotWrongPiece(Piece& piece) {
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   logger->error(MSG_GOT_WRONG_PIECE, cuid, piece.getIndex());
   erasePieceOnDisk(piece);
   piece.clearAllBlock();
-  torrentMan->updatePiece(piece);
+  pieceStorage->updatePiece(piece);
   peerInteraction->abortPiece(piece);
 }
 
 void PieceMessage::erasePieceOnDisk(const Piece& piece) {
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
   int BUFSIZE = 4096;
   char buf[BUFSIZE];
   memset(buf, 0, BUFSIZE);
-  long long int offset = ((long long int)piece.getIndex())*torrentMan->pieceLength;
+  long long int offset =
+    ((long long int)piece.getIndex())*btContext->getPieceLength();
   for(int i = 0; i < piece.getLength()/BUFSIZE; i++) {
-    torrentMan->diskAdaptor->writeData(buf, BUFSIZE, offset);
+    pieceStorage->getDiskAdaptor()->writeData(buf, BUFSIZE, offset);
     offset += BUFSIZE;
   }
   int r = piece.getLength()%BUFSIZE;
   if(r > 0) {
-    torrentMan->diskAdaptor->writeData(buf, r, offset);
+    pieceStorage->getDiskAdaptor()->writeData(buf, r, offset);
   }
 }
 

+ 0 - 1
src/PieceMessage.h

@@ -36,7 +36,6 @@
 #define _D_PIECE_MESSAGE_H_
 
 #include "PeerMessage.h"
-#include "TorrentMan.h"
 
 class PieceMessage : public PeerMessage {
 private:

+ 157 - 0
src/PieceStorage.h

@@ -0,0 +1,157 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_PIECE_STORAGE_H_
+#define _D_PIECE_STORAGE_H_
+
+#include "common.h"
+#include "Peer.h"
+#include "Piece.h"
+#include "DiskAdaptor.h"
+
+class PieceStorage {
+public:
+  virtual ~PieceStorage() {}
+
+  /**
+   * Returns true if the peer has a piece that localhost doesn't have.
+   * Otherwise returns false.
+   */
+  virtual bool hasMissingPiece(const PeerHandle& peer) = 0;
+
+  /**
+   * Returns a piece that the peer has but localhost doesn't.
+   * The piece will be marked "used" status in order to prevent other command
+   * from get the same piece. But in end game mode, same piece may be returned
+   * to several commands.
+   */
+  virtual Piece getMissingPiece(const PeerHandle& peer) = 0;
+  /**
+   * Returns a piece that the peer has but localhost doesn't.
+   * Only pieces that declared as "fast" are returned.
+   * The piece will be marked "used" status in order to prevent other command
+   * from get the same piece. But in end game mode, same piece may be returned
+   * to several commands.
+   */
+  virtual Piece getMissingFastPiece(const PeerHandle& peer) = 0;
+
+  /**
+   * Tells that the download of the specfied piece completes.
+   */
+  virtual void completePiece(const Piece& piece) = 0;
+
+  /**
+   * Tells that the download of the specified piece is canceled.
+   */
+  virtual void cancelPiece(const Piece& piece) = 0;
+
+  /**
+   * Updates the internal piece data with the specified piece data.
+   */
+  virtual void updatePiece(const Piece& piece) = 0;
+
+  /**
+   * Updates the spcefied piece data with the internal piece data.
+   */
+  virtual void syncPiece(Piece& piece) = 0;
+
+  /**
+   * Returns true if the specified piece is already downloaded.
+   * Otherwise returns false.
+   */
+  virtual bool hasPiece(int index) = 0;
+
+  virtual long long int getTotalLength() = 0;
+
+  virtual long long int getFilteredTotalLength() = 0;
+
+  virtual long long int getCompletedLength() = 0;
+
+  virtual long long int getFilteredCompletedLength() = 0;
+  
+  virtual void setFileFilter(const Strings& filePaths) = 0;
+
+  virtual void setFileFilter(const Integers& fileIndexes) = 0;
+
+  virtual void clearFileFilter() = 0;
+
+  virtual bool downloadFinished() = 0;
+
+  /**
+   * Initializes DiskAdaptor.
+   * TODO add better documentation here.
+   */
+  virtual void initStorage() = 0;
+
+  virtual const unsigned char* getBitfield() = 0;
+
+  virtual void setBitfield(const unsigned char* bitfield,
+			   int bitfieldLength) = 0;
+  
+  virtual int getBitfieldLength() = 0;
+
+  virtual bool isSelectiveDownloadingMode() = 0;
+
+  virtual void finishSelectiveDownloadingMode() = 0;
+
+  virtual bool isEndGame() = 0;
+
+  virtual DiskAdaptor* getDiskAdaptor() = 0;
+  
+  virtual int getPieceLength(int index) = 0;
+
+  /**
+   * Adds piece index to advertise to other commands. They send have message
+   * based on this information.
+   */
+  virtual void advertisePiece(int cuid, int index) = 0;
+
+  /**
+   * Returns piece index which is not advertised by the caller command and
+   * newer than lastCheckTime.
+   */
+  virtual Integers getAdvertisedPieceIndexes(int myCuid,
+					     const Time& lastCheckTime) = 0;
+
+  /**
+   * Removes have entry if specified seconds have elapsed since its
+   * registration.
+   */
+  virtual void removeAdvertisedPiece(int elapsed) = 0;
+
+};
+
+typedef SharedHandle<PieceStorage> PieceStorageHandle;
+
+#endif // _D_PIECE_STORAGE_H_

+ 0 - 1
src/RejectMessage.h

@@ -36,7 +36,6 @@
 #define _D_REJECT_MESSAGE_H_
 
 #include "SimplePeerMessage.h"
-#include "TorrentMan.h"
 
 class RejectMessage : public SimplePeerMessage {
 private:

+ 1 - 2
src/RequestMessage.cc

@@ -55,8 +55,7 @@ RequestMessage* RequestMessage::create(const char* data, int dataLength) {
 }
 
 void RequestMessage::receivedAction() {
-  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
-  if(torrentMan->hasPiece(index) &&
+  if(pieceStorage->hasPiece(index) &&
      (!peer->amChoking ||
       peer->amChoking && peerInteraction->isInFastSet(index))) {
     peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()->

+ 0 - 1
src/RequestMessage.h

@@ -36,7 +36,6 @@
 #define _D_REQUEST_MESSAGE_H_
 
 #include "SimplePeerMessage.h"
-#include "TorrentMan.h"
 
 class RequestMessage : public SimplePeerMessage {
 private:

+ 12 - 3
src/SeedCheckCommand.cc

@@ -34,8 +34,17 @@
 /* copyright --> */
 #include "SeedCheckCommand.h"
 
+SeedCheckCommand::SeedCheckCommand(int cuid,
+				   TorrentDownloadEngine* e,
+				   const BtContextHandle& btContext,
+				   SeedCriteriaHandle seedCriteria)
+  :BtContextAwareCommand(cuid, btContext),
+   e(e),
+   seedCriteria(seedCriteria),
+   checkStarted(false) {}
+
 bool SeedCheckCommand::execute() {
-  if(e->torrentMan->isHalt()) {
+  if(btRuntime->isHalt()) {
     return true;
   }
   if(!seedCriteria.get()) {
@@ -43,7 +52,7 @@ bool SeedCheckCommand::execute() {
   }
   if(checkPoint.elapsed(1)) {
     if(!checkStarted) {
-      if(e->torrentMan->downloadComplete()) {
+      if(pieceStorage->downloadFinished()) {
 	checkStarted = true;
 	seedCriteria->reset();
       }
@@ -51,7 +60,7 @@ bool SeedCheckCommand::execute() {
     if(checkStarted) {
       if(seedCriteria->evaluate()) {
 	logger->notice("CUID#%d - Seeding is over.", cuid);
-	e->torrentMan->setHalt(true);
+	btRuntime->setHalt(true);
       }
     }
   }

+ 6 - 8
src/SeedCheckCommand.h

@@ -35,24 +35,22 @@
 #ifndef _D_SEED_CHECK_COMMAND_H_
 #define _D_SEED_CHECK_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 #include "TimeA2.h"
 #include "SeedCriteria.h"
 
-class SeedCheckCommand : public Command {
+class SeedCheckCommand : public BtContextAwareCommand {
 private:
   TorrentDownloadEngine* e;
   Time checkPoint;
   SeedCriteriaHandle seedCriteria;
   bool checkStarted;
 public:
-  SeedCheckCommand(int cuid, TorrentDownloadEngine* e,
-		   SeedCriteriaHandle seedCriteria)
-    :Command(cuid),
-     e(e),
-     seedCriteria(seedCriteria),
-     checkStarted(false) {}
+  SeedCheckCommand(int cuid,
+		   TorrentDownloadEngine* e,
+		   const BtContextHandle& btContext,
+		   SeedCriteriaHandle seedCriteria);
 
   virtual ~SeedCheckCommand() {}
 

+ 17 - 6
src/ShareRatioSeedCriteria.h

@@ -36,26 +36,37 @@
 #define _D_SHARE_RATIO_SEED_CRITERIA_H_
 
 #include "SeedCriteria.h"
-#include "TorrentMan.h"
+#include "BtContext.h"
+#include "PeerStorage.h"
+#include "BtRuntime.h"
+#include "BtRegistry.h"
 
 class ShareRatioSeedCriteria : public SeedCriteria {
 private:
   double ratio;
-  TorrentMan* torrentMan;
+  BtContextHandle btContext;
+  PeerStorageHandle peerStorage;
+  BtRuntimeHandle btRuntime;
 public:
-  ShareRatioSeedCriteria(double ratio, TorrentMan* torrentMan)
+  ShareRatioSeedCriteria(double ratio, const BtContextHandle& btContext)
     :ratio(ratio),
-     torrentMan(torrentMan) {}
+     btContext(btContext),
+     peerStorage(PEER_STORAGE(btContext)),
+     btRuntime(BT_RUNTIME(btContext)) {}
+
   virtual ~ShareRatioSeedCriteria() {}
 
   virtual void reset() {}
 
   virtual bool evaluate() {
-    if(torrentMan->getDownloadLength() == 0) {
+    if(btContext->getTotalLength() == 0) {
       return false;
     }
+    TransferStat stat = peerStorage->calculateStat();
+    long long int allTimeUploadLength =
+      btRuntime->getUploadLengthAtStartup()+stat.getSessionUploadLength();
     return ratio <=
-      ((double)torrentMan->getUploadLength())/torrentMan->getDownloadLength();
+      ((double)allTimeUploadLength)/btContext->getTotalLength();
   }
 
   void setRatio(double ratio) {

+ 10 - 4
src/TorrentAutoSaveCommand.cc

@@ -35,15 +35,21 @@
 #include "TorrentAutoSaveCommand.h"
 #include "Util.h"
 
-TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), e(e), interval(interval) {}
+TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid,
+					       TorrentDownloadEngine* e,
+					       const BtContextHandle& btContext,
+					       int interval):
+  BtContextAwareCommand(cuid, btContext),
+  e(e),
+  interval(interval) {}
 
 TorrentAutoSaveCommand::~TorrentAutoSaveCommand() {}
 
 bool TorrentAutoSaveCommand::execute() {
-  if(checkPoint.elapsed(interval) || e->torrentMan->isHalt()) {
+  if(checkPoint.elapsed(interval) || btRuntime->isHalt()) {
     checkPoint.reset();
-    e->torrentMan->save();
-    if(e->torrentMan->isHalt()) {
+    btProgressInfoFile->save();
+    if(btRuntime->isHalt()) {
       return true;
     }
   }

+ 8 - 3
src/TorrentAutoSaveCommand.h

@@ -35,17 +35,22 @@
 #ifndef _D_TORRENT_AUTO_SAVE_COMMAND_H_
 #define _D_TORRENT_AUTO_SAVE_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 #include "TimeA2.h"
+#include "BtContext.h"
 
-class TorrentAutoSaveCommand : public Command {
+class TorrentAutoSaveCommand : public BtContextAwareCommand {
 private:
   TorrentDownloadEngine* e;
   int interval;
   Time checkPoint;
 public:
-  TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval);
+  TorrentAutoSaveCommand(int cuid,
+			 TorrentDownloadEngine* e,
+			 const BtContextHandle& btContext,
+			 int interval);
+
   ~TorrentAutoSaveCommand();
 
   bool execute();

+ 14 - 4
src/TorrentConsoleDownloadEngine.cc

@@ -34,6 +34,9 @@
 /* copyright --> */
 #include "TorrentConsoleDownloadEngine.h"
 #include "Util.h"
+#include <signal.h>
+
+volatile sig_atomic_t haltRequested = 0;
 
 TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {}
 
@@ -42,8 +45,8 @@ TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {}
 void TorrentConsoleDownloadEngine::sendStatistics() {
   printf("\r                                                                             ");
   printf("\r");
-  if(torrentMan->downloadComplete()) {
-    printf("Download Completed ");
+  if(pieceStorage->downloadFinished()) {
+    printf("Download Completed.");
   } else {
     printf("%s/%sB %d%% %s D:%.2f",
 	   Util::llitos(downloadLength, true).c_str(),
@@ -55,7 +58,14 @@ void TorrentConsoleDownloadEngine::sendStatistics() {
   }
   printf(" U:%.2f(%s) %d peers",
 	 uploadSpeed/1024.0,
-	 Util::llitos(torrentMan->getUploadLength(), true).c_str(),
-	 torrentMan->connections);
+	 Util::llitos(uploadLength, true).c_str(),
+	 btRuntime->getConnections());
   fflush(stdout);	 
 }
+
+void TorrentConsoleDownloadEngine::afterEachIteration() {
+  if(haltRequested) {
+    btRuntime->setHalt(true);
+  }
+  TorrentDownloadEngine::afterEachIteration();
+}

+ 2 - 0
src/TorrentConsoleDownloadEngine.h

@@ -43,6 +43,8 @@ protected:
 public:
   TorrentConsoleDownloadEngine();
   ~TorrentConsoleDownloadEngine();
+
+  virtual void afterEachIteration();
 };
 
 #endif // _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_

+ 40 - 31
src/TorrentDownloadEngine.cc

@@ -34,22 +34,35 @@
 /* copyright --> */
 #include "TorrentDownloadEngine.h"
 #include "Util.h"
+#include "BtRegistry.h"
 
-TorrentDownloadEngine::TorrentDownloadEngine():filenameFixed(false),
-					       torrentMan(NULL) {}
+TorrentDownloadEngine::TorrentDownloadEngine():
+  filenameFixed(false),
+  btContext(0),
+  btRuntime(0),
+  pieceStorage(0),
+  peerStorage(0),
+  btAnnounce(0),
+  btProgressInfoFile(0) {}
 
 TorrentDownloadEngine::~TorrentDownloadEngine() {
-  if(torrentMan != NULL) {
-    delete torrentMan;
-  }
+}
+
+void TorrentDownloadEngine::setBtContext(const BtContextHandle& btContext) {
+  this->btContext = btContext;
+  btRuntime = BT_RUNTIME(btContext);
+  pieceStorage = PIECE_STORAGE(btContext);
+  peerStorage = PEER_STORAGE(btContext);
+  btAnnounce = BT_ANNOUNCE(btContext);
+  btProgressInfoFile = BT_PROGRESS_INFO_FILE(btContext);
 }
 
 void TorrentDownloadEngine::onEndOfRun() {
-  torrentMan->diskAdaptor->closeFile();
-  if(torrentMan->downloadComplete()) {
-    torrentMan->remove();
+  pieceStorage->getDiskAdaptor()->closeFile();
+  if(pieceStorage->downloadFinished()) {
+    btProgressInfoFile->removeFile();
   } else {
-    torrentMan->save();
+    btProgressInfoFile->save();
   }
 }
 
@@ -57,16 +70,12 @@ void TorrentDownloadEngine::initStatistics() {
   downloadSpeed = 0;
   uploadSpeed = 0;
   cp.reset();
-  lastCalcStat.reset();
   startup.reset();
   eta = 0;
   avgSpeed = 0;
   downloadLength = 0;
+  uploadLength = 0;
   totalLength = 0;
-  if(torrentMan->isSelectiveDownloadingMode()) {
-    selectedDownloadLengthDiff = torrentMan->getDownloadLength()-torrentMan->getCompletedLength();
-    selectedTotalLength = torrentMan->getSelectedTotalLength();
-  }
 }
 
 int TorrentDownloadEngine::calculateSpeed(long long int length, int elapsed) {
@@ -75,10 +84,22 @@ int TorrentDownloadEngine::calculateSpeed(long long int length, int elapsed) {
 }
 
 void TorrentDownloadEngine::calculateStat() {
-  TransferStat stat = torrentMan->calculateStat();
-  downloadSpeed = stat.downloadSpeed;
-  uploadSpeed = stat.uploadSpeed;
-  avgSpeed = calculateSpeed(stat.sessionDownloadLength, startup.difference());
+  TransferStat stat = peerStorage->calculateStat();
+
+  if(pieceStorage->isSelectiveDownloadingMode()) {
+    downloadLength = pieceStorage->getFilteredCompletedLength();
+    totalLength = pieceStorage->getFilteredTotalLength();
+  } else {
+    downloadLength = pieceStorage->getCompletedLength();
+    totalLength = pieceStorage->getTotalLength();
+  }
+  uploadLength = stat.getSessionUploadLength()+
+    btRuntime->getUploadLengthAtStartup();
+
+  downloadSpeed = stat.getDownloadSpeed();
+  uploadSpeed = stat.getUploadSpeed();
+  avgSpeed = calculateSpeed(stat.getSessionDownloadLength(),
+			    startup.difference());
   if(avgSpeed < 0) {
     avgSpeed = 0;
   } else if(avgSpeed != 0) {
@@ -87,20 +108,8 @@ void TorrentDownloadEngine::calculateStat() {
 }
 
 void TorrentDownloadEngine::calculateStatistics() {
-  if(torrentMan->isSelectiveDownloadingMode()) {
-    downloadLength = torrentMan->getDownloadLength()-selectedDownloadLengthDiff;
-    totalLength = selectedTotalLength;
-  } else {
-    downloadLength = torrentMan->getDownloadLength();
-    totalLength = torrentMan->getTotalLength();
-  }
-  
-  Time now;
-  if(now.getTimeInMillis()-lastCalcStat.getTimeInMillis() >= 1000) {
-    calculateStat();
-    lastCalcStat = now;
-  }
   if(cp.difference() >= 1) {
+    calculateStat();
     sendStatistics();
     cp.reset();
   }

+ 16 - 3
src/TorrentDownloadEngine.h

@@ -36,8 +36,13 @@
 #define _D_TORRENT_DOWNLOAD_ENGINE_H_
 
 #include "DownloadEngine.h"
-#include "TorrentMan.h"
 #include "TimeA2.h"
+#include "BtContext.h"
+#include "BtRuntime.h"
+#include "PieceStorage.h"
+#include "PeerStorage.h"
+#include "BtAnnounce.h"
+#include "BtProgressInfoFile.h"
 
 class TorrentDownloadEngine : public DownloadEngine {
 private:
@@ -59,8 +64,16 @@ protected:
   // The estimated remaining time to complete the download.
   int eta;
   long long int downloadLength;
+  long long int uploadLength;
   long long int totalLength;
 
+  BtContextHandle btContext;
+  BtRuntimeHandle btRuntime;
+  PieceStorageHandle pieceStorage;
+  PeerStorageHandle peerStorage;
+  BtAnnounceHandle btAnnounce;
+  BtProgressInfoFileHandle btProgressInfoFile;
+
   int calculateSpeed(long long int sessionLength, int elapsed);
   void calculateStat();
 
@@ -70,9 +83,9 @@ public:
   TorrentDownloadEngine();
   virtual ~TorrentDownloadEngine();
 
-  TorrentMan* torrentMan;
-
   bool isFilenameFixed() const { return filenameFixed; }
+
+  void setBtContext(const BtContextHandle& btContext);
 };
 
 #endif // _D_TORRENT_DOWNLOAD_ENGINE_H_

+ 22 - 20
src/TorrentRequestInfo.cc

@@ -36,19 +36,24 @@
 #include "DownloadEngineFactory.h"
 #include "prefs.h"
 #include "Util.h"
+#include "BtRegistry.h"
+#include "DefaultBtContext.h"
 
 extern RequestInfo* requestInfo;
 extern void setSignalHander(int signal, void (*handler)(int), int flags);
 extern bool timeoutSpecified;
+extern volatile sig_atomic_t haltRequested;
 
 void torrentHandler(int signal) {
-  ((TorrentDownloadEngine*)requestInfo->getDownloadEngine())->
-    torrentMan->setHalt(true);
+  haltRequested = 1;
 }
 
 RequestInfo* TorrentRequestInfo::execute() {
+  BtContextHandle btContext(new DefaultBtContext());
+  btContext->load(torrentFile);
+  
   if(op->get(PREF_SHOW_FILES) == V_TRUE) {
-    showFileEntry();
+    showFileEntry(btContext);
     return 0;
   }
   if(!timeoutSpecified) {
@@ -56,45 +61,42 @@ RequestInfo* TorrentRequestInfo::execute() {
   }
   // set max_tries to 1. AnnounceList handles retries.
   op->put(PREF_MAX_TRIES, "1");
-  e = DownloadEngineFactory::newTorrentConsoleEngine(op,
-						     torrentFile,
-						     targetFiles);
+  SharedHandle<TorrentDownloadEngine>
+    e(DownloadEngineFactory::newTorrentConsoleEngine(btContext,
+						     op,
+						     targetFiles));
+
   setSignalHander(SIGINT, torrentHandler, SA_RESETHAND);
   setSignalHander(SIGTERM, torrentHandler, SA_RESETHAND);
     
   try {
     e->run();
-    if(e->torrentMan->downloadComplete()) {
+    if(PIECE_STORAGE(btContext)->downloadFinished()) {
       printDownloadCompeleteMessage();
     }
-  } catch(Exception* e) {
-    logger->error("Exception caught", e);
-    delete e;
+  } catch(Exception* ex) {
+    logger->error("Exception caught", ex);
     fail = true;
+    delete ex;
   }
   setSignalHander(SIGINT, SIG_DFL, 0);
   setSignalHander(SIGTERM, SIG_DFL, 0);
-  delete e;
   
   return 0;
 }
 
-// TODO should be const TorrentMan* torrentMan
-void TorrentRequestInfo::showFileEntry()
+void TorrentRequestInfo::showFileEntry(const BtContextHandle& btContext)
 {
-  TorrentMan torrentMan;
-  torrentMan.option = op;
-
-  FileEntries fileEntries =
-    torrentMan.readFileEntryFromMetaInfoFile(torrentFile);
+  FileEntries fileEntries = btContext->getFileEntries();
   cout << _("Files:") << endl;
   cout << "idx|path/length" << endl;
   cout << "===+===========================================================================" << endl;
   int count = 1;
   for(FileEntries::const_iterator itr = fileEntries.begin();
       itr != fileEntries.end(); count++, itr++) {
-    printf("%3d|%s\n   |%s Bytes\n", count, itr->path.c_str(),
-	   Util::llitos(itr->length, true).c_str());
+    printf("%3d|%s\n   |%s Bytes\n", count,
+	   (*itr)->getPath().c_str(),
+	   Util::llitos((*itr)->getLength(), true).c_str());
     cout << "---+---------------------------------------------------------------------------" << endl;
   }
 }

+ 7 - 5
src/TorrentRequestInfo.h

@@ -37,19 +37,19 @@
 
 #include "RequestInfo.h"
 #include "TorrentDownloadEngine.h"
+#include "BtContext.h"
 
 class TorrentRequestInfo : public RequestInfo {
 private:
   string torrentFile;
-  TorrentDownloadEngine* e;
   Strings targetFiles;
 
-  void showFileEntry();
+  void showFileEntry(const BtContextHandle& btContext);
 public:
   TorrentRequestInfo(const string& torrentFile, Option* op):
     RequestInfo(op),
-    torrentFile(torrentFile),
-    e(0) {}
+    torrentFile(torrentFile) {}
+
   virtual ~TorrentRequestInfo() {}
 
   virtual RequestInfo* execute();
@@ -57,8 +57,10 @@ public:
   void setTargetFiles(const Strings& targetFiles) {
     this->targetFiles = targetFiles;
   }
-  virtual DownloadEngine* getDownloadEngine() { return e; }
 
+  virtual DownloadEngine* getDownloadEngine() {
+    return 0;
+  }
 };
 
 #endif // _D_TORRENT_REQUEST_INFO_H_

+ 23 - 11
src/TrackerUpdateCommand.cc

@@ -40,7 +40,13 @@
 #include "SleepCommand.h"
 #include "Util.h"
 
-TrackerUpdateCommand::TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e):Command(cuid), e(e) {
+extern PeerHandle nullPeer;
+
+TrackerUpdateCommand::TrackerUpdateCommand(int cuid,
+					   TorrentDownloadEngine* e,
+					   const BtContextHandle& btContext):
+  BtContextAwareCommand(cuid, btContext), e(e)
+{
   logger = LogFactory::getInstance();
 }
 
@@ -77,7 +83,7 @@ char* TrackerUpdateCommand::getTrackerResponse(size_t& trackerResponseLength) {
 }
 
 bool TrackerUpdateCommand::execute() {
-  if(e->segmentMan->errors > 0 && e->torrentMan->isHalt()) {
+  if(e->segmentMan->errors > 0 && btRuntime->isHalt()) {
     return true;
   }
   if(!e->segmentMan->finished()) {
@@ -89,19 +95,25 @@ bool TrackerUpdateCommand::execute() {
   try {
     trackerResponse = getTrackerResponse(trackerResponseLength);
 
-    e->torrentMan->processAnnounceResponse(trackerResponse,
-					   trackerResponseLength);
-    while(e->torrentMan->needMorePeerConnection()) {
-      PeerHandle peer = e->torrentMan->getPeer();
-      int newCuid =  e->torrentMan->getNewCuid();
+    btAnnounce->processAnnounceResponse(trackerResponse,
+					trackerResponseLength);
+    while(!btRuntime->isHalt() && btRuntime->lessThanMinPeer()) {
+      PeerHandle peer = peerStorage->getUnusedPeer();
+      if(peer == nullPeer) {
+	break;
+      }
+      int newCuid =  btRuntime->getNewCuid();
       peer->cuid = newCuid;
       PeerInitiateConnectionCommand* command =
-	new PeerInitiateConnectionCommand(newCuid, peer, e);
+	new PeerInitiateConnectionCommand(newCuid,
+					  peer,
+					  e,
+					  btContext);
       e->commands.push_back(command);
       logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid);
     }
-    e->torrentMan->announceSuccess();
-    e->torrentMan->resetAnnounce();
+    btAnnounce->announceSuccess();
+    btAnnounce->resetAnnounce();
     e->segmentMan->init();
   } catch(Exception* err) {
     logger->error("CUID#%d - Error occurred while processing tracker response.", cuid, err);
@@ -111,7 +123,7 @@ bool TrackerUpdateCommand::execute() {
   if(trackerResponse) {
     delete [] trackerResponse;
   }
-  if(e->torrentMan->isHalt()) {
+  if(btRuntime->isHalt()) {
     return true;
   } else {
     return prepareForRetry();

+ 6 - 3
src/TrackerUpdateCommand.h

@@ -35,18 +35,21 @@
 #ifndef _D_TRACKER_UPDATE_COMMAND_H_
 #define _D_TRACKER_UPDATE_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 #include "Logger.h"
 
-class TrackerUpdateCommand : public Command {
+class TrackerUpdateCommand : public BtContextAwareCommand {
 private:
   TorrentDownloadEngine* e;
   const Logger* logger;
   bool prepareForRetry();
   char* getTrackerResponse(size_t& trackerResponseLength);
 public:
-  TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e);
+  TrackerUpdateCommand(int cuid,
+		       TorrentDownloadEngine* e,
+		       const BtContextHandle& btContext);
+
   virtual ~TrackerUpdateCommand();
 
   bool execute();

+ 16 - 13
src/TrackerWatcherCommand.cc

@@ -39,17 +39,19 @@
 #include "prefs.h"
 
 TrackerWatcherCommand::TrackerWatcherCommand(int cuid,
-					     TorrentDownloadEngine* e):
-  Command(cuid), e(e) {
+					     TorrentDownloadEngine* e,
+					     const BtContextHandle& btContext):
+  BtContextAwareCommand(cuid, btContext), e(e)
+{
 }
 
 TrackerWatcherCommand::~TrackerWatcherCommand() {}
 
 
 bool TrackerWatcherCommand::execute() {
-  if(e->torrentMan->isHalt() &&
-     e->segmentMan->errors > 0 && e->torrentMan->isAllAnnounceFailed() ||
-     e->torrentMan->noMoreAnnounce()) {
+  if(btRuntime->isHalt() &&
+     e->segmentMan->errors > 0 && btAnnounce->isAllAnnounceFailed() ||
+     btAnnounce->noMoreAnnounce()) {
     return true;
   }
   Command* command = createCommand();
@@ -62,18 +64,18 @@ bool TrackerWatcherCommand::execute() {
 
 Command* TrackerWatcherCommand::createCommand() {
   Command* command = 0;
-  if(e->torrentMan->isAnnounceReady()) {
-    command = createRequestCommand(e->torrentMan->getAnnounceUrl());
-    e->torrentMan->announceStart(); // inside it, trackers++.
+  if(btAnnounce->isAnnounceReady()) {
+    command = createRequestCommand(btAnnounce->getAnnounceUrl());
+    btAnnounce->announceStart(); // inside it, trackers++.
   } else if(e->segmentMan->errors > 0) {
-    e->torrentMan->announceFailure(); // inside it, trackers = 0.
+    btAnnounce->announceFailure(); // inside it, trackers = 0.
     e->segmentMan->init();
-    if(e->torrentMan->isAllAnnounceFailed()) {
-      e->torrentMan->resetAnnounce();
+    if(btAnnounce->isAllAnnounceFailed()) {
+      btAnnounce->resetAnnounce();
       // sleep a few seconds.
       command =
 	new SleepCommand(cuid, e,
-			 createRequestCommand(e->torrentMan->getAnnounceUrl()),
+			 createRequestCommand(btAnnounce->getAnnounceUrl()),
 			 e->option->getAsInt(PREF_RETRY_WAIT));
     }
   }
@@ -84,7 +86,8 @@ Command* TrackerWatcherCommand::createRequestCommand(const string& url) {
   RequestHandle req;
   req->setUrl(url);
   req->isTorrent = true;
-  Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(e->torrentMan->getNewCuid(), req, e);
+  Command* command =
+    InitiateConnectionCommandFactory::createInitiateConnectionCommand(btRuntime->getNewCuid(), req, e);
   logger->info("CUID#%d - Creating new tracker request command #%d", cuid,
 	       command->getCuid());
   return command;

+ 6 - 3
src/TrackerWatcherCommand.h

@@ -35,10 +35,10 @@
 #ifndef _D_TRACKER_WATCHER_COMMAND_H_
 #define _D_TRACKER_WATCHER_COMMAND_H_
 
-#include "Command.h"
+#include "BtContextAwareCommand.h"
 #include "TorrentDownloadEngine.h"
 
-class TrackerWatcherCommand : public Command {
+class TrackerWatcherCommand : public BtContextAwareCommand {
 private:
   TorrentDownloadEngine* e;
 
@@ -48,7 +48,10 @@ private:
    */
   Command* createRequestCommand(const string& url);
 public:
-  TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e);
+  TrackerWatcherCommand(int cuid,
+			TorrentDownloadEngine* e,
+			const BtContextHandle& btContext);
+
   ~TrackerWatcherCommand();
 
   Command* createCommand();

+ 12 - 4
src/Util.cc

@@ -117,20 +117,28 @@ int Util::difftvsec(struct timeval tv1, struct timeval tv2) {
   return tv1.tv_sec-tv2.tv_sec;
 }
 
-void Util::slice(Strings& result, const string& src, char delim) {
+void Util::slice(Strings& result, const string& src, char delim, bool doTrim) {
   string::size_type p = 0;
   while(1) {
     string::size_type np = src.find(delim, p);
     if(np == string::npos) {
-      string term = trim(src.substr(p));
-      if(term.size() > 0) {
+      string term = src.substr(p);
+      if(doTrim) {
+	term = trim(term);
+      }
+      if(term.size()) {
 	result.push_back(term);
       }
       break;
     }
     string term = src.substr(p, np-p);
+    if(doTrim) {
+      term = trim(term);
+    }
     p = np+1;
-    result.push_back(trim(term));
+    if(term.size()) {
+      result.push_back(term);
+    }
   } 
 }
 

+ 1 - 1
src/Util.h

@@ -65,7 +65,7 @@ public:
    * Take a string src which is a deliminated list and add its elements
    * into result. result is not cleared before conversion begins.
    */
-  static void slice(Strings& result, const string& src, char delim);
+  static void slice(Strings& result, const string& src, char delim, bool trim = false);
   
   static string trim(const string& src);
 

+ 2 - 0
src/common.h

@@ -71,6 +71,8 @@ public:
   }
 };
 
+#include "SharedHandle.h"
+
 typedef deque<string> Strings;
 typedef deque<int> Integers;
 

+ 1 - 1
src/main.cc

@@ -105,7 +105,7 @@ void showVersion() {
       "along with this program; if not, write to the Free Software\n"
       "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n");
   cout << endl;
-  printf(_("Contact Info: %s\n"), "Tasuhiro Tsujikawa <tujikawa at users dot sourceforge dot net>");
+  printf(_("Contact Info: %s\n"), "Tatsuhiro Tsujikawa <tujikawa at users dot sourceforge dot net>");
   cout << endl;
 
 }

+ 8 - 8
test/AnnounceListTest.cc

@@ -227,10 +227,10 @@ Strings createUrls(const string& url) {
 }
 
 void AnnounceListTest::testMoveToStoppedAllowedTier() {
-  AnnounceTier t1(createUrls("tracker1"));
-  AnnounceTier t2(createUrls("tracker2"));
-  t2.event = AnnounceTier::COMPLETED;
-  AnnounceTier t3(createUrls("tracker3"));
+  AnnounceTierHandle t1(new AnnounceTier(createUrls("tracker1")));
+  AnnounceTierHandle t2(new AnnounceTier(createUrls("tracker2")));
+  t2->event = AnnounceTier::COMPLETED;
+  AnnounceTierHandle t3(new AnnounceTier(createUrls("tracker3")));
 
   AnnounceTiers tiers;
   tiers.push_back(t1);
@@ -250,10 +250,10 @@ void AnnounceListTest::testMoveToStoppedAllowedTier() {
 }
 
 void AnnounceListTest::testMoveToCompletedAllowedTier() {
-  AnnounceTier t1(createUrls("tracker1"));
-  AnnounceTier t2(createUrls("tracker2"));
-  t2.event = AnnounceTier::COMPLETED;
-  AnnounceTier t3(createUrls("tracker3"));
+  AnnounceTierHandle t1(new AnnounceTier(createUrls("tracker1")));
+  AnnounceTierHandle t2(new AnnounceTier(createUrls("tracker2")));
+  t2->event = AnnounceTier::COMPLETED;
+  AnnounceTierHandle t3(new AnnounceTier(createUrls("tracker3")));
 
   AnnounceTiers tiers;
   tiers.push_back(t1);

+ 7 - 6
test/BitfieldManTest.cc

@@ -95,21 +95,21 @@ void BitfieldManTest::testFilter() {
   int index;
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
+  CPPUNIT_ASSERT_EQUAL(2, index);
+  index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
+  btman.setUseBit(index);
   CPPUNIT_ASSERT_EQUAL(3, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
   CPPUNIT_ASSERT_EQUAL(4, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
-  CPPUNIT_ASSERT_EQUAL(2, index);
+  CPPUNIT_ASSERT_EQUAL(5, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
   CPPUNIT_ASSERT_EQUAL(6, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
-  CPPUNIT_ASSERT_EQUAL(5, index);
-  index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
-  btman.setUseBit(index);
   CPPUNIT_ASSERT_EQUAL(7, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
@@ -118,17 +118,18 @@ void BitfieldManTest::testFilter() {
 
   // test offset=5, length=2
   btman.clearAllBit();
+  btman.clearAllUseBit();
   btman.clearFilter();
   btman.addFilter(5, 2);
   btman.enableFilter();
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
   btman.setBit(index);
-  CPPUNIT_ASSERT_EQUAL(3, index);
+  CPPUNIT_ASSERT_EQUAL(2, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
   btman.setBit(index);
-  CPPUNIT_ASSERT_EQUAL(2, index);
+  CPPUNIT_ASSERT_EQUAL(3, index);
   index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt));
   btman.setUseBit(index);
   CPPUNIT_ASSERT_EQUAL(-1, index);

+ 88 - 0
test/BtRegistryTest.cc

@@ -0,0 +1,88 @@
+#include "BtRegistry.h"
+#include "Exception.h"
+#include "MockPeerStorage.h"
+#include "MockPieceStorage.h"
+#include "MockBtAnnounce.h"
+#include "MockBtProgressInfoFile.h"
+#include <string>
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class BtRegistryTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(BtRegistryTest);
+  CPPUNIT_TEST(testGetPeerStorage);
+  CPPUNIT_TEST(testGetPieceStorage);
+  CPPUNIT_TEST(testGetBtRuntime);
+  CPPUNIT_TEST(testGetBtAnnounce);
+  CPPUNIT_TEST(testGetBtProgressInfoFile);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testGetPeerStorage();
+  void testGetPieceStorage();
+  void testGetBtRuntime();
+  void testGetBtAnnounce();
+  void testGetBtProgressInfoFile();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( BtRegistryTest );
+
+void BtRegistryTest::testGetPeerStorage() {
+  CPPUNIT_ASSERT(!BtRegistry::getPeerStorage("test").get());
+
+  PeerStorageHandle peerStorage(new MockPeerStorage());
+
+  CPPUNIT_ASSERT(BtRegistry::registerPeerStorage("test",
+						 peerStorage));
+  CPPUNIT_ASSERT_EQUAL(peerStorage.get(),
+		       BtRegistry::getPeerStorage("test").get());
+}
+
+void BtRegistryTest::testGetPieceStorage() {
+  CPPUNIT_ASSERT(!BtRegistry::getPieceStorage("test").get());
+
+  PieceStorageHandle pieceStorage(new MockPieceStorage());
+
+  CPPUNIT_ASSERT(BtRegistry::registerPieceStorage("test",
+						  pieceStorage));
+  CPPUNIT_ASSERT_EQUAL(pieceStorage.get(),
+		       BtRegistry::getPieceStorage("test").get());
+}
+
+void BtRegistryTest::testGetBtRuntime() {
+  CPPUNIT_ASSERT(!BtRegistry::getBtRuntime("test").get());
+
+  BtRuntimeHandle runtime;
+
+  CPPUNIT_ASSERT(BtRegistry::registerBtRuntime("test", runtime));
+  CPPUNIT_ASSERT_EQUAL(runtime.get(),
+		       BtRegistry::getBtRuntime("test").get());
+}
+
+void BtRegistryTest::testGetBtAnnounce() {
+  CPPUNIT_ASSERT(!BtRegistry::getBtAnnounce("test").get());
+  
+  BtAnnounceHandle btAnnounce(new MockBtAnnounce());
+
+  CPPUNIT_ASSERT(BtRegistry::registerBtAnnounce("test", btAnnounce));
+  CPPUNIT_ASSERT_EQUAL(btAnnounce.get(),
+		       BtRegistry::getBtAnnounce("test").get());
+}
+
+void BtRegistryTest::testGetBtProgressInfoFile() {
+  CPPUNIT_ASSERT(!BtRegistry::getBtProgressInfoFile("test").get());
+
+  BtProgressInfoFileHandle btProgressInfoFile(new MockBtProgressInfoFile());
+
+  CPPUNIT_ASSERT(BtRegistry::registerBtProgressInfoFile("test",
+  							btProgressInfoFile));
+  CPPUNIT_ASSERT_EQUAL(btProgressInfoFile.get(),
+  		       BtRegistry::getBtProgressInfoFile("test").get());
+}

部分文件因为文件数量过多而无法显示