Browse Source

2007-10-12 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Implemented BitTorrent/http/ftp integrated download.
	I've rewritten lots of files and now some headers have forward
	class declarations to reduce compile time.
	The implementation is extremely alpha stage, I recommend to use this
	for testing purpose only.
Tatsuhiro Tsujikawa 18 years ago
parent
commit
048a2cf597
100 changed files with 2546 additions and 1394 deletions
  1. 8 0
      ChangeLog
  2. 6 1
      TODO
  3. 10 10
      configure
  4. 1 1
      configure.ac
  5. 1 1
      po/Makefile.in
  6. 1 0
      po/POTFILES
  7. 1 0
      po/POTFILES.in
  8. 176 24
      src/AbstractCommand.cc
  9. 25 7
      src/AbstractCommand.h
  10. 33 20
      src/AbstractDiskWriter.cc
  11. 11 23
      src/AbstractDiskWriter.h
  12. 3 0
      src/AbstractProxyRequestCommand.cc
  13. 3 1
      src/AbstractProxyRequestCommand.h
  14. 5 0
      src/AbstractProxyResponseCommand.cc
  15. 3 1
      src/AbstractProxyResponseCommand.h
  16. 23 6
      src/AbstractSingleDiskAdaptor.cc
  17. 16 8
      src/AbstractSingleDiskAdaptor.h
  18. 17 1
      src/ActivePeerConnectionCommand.cc
  19. 12 12
      src/ActivePeerConnectionCommand.h
  20. 2 2
      src/AlphaNumberDecorator.h
  21. 8 1
      src/AutoSaveCommand.cc
  22. 2 3
      src/AutoSaveCommand.h
  23. 52 0
      src/BinaryStream.h
  24. 22 30
      src/BtCheckIntegrityEntry.cc
  25. 51 0
      src/BtCheckIntegrityEntry.h
  26. 8 25
      src/BtContext.h
  27. 1 3
      src/BtContextAwareCommand.cc
  28. 4 3
      src/BtContextAwareCommand.h
  29. 83 0
      src/BtDependency.cc
  30. 22 19
      src/BtDependency.h
  31. 15 20
      src/BtFileAllocationEntry.cc
  32. 56 0
      src/BtFileAllocationEntry.h
  33. 2 2
      src/BtPieceMessage.cc
  34. 24 21
      src/BtPostDownloadHandler.cc
  35. 51 0
      src/BtPostDownloadHandler.h
  36. 0 2
      src/BtProgressInfoFile.h
  37. 62 65
      src/BtRegistry.cc
  38. 20 11
      src/BtRegistry.h
  39. 8 2
      src/BtRuntime.h
  40. 97 0
      src/BtSetup.cc
  41. 14 12
      src/BtSetup.h
  42. 17 15
      src/ByteArrayDiskWriter.cc
  43. 2 3
      src/ByteArrayDiskWriter.h
  44. 52 0
      src/ByteArrayDiskWriterFactory.h
  45. 9 21
      src/CheckIntegrityCommand.cc
  46. 4 3
      src/CheckIntegrityCommand.h
  47. 43 12
      src/CheckIntegrityEntry.cc
  48. 20 12
      src/CheckIntegrityEntry.h
  49. 72 0
      src/CheckIntegrityMan.cc
  50. 12 29
      src/CheckIntegrityMan.h
  51. 8 4
      src/ChecksumCommand.cc
  52. 2 2
      src/ChecksumCommand.h
  53. 5 0
      src/ChunkChecksum.h
  54. 2 0
      src/ChunkChecksumValidator.cc
  55. 0 210
      src/ConsoleDownloadEngine.cc
  56. 162 0
      src/ConsoleStatCalc.cc
  57. 14 10
      src/ConsoleStatCalc.h
  58. 8 3
      src/CopyDiskAdaptor.cc
  59. 3 2
      src/CopyDiskAdaptor.h
  60. 7 1
      src/DefaultBtContext.cc
  61. 19 1
      src/DefaultBtContext.h
  62. 198 93
      src/DefaultBtProgressInfoFile.cc
  63. 19 35
      src/DefaultBtProgressInfoFile.h
  64. 1 35
      src/DefaultDiskWriter.cc
  65. 2 3
      src/DefaultDiskWriter.h
  66. 52 0
      src/DefaultDiskWriterFactory.h
  67. 2 0
      src/DefaultPeerStorage.cc
  68. 157 83
      src/DefaultPieceStorage.cc
  69. 30 11
      src/DefaultPieceStorage.h
  70. 6 5
      src/DefaultSegmentManFactory.cc
  71. 2 1
      src/DefaultSegmentManFactory.h
  72. 14 2
      src/Dependency.h
  73. 5 2
      src/DirectDiskAdaptor.cc
  74. 2 1
      src/DirectDiskAdaptor.h
  75. 11 6
      src/DiskAdaptor.cc
  76. 11 7
      src/DiskAdaptor.h
  77. 5 25
      src/DiskWriter.h
  78. 9 10
      src/DiskWriterFactory.h
  79. 45 16
      src/DownloadCommand.cc
  80. 5 8
      src/DownloadCommand.h
  81. 99 0
      src/DownloadContext.h
  82. 75 2
      src/DownloadEngine.cc
  83. 48 35
      src/DownloadEngine.h
  84. 34 169
      src/DownloadEngineFactory.cc
  85. 13 18
      src/DownloadEngineFactory.h
  86. 23 0
      src/File.cc
  87. 2 0
      src/File.h
  88. 27 24
      src/FileAllocationCommand.cc
  89. 7 4
      src/FileAllocationCommand.h
  90. 18 5
      src/FileAllocationDispatcherCommand.cc
  91. 5 6
      src/FileAllocationDispatcherCommand.h
  92. 26 13
      src/FileAllocationEntry.cc
  93. 16 19
      src/FileAllocationEntry.h
  94. 56 0
      src/FileAllocationIterator.h
  95. 39 29
      src/FileAllocationMan.cc
  96. 14 38
      src/FileAllocationMan.h
  97. 14 1
      src/FileEntry.cc
  98. 2 12
      src/FileEntry.h
  99. 24 2
      src/FillRequestGroupCommand.cc
  100. 8 9
      src/FillRequestGroupCommand.h

+ 8 - 0
ChangeLog

@@ -1,3 +1,11 @@
+2007-10-12  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Implemented BitTorrent/http/ftp integrated download.
+	I've rewritten lots of files and now some headers have forward
+	class declarations to reduce compile time.
+	The implementation is extremely alpha stage, I recommend to use this
+	for testing purpose only.
+
 2007-09-14  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	Fixed the compilation error on 64bit platform.

+ 6 - 1
TODO

@@ -47,4 +47,9 @@
 	src/PeerChokeCommand.h
 	src/TorrentAutoSaveCommand.h
 * Rewrite MetaFileUtil
-* Integrate FTP/HTTP/BitTorrent downloads from metalinks
+* Reconsider the use of RecoverableException and FatalException
+* Limit the number of opening file to,say,100 in MultiDiskAdaptor.
+
+* Implement duplicate download checking in Bt
+* Implement the feature to treat http/ftp as auxuality download method for BitTorrent
+* Fixed the download error when sending "CWD //*" to the ftp server

+ 10 - 10
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for aria2c 0.11.3.
+# Generated by GNU Autoconf 2.61 for aria2c 0.12.0alpha.
 #
 # Report bugs to <[email protected]>.
 #
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='aria2c'
 PACKAGE_TARNAME='aria2c'
-PACKAGE_VERSION='0.11.3'
-PACKAGE_STRING='aria2c 0.11.3'
+PACKAGE_VERSION='0.12.0alpha'
+PACKAGE_STRING='aria2c 0.12.0alpha'
 PACKAGE_BUGREPORT='[email protected]'
 
 ac_unique_file="src/Socket.h"
@@ -1298,7 +1298,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures aria2c 0.11.3 to adapt to many kinds of systems.
+\`configure' configures aria2c 0.12.0alpha to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1369,7 +1369,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of aria2c 0.11.3:";;
+     short | recursive ) echo "Configuration of aria2c 0.12.0alpha:";;
    esac
   cat <<\_ACEOF
 
@@ -1490,7 +1490,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-aria2c configure 0.11.3
+aria2c configure 0.12.0alpha
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by aria2c $as_me 0.11.3, which was
+It was created by aria2c $as_me 0.12.0alpha, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -2300,7 +2300,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='aria2c'
- VERSION='0.11.3'
+ VERSION='0.12.0alpha'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -14327,7 +14327,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by aria2c $as_me 0.11.3, which was
+This file was extended by aria2c $as_me 0.12.0alpha, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14380,7 +14380,7 @@ Report bugs to <[email protected]>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-aria2c config.status 0.11.3
+aria2c config.status 0.12.0alpha
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 

+ 1 - 1
configure.ac

@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 #
 AC_PREREQ(2.59)
-AC_INIT(aria2c, 0.11.3, [email protected])
+AC_INIT(aria2c, 0.12.0alpha, [email protected])
 AC_CANONICAL_HOST
 AC_CANONICAL_SYSTEM
 AM_INIT_AUTOMAKE()

+ 1 - 1
po/Makefile.in

@@ -9,7 +9,7 @@
 # General Public License and is *not* in the public domain.
 
 PACKAGE = aria2c
-VERSION = 0.11.3
+VERSION = 0.12.0alpha
 
 SHELL = /bin/sh
 

+ 1 - 0
po/POTFILES

@@ -4,6 +4,7 @@
      ../src/TorrentRequestInfo.cc \
      ../src/UrlRequestInfo.cc \
      ../src/main.cc \
+     ../src/version_usage.cc \
      ../src/DefaultPieceStorage.cc \
      ../src/DefaultBtAnnounce.cc \
      ../src/DefaultBtProgressInfoFile.cc \

+ 1 - 0
po/POTFILES.in

@@ -4,6 +4,7 @@ src/DownloadEngineFactory.cc
 src/TorrentRequestInfo.cc
 src/UrlRequestInfo.cc
 src/main.cc
+src/version_usage.cc
 src/DefaultPieceStorage.cc
 src/DefaultBtAnnounce.cc
 src/DefaultBtProgressInfoFile.cc

+ 176 - 24
src/AbstractCommand.cc

@@ -33,44 +33,64 @@
  */
 /* copyright --> */
 #include "AbstractCommand.h"
+#include "SegmentMan.h"
+#include "NameResolver.h"
+#include "CUIDCounter.h"
 #include "DlAbortEx.h"
 #include "DlRetryEx.h"
+#include "FatalException.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "Util.h"
 #include "message.h"
 #include "SleepCommand.h"
 #include "prefs.h"
 #include "DNSCache.h"
-#include "FatalException.h"
+#include "SingleFileDownloadContext.h"
+#include "DefaultPieceStorage.h"
+#include "UnknownLengthPieceStorage.h"
+#include "File.h"
+#include "StreamCheckIntegrityEntry.h"
+#include "DefaultBtProgressInfoFile.h"
+#include "CheckIntegrityCommand.h"
+#include "DiskAdaptor.h"
+#include "PeerStat.h"
+#include "Segment.h"
+#include "DiskWriterFactory.h"
+#include "Option.h"
 
 AbstractCommand::AbstractCommand(int32_t cuid,
 				 const RequestHandle& req,
 				 RequestGroup* requestGroup,
 				 DownloadEngine* e,
 				 const SocketHandle& s):
-  Command(cuid), req(req), _requestGroup(requestGroup), e(e), socket(s),
+  Command(cuid), RequestGroupAware(requestGroup),
+  req(req), e(e), socket(s),
+  segment(0),
   checkSocketIsReadable(false), checkSocketIsWritable(false),
-  nameResolverCheck(false) {
-  
+  nameResolverCheck(false)
+{ 
   setReadCheckSocket(socket);
   timeout = this->e->option->getAsInt(PREF_TIMEOUT);
-  ++_requestGroup->numConnection;
+  _requestGroup->increaseStreamConnection();
 }
 
 AbstractCommand::~AbstractCommand() {
   disableReadCheckSocket();
   disableWriteCheckSocket();
-  --_requestGroup->numConnection;
+  _requestGroup->decreaseStreamConnection();
 }
 
 bool AbstractCommand::execute() {
   try {
-    if(_requestGroup->getSegmentMan()->finished()) {
+    if(_requestGroup->downloadFinished() || _requestGroup->isHaltRequested()) {
       //logger->debug("CUID#%d - finished.", cuid);
       return true;
     }
-    PeerStatHandle peerStat = _requestGroup->getSegmentMan()->getPeerStat(cuid);
-    if(peerStat.get()) {
+    PeerStatHandle peerStat = 0;
+    if(!_requestGroup->getSegmentMan().isNull()) {
+      peerStat = _requestGroup->getSegmentMan()->getPeerStat(cuid);
+    }
+    if(!peerStat.isNull()) {
       if(peerStat->getStatus() == PeerStat::REQUEST_IDLE) {
 	logger->info(MSG_ABORT_REQUESTED, cuid);
 	onAbort(0);
@@ -86,9 +106,8 @@ bool AbstractCommand::execute() {
 #endif // ENABLE_ASYNC_DNS
        !checkSocketIsReadable && !checkSocketIsWritable && !nameResolverCheck) {
       checkPoint.reset();
-      if(_requestGroup->getSegmentMan()->downloadStarted) {
-	// TODO Segment::isNull(), Change method name, it is very confusing.
-	if(segment->isNull()) {
+      if(!_requestGroup->getPieceStorage().isNull()) {
+	if(segment.isNull()) {
 	  segment = _requestGroup->getSegmentMan()->getSegment(cuid);
 	  if(segment.isNull()) {
 	    logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid);
@@ -98,26 +117,17 @@ bool AbstractCommand::execute() {
       }
       return executeInternal();
     } else {
-
       if(checkPoint.elapsed(timeout)) {
 	throw new DlRetryEx(EX_TIME_OUT);
       }
       e->commands.push_back(this);
       return false;
     }
-  } catch(FatalException* err) {
-    logger->error(MSG_DOWNLOAD_ABORTED, err, cuid, req->getUrl().c_str());
-    onAbort(err);
-    delete(err);
-    req->resetUrl();
-    _requestGroup->getSegmentMan()->errors++;
-    return true;    
   } catch(DlAbortEx* err) {
     logger->error(MSG_DOWNLOAD_ABORTED, err, cuid, req->getUrl().c_str());
     onAbort(err);
     delete(err);
     req->resetUrl();
-    _requestGroup->getSegmentMan()->errors++;
     tryReserved();
     return true;
   } catch(DlRetryEx* err) {
@@ -132,13 +142,16 @@ bool AbstractCommand::execute() {
       logger->info(MSG_MAX_TRY, cuid, req->getTryCount());
       logger->error(MSG_DOWNLOAD_ABORTED, err, cuid, req->getUrl().c_str());
       delete(err);
-      _requestGroup->getSegmentMan()->errors++;
       tryReserved();
       return true;
     } else {
       delete(err);
       return prepareForRetry(e->option->getAsInt(PREF_RETRY_WAIT));
     }
+  } catch(FatalException* err) {
+    delete(err);
+    _requestGroup->setHaltRequested(true);
+    return true;
   }
 }
 
@@ -148,7 +161,9 @@ void AbstractCommand::tryReserved() {
 }
 
 bool AbstractCommand::prepareForRetry(int32_t wait) {
-  _requestGroup->getSegmentMan()->cancelSegment(cuid);
+  if(!_requestGroup->getPieceStorage().isNull()) {
+    _requestGroup->getSegmentMan()->cancelSegment(cuid);
+  }
   Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, _requestGroup, e);
   if(wait == 0) {
     e->commands.push_back(command);
@@ -162,7 +177,9 @@ bool AbstractCommand::prepareForRetry(int32_t wait) {
 void AbstractCommand::onAbort(Exception* ex) {
   logger->debug(MSG_UNREGISTER_CUID, cuid);
   //_segmentMan->unregisterId(cuid);
-  _requestGroup->getSegmentMan()->cancelSegment(cuid);
+  if(!_requestGroup->getPieceStorage().isNull()) {
+    _requestGroup->getSegmentMan()->cancelSegment(cuid);
+  }
 }
 
 void AbstractCommand::disableReadCheckSocket() {
@@ -272,3 +289,138 @@ bool AbstractCommand::nameResolveFinished() const {
   return false;
 }
 #endif // ENABLE_ASYNC_DNS
+
+void AbstractCommand::loadAndOpenFile()
+{
+  if(!_requestGroup->isPreLocalFileCheckEnabled()) {
+    _requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
+    return;
+  }
+
+  //_requestGroup->setProgressInfoFile(new DefaultBtProgressInfoFile(_requestGroup->getDownloadContext(), _requestGroup->getPieceStorage(), e->option));
+  BtProgressInfoFileHandle progressInfoFile =
+    new DefaultBtProgressInfoFile(_requestGroup->getDownloadContext(), _requestGroup->getPieceStorage(), e->option);
+  if(progressInfoFile->exists()) {
+    progressInfoFile->load();
+    _requestGroup->getPieceStorage()->getDiskAdaptor()->openExistingFile();
+  } else {
+    File outfile(_requestGroup->getFilePath());    
+    if(outfile.exists() && e->option->get(PREF_CONTINUE) == V_TRUE) {
+      if(_requestGroup->getTotalLength() < outfile.size()) {
+	throw new FatalException(EX_FILE_LENGTH_MISMATCH_BETWEEN_LOCAL_AND_REMOTE,
+				 _requestGroup->getFilePath().c_str(),
+				 Util::llitos(outfile.size()).c_str(),
+				 Util::llitos(_requestGroup->getTotalLength()).c_str());
+      }
+      _requestGroup->getPieceStorage()->getDiskAdaptor()->openExistingFile();
+      _requestGroup->getPieceStorage()->markPiecesDone(outfile.size());
+    } else {
+#ifdef ENABLE_MESSAGE_DIGEST
+      if(outfile.exists() && e->option->get(PREF_CHECK_INTEGRITY) == V_TRUE) {
+	_requestGroup->getPieceStorage()->getDiskAdaptor()->openExistingFile();
+      } else {
+	shouldCancelDownloadForSafety();
+	_requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
+      }
+#else // ENABLE_MESSAGE_DIGEST
+      shouldCancelDownloadForSafety();
+      _requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
+#endif // ENABLE_MESSAGE_DIGEST
+    }
+  }
+  _requestGroup->setProgressInfoFile(progressInfoFile);
+}
+
+void AbstractCommand::shouldCancelDownloadForSafety()
+{
+  File outfile(_requestGroup->getFilePath());
+  if(outfile.exists() && !_requestGroup->getProgressInfoFile()->exists()) {
+    if(e->option->get(PREF_AUTO_FILE_RENAMING) == V_TRUE) {
+      if(tryAutoFileRenaming()) {
+	logger->notice("File already exists. Renamed to %s.",
+		       _requestGroup->getFilePath().c_str());
+      } else {
+	logger->notice("File renaming failed: %s",
+		       _requestGroup->getFilePath().c_str());
+	throw new FatalException(EX_DOWNLOAD_ABORTED);
+      }
+    } else if(e->option->get(PREF_ALLOW_OVERWRITE) != V_TRUE) {
+      logger->notice(MSG_FILE_ALREADY_EXISTS,
+		     _requestGroup->getFilePath().c_str(),
+		     _requestGroup->getProgressInfoFile()->getFilename().c_str());
+      throw new FatalException(EX_DOWNLOAD_ABORTED);
+    }
+  }
+}
+
+bool AbstractCommand::tryAutoFileRenaming()
+{
+  string filepath = _requestGroup->getFilePath();
+  if(filepath.empty()) {
+    return false;
+  }
+  for(int32_t i = 1; i < 10000; ++i) {
+    File newfile(filepath+"."+Util::itos(i));
+    if(!newfile.exists()) {
+      SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setUFilename(newfile.getBasename());
+      return true;
+    }
+  }
+  return false;
+}
+
+void AbstractCommand::initPieceStorage()
+{
+  if(_requestGroup->getDownloadContext()->getTotalLength() == 0) {
+    UnknownLengthPieceStorageHandle ps = new UnknownLengthPieceStorage(_requestGroup->getDownloadContext(), e->option);
+    if(!_requestGroup->getDiskWriterFactory().isNull()) {
+      ps->setDiskWriterFactory(_requestGroup->getDiskWriterFactory());
+    }
+    _requestGroup->setPieceStorage(ps);
+  } else {
+    DefaultPieceStorageHandle ps = new DefaultPieceStorage(_requestGroup->getDownloadContext(), e->option);
+    if(!_requestGroup->getDiskWriterFactory().isNull()) {
+      ps->setDiskWriterFactory(_requestGroup->getDiskWriterFactory());
+    }
+    _requestGroup->setPieceStorage(ps);
+  }
+  _requestGroup->getPieceStorage()->initStorage();
+  _requestGroup->initSegmentMan();
+}
+
+bool AbstractCommand::downloadFinishedByFileLength()
+{
+  // check existence of control file using ProgressInfoFile class.
+  if(_requestGroup->getProgressInfoFile()->exists()) {
+    return false;
+  }
+  // TODO consider the case when the getFilePath() returns dir path. 
+  File outfile(_requestGroup->getFilePath());
+  if(outfile.exists() &&
+     _requestGroup->getTotalLength() == outfile.size()) {
+    _requestGroup->getPieceStorage()->markAllPiecesDone();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void AbstractCommand::prepareForNextAction(Command* nextCommand)
+{
+  CheckIntegrityEntryHandle entry =
+    new StreamCheckIntegrityEntry(req, _requestGroup, nextCommand);
+#ifdef ENABLE_MESSAGE_DIGEST
+  if(File(_requestGroup->getFilePath()).size() > 0 &&
+     e->option->get(PREF_CHECK_INTEGRITY) == V_TRUE &&
+     entry->isValidationReady()) {
+    entry->initValidator();
+    logger->debug("Issuing CheckIntegrityCommand.");
+    CheckIntegrityCommand* command =
+      new CheckIntegrityCommand(CUIDCounterSingletonHolder::instance()->newID(), _requestGroup, e, entry);
+    e->commands.push_back(command);
+  } else
+#endif // ENABLE_MESSAGE_DIGEST
+    {
+      e->addCommand(entry->prepareForNextAction(e));
+    }
+}

+ 25 - 7
src/AbstractCommand.h

@@ -36,20 +36,24 @@
 #define _D_ABSTRACT_COMMAND_H_
 
 #include "Command.h"
-#include "Request.h"
-#include "DownloadEngine.h"
-#include "SegmentMan.h"
 #include "TimeA2.h"
-#include "RecoverableException.h"
-#include "RequestGroup.h"
+#include "RequestGroupAware.h"
+#include "Socket.h"
 
-class AbstractCommand : public Command {
+class Request;
+extern typedef SharedHandle<Request> RequestHandle;
+class DownloadEngine;
+class Segment;
+extern typedef SharedHandle<Segment> SegmentHandle;
+class NameResolver;
+extern typedef SharedHandle<NameResolver> NameResolverHandle;
+
+class AbstractCommand : public Command, public RequestGroupAware {
 private:
   Time checkPoint;
   int32_t timeout;
 protected:
   RequestHandle req;
-  RequestGroup* _requestGroup;
   DownloadEngine* e;
   SocketHandle socket;
   SegmentHandle segment;
@@ -70,12 +74,26 @@ protected:
   virtual bool nameResolveFinished() const;
 #endif // ENABLE_ASYNC_DNS
   void setTimeout(int32_t timeout) { this->timeout = timeout; }
+
+  void loadAndOpenFile();
+
+  bool tryAutoFileRenaming();
+
+  void initPieceStorage();
+
+  bool downloadFinishedByFileLength();
+
+  void prepareForNextAction(Command* nextCommand = 0);
+
+  void shouldCancelDownloadForSafety();
+
 private:
   bool checkSocketIsReadable;
   bool checkSocketIsWritable;
   SocketHandle readCheckTarget;
   SocketHandle writeCheckTarget;
   bool nameResolverCheck;
+
 public:
   AbstractCommand(int32_t cuid, const RequestHandle& req, RequestGroup* requestGroup, DownloadEngine* e, const SocketHandle& s = SocketHandle());
   virtual ~AbstractCommand();

+ 33 - 20
src/AbstractDiskWriter.cc

@@ -33,7 +33,6 @@
  */
 /* copyright --> */
 #include "AbstractDiskWriter.h"
-#include "DlAbortEx.h"
 #include "File.h"
 #include "Util.h"
 #include "message.h"
@@ -47,8 +46,6 @@
 
 AbstractDiskWriter::AbstractDiskWriter():
   fd(-1),
-  fileAllocator(0),
-  glowFileAllocator(0),
   logger(LogFactory::getInstance())
 {}
 
@@ -57,7 +54,9 @@ AbstractDiskWriter::~AbstractDiskWriter()
   closeFile();
 }
 
-void AbstractDiskWriter::openFile(const string& filename, int64_t totalLength) {
+void AbstractDiskWriter::openFile(const string& filename, int64_t totalLength)
+  throw(DlAbortEx*)
+{
   File f(filename);
   if(f.exists()) {
     openExistingFile(filename, totalLength);
@@ -66,14 +65,18 @@ void AbstractDiskWriter::openFile(const string& filename, int64_t totalLength) {
   }
 }
 
-void AbstractDiskWriter::closeFile() {
+void AbstractDiskWriter::closeFile()
+{
   if(fd >= 0) {
     close(fd);
     fd = -1;
   }
 }
 
-void AbstractDiskWriter::openExistingFile(const string& filename, int64_t totalLength) {
+void AbstractDiskWriter::openExistingFile(const string& filename,
+					  int64_t totalLength)
+  throw(DlAbortEx*)
+{
   this->filename = filename;
   File f(filename);
   if(!f.isFile()) {
@@ -83,17 +86,11 @@ void AbstractDiskWriter::openExistingFile(const string& filename, int64_t totalL
   if((fd = open(filename.c_str(), O_RDWR|O_BINARY, OPEN_MODE)) < 0) {
     throw new DlAbortEx(EX_FILE_OPEN, filename.c_str(), strerror(errno));
   }
-  if(f.size() < totalLength) {
-    if(!fileAllocator.isNull()) {
-      logger->notice(MSG_ALLOCATING_FILE,
-		     filename.c_str(),
-		     Util::ullitos(totalLength).c_str());
-      glowFileAllocator->allocate(fd, totalLength);
-    }
-  }
 }
 
-void AbstractDiskWriter::createFile(const string& filename, int32_t addFlags) {
+void AbstractDiskWriter::createFile(const string& filename, int32_t addFlags)
+  throw(DlAbortEx*)
+{
   this->filename = filename;
   // TODO proper filename handling needed
   assert(filename.size());
@@ -105,28 +102,36 @@ void AbstractDiskWriter::createFile(const string& filename, int32_t addFlags) {
   }  
 }
 
-int32_t AbstractDiskWriter::writeDataInternal(const char* data, int32_t len) {
+int32_t AbstractDiskWriter::writeDataInternal(const unsigned char* data, int32_t len)
+{
   return write(fd, data, len);
 }
 
-int32_t AbstractDiskWriter::readDataInternal(char* data, int32_t len) {
+int32_t AbstractDiskWriter::readDataInternal(unsigned char* data, int32_t len)
+{
   return read(fd, data, len);
 }
 
-void AbstractDiskWriter::seek(int64_t offset) {
+void AbstractDiskWriter::seek(int64_t offset)
+  throw(DlAbortEx*)
+{
   if(offset != lseek(fd, offset, SEEK_SET)) {
     throw new DlAbortEx(EX_FILE_SEEK, filename.c_str(), strerror(errno));
   }
 }
 
-void AbstractDiskWriter::writeData(const char* data, int32_t len, int64_t offset) {
+void AbstractDiskWriter::writeData(const unsigned char* data, int32_t len, int64_t offset)
+  throw(DlAbortEx*)
+{
   seek(offset);
   if(writeDataInternal(data, len) < 0) {
     throw new DlAbortEx(EX_FILE_WRITE, filename.c_str(), strerror(errno));
   }
 }
 
-int32_t AbstractDiskWriter::readData(char* data, int32_t len, int64_t offset) {
+int32_t AbstractDiskWriter::readData(unsigned char* data, int32_t len, int64_t offset)
+  throw(DlAbortEx*)
+{
   int32_t ret;
   seek(offset);
   if((ret = readDataInternal(data, len)) < 0) {
@@ -136,13 +141,21 @@ int32_t AbstractDiskWriter::readData(char* data, int32_t len, int64_t offset) {
 }
 
 void AbstractDiskWriter::truncate(int64_t length)
+  throw(DlAbortEx*)
 {
+  if(fd == -1) {
+    throw new DlAbortEx("File not opened.");
+  }
   ftruncate(fd, length);
 }
 
 // TODO the file descriptor fd must be opened before calling this function.
 int64_t AbstractDiskWriter::size() const
+  throw(DlAbortEx*)
 {
+  if(fd == -1) {
+    throw new DlAbortEx("File not opened.");
+  }
   struct stat fileStat;
   if(fstat(fd, &fileStat) < 0) {
     return 0;

+ 11 - 23
src/AbstractDiskWriter.h

@@ -36,52 +36,40 @@
 #define _D_ABSTRACT_DISK_WRITER_H_
 
 #include "DiskWriter.h"
-#include "FileAllocator.h"
 #include "Logger.h"
+#include "DlAbortEx.h"
 
 class AbstractDiskWriter : public DiskWriter {
 protected:
   string filename;
   int32_t fd;
-  FileAllocatorHandle fileAllocator;
-  FileAllocatorHandle glowFileAllocator;
   const Logger* logger;
 
-  void createFile(const string& filename, int32_t addFlags = 0);
+  void createFile(const string& filename, int32_t addFlags = 0) throw(DlAbortEx*);
 
 private:
-  int32_t writeDataInternal(const char* data, int32_t len);
-  int32_t readDataInternal(char* data, int32_t len);
+  int32_t writeDataInternal(const unsigned char* data, int32_t len);
+  int32_t readDataInternal(unsigned char* data, int32_t len);
 
-  void seek(int64_t offset);
+  void seek(int64_t offset) throw(DlAbortEx*);
 
 public:
   AbstractDiskWriter();
   virtual ~AbstractDiskWriter();
 
-  virtual void openFile(const string& filename, int64_t totalLength = 0);
+  virtual void openFile(const string& filename, int64_t totalLength = 0) throw(DlAbortEx*);
 
   virtual void closeFile();
 
-  virtual void openExistingFile(const string& filename, int64_t totalLength = 0);
+  virtual void openExistingFile(const string& filename, int64_t totalLength = 0) throw(DlAbortEx*);
 
-  virtual void writeData(const char* data, int32_t len, int64_t offset);
+  virtual void writeData(const unsigned char* data, int32_t len, int64_t offset) throw(DlAbortEx*);
 
-  virtual int32_t readData(char* data, int32_t len, int64_t offset);
+  virtual int32_t readData(unsigned char* data, int32_t len, int64_t offset) throw(DlAbortEx*);
 
-  void setFileAllocator(const FileAllocatorHandle& fileAllocator)
-  {
-    this->fileAllocator = fileAllocator;
-  }
+  virtual void truncate(int64_t length) throw(DlAbortEx*);
 
-  void setGlowFileAllocator(const FileAllocatorHandle& fileAllocator)
-  {
-    this->glowFileAllocator = fileAllocator;
-  }
-
-  virtual void truncate(int64_t length);
-
-  virtual int64_t size() const;
+  virtual int64_t size() const throw(DlAbortEx*);
 };
 
 #endif // _D_ABSTRACT_DISK_WRITER_H_

+ 3 - 0
src/AbstractProxyRequestCommand.cc

@@ -33,6 +33,9 @@
  */
 /* copyright --> */
 #include "AbstractProxyRequestCommand.h"
+#include "DownloadEngine.h"
+#include "RequestGroup.h"
+#include "Request.h"
 #include "HttpConnection.h"
 #include "prefs.h"
 

+ 3 - 1
src/AbstractProxyRequestCommand.h

@@ -36,7 +36,9 @@
 #define _D_ABSTRACT_PROXY_REQUEST_COMMAND_H_
 
 #include "AbstractCommand.h"
-#include "HttpConnection.h"
+
+class HttpConnection;
+extern typedef SharedHandle<HttpConnection> HttpConnectionHandle;
 
 class AbstractProxyRequestCommand : public AbstractCommand {
 protected:

+ 5 - 0
src/AbstractProxyResponseCommand.cc

@@ -33,6 +33,11 @@
  */
 /* copyright --> */
 #include "AbstractProxyResponseCommand.h"
+#include "HttpConnection.h"
+#include "Request.h"
+#include "RequestGroup.h"
+#include "DownloadEngine.h"
+#include "HttpResponse.h"
 #include "HttpRequestCommand.h"
 #include "DlRetryEx.h"
 #include "message.h"

+ 3 - 1
src/AbstractProxyResponseCommand.h

@@ -36,7 +36,9 @@
 #define _D_ABSTRACT_PROXY_RESPONSE_COMMAND_H_
 
 #include "AbstractCommand.h"
-#include "HttpConnection.h"
+
+class HttpConnection;
+extern typedef SharedHandle<HttpConnection> HttpConnectionHandle;
 
 class AbstractProxyResponseCommand : public AbstractCommand {
 protected:

+ 23 - 6
src/AbstractSingleDiskAdaptor.cc

@@ -34,28 +34,40 @@
 /* copyright --> */
 #include "AbstractSingleDiskAdaptor.h"
 #include "File.h"
+#include "SingleFileAllocationIterator.h"
 
-void AbstractSingleDiskAdaptor::initAndOpenFile() {
+void AbstractSingleDiskAdaptor::initAndOpenFile()
+  throw(DlAbortEx*)
+{
   diskWriter->initAndOpenFile(getFilePath(), totalLength);
 }
 
-void AbstractSingleDiskAdaptor::openFile() {
+void AbstractSingleDiskAdaptor::openFile()
+  throw(DlAbortEx*)
+{
   diskWriter->openFile(getFilePath(), totalLength);
 }
 
-void AbstractSingleDiskAdaptor::closeFile() {
+void AbstractSingleDiskAdaptor::closeFile()
+{
   diskWriter->closeFile();
 }
 
-void AbstractSingleDiskAdaptor::openExistingFile() {
+void AbstractSingleDiskAdaptor::openExistingFile()
+  throw(DlAbortEx*)
+{
   diskWriter->openExistingFile(getFilePath(), totalLength);
 }
 
-void AbstractSingleDiskAdaptor::writeData(const unsigned char* data, int32_t len, int64_t offset) {
+void AbstractSingleDiskAdaptor::writeData(const unsigned char* data, int32_t len, int64_t offset)
+  throw(DlAbortEx*)
+{
   diskWriter->writeData(data, len, offset);
 }
 
-int32_t AbstractSingleDiskAdaptor::readData(unsigned char* data, int32_t len, int64_t offset) {
+int32_t AbstractSingleDiskAdaptor::readData(unsigned char* data, int32_t len, int64_t offset)
+  throw(DlAbortEx*)
+{
   return diskWriter->readData(data, len, offset);
 }
 
@@ -63,3 +75,8 @@ bool AbstractSingleDiskAdaptor::fileExists()
 {
   return File(getFilePath()).exists();
 }
+
+FileAllocationIteratorHandle AbstractSingleDiskAdaptor::fileAllocationIterator()
+{
+  return new SingleFileAllocationIterator(this);
+}

+ 16 - 8
src/AbstractSingleDiskAdaptor.h

@@ -37,6 +37,7 @@
 
 #include "DiskAdaptor.h"
 #include "DiskWriter.h"
+#include "DlAbortEx.h"
 
 class AbstractSingleDiskAdaptor : public DiskAdaptor {
 protected:
@@ -47,26 +48,33 @@ public:
 
   virtual ~AbstractSingleDiskAdaptor() {}
 
-  virtual void initAndOpenFile();
+  virtual void initAndOpenFile() throw(DlAbortEx*);
 
-  virtual void openFile();
+  virtual void openFile() throw(DlAbortEx*);
 
   virtual void closeFile();
 
-  virtual void openExistingFile();
+  virtual void openExistingFile() throw(DlAbortEx*);
 
   virtual void writeData(const unsigned char* data, int32_t len,
-			 int64_t offset);
+			 int64_t offset) throw(DlAbortEx*);
 
-  virtual int32_t readData(unsigned char* data, int32_t len, int64_t offset);
+  virtual int32_t readData(unsigned char* data, int32_t len, int64_t offset) throw(DlAbortEx*);
 
   virtual bool fileExists();
 
-  virtual int64_t size() const
+  virtual int64_t size() const throw(DlAbortEx*)
   {
-    return getTotalLength();
+    return diskWriter->size();
   }
-    
+
+  virtual void truncate(int64_t length) throw(DlAbortEx*)
+  {
+    diskWriter->truncate(length);
+  }
+  
+  virtual FileAllocationIteratorHandle fileAllocationIterator();
+
   void setDiskWriter(const DiskWriterHandle diskWriter) {
     this->diskWriter = diskWriter;
   }

+ 17 - 1
src/ActivePeerConnectionCommand.cc

@@ -37,6 +37,22 @@
 #include "CUIDCounter.h"
 #include "message.h"
 
+ActivePeerConnectionCommand::ActivePeerConnectionCommand(int cuid,
+							 RequestGroup* requestGroup,
+							 DownloadEngine* e,
+							 const BtContextHandle& btContext,
+							 int32_t interval)
+  :Command(cuid),
+   BtContextAwareCommand(btContext),
+   RequestGroupAware(requestGroup),
+   interval(interval),
+   e(e),
+   _lowestSpeedLimit(20*1024),
+   _numNewConnection(5)
+{}
+
+ActivePeerConnectionCommand::~ActivePeerConnectionCommand() {}
+
 bool ActivePeerConnectionCommand::execute() {
   if(btRuntime->isHalt()) {
     return true;
@@ -63,7 +79,7 @@ void ActivePeerConnectionCommand::connectToPeer(const PeerHandle& peer)
   }
   peer->cuid = CUIDCounterSingletonHolder::instance()->newID();
   PeerInitiateConnectionCommand* command =
-    new PeerInitiateConnectionCommand(peer->cuid, peer, e, btContext);
+    new PeerInitiateConnectionCommand(peer->cuid, _requestGroup, peer, e, btContext);
   e->commands.push_back(command);
   logger->info(MSG_CONNECTING_TO_PEER,
 	       cuid, peer->ipaddr.c_str());

+ 12 - 12
src/ActivePeerConnectionCommand.h

@@ -35,30 +35,30 @@
 #ifndef _D_ACTIVE_PEER_CONNECTION_COMMAND_H_
 #define _D_ACTIVE_PEER_CONNECTION_COMMAND_H_
 
+#include "Command.h"
 #include "BtContextAwareCommand.h"
-#include "TorrentDownloadEngine.h"
+#include "DownloadEngine.h"
 #include "TimeA2.h"
+#include "RequestGroupAware.h"
 
-class ActivePeerConnectionCommand : public BtContextAwareCommand {
+class ActivePeerConnectionCommand : public Command,
+				    public BtContextAwareCommand,
+				    public RequestGroupAware
+{
 private:
   int32_t interval; // UNIT: sec
-  TorrentDownloadEngine* e;
+  DownloadEngine* e;
   Time checkPoint;
   int32_t _lowestSpeedLimit; // UNIT: byte/sec
   int32_t _numNewConnection; // the number of the connection to establish.
 public:
   ActivePeerConnectionCommand(int cuid,
-			      TorrentDownloadEngine* e,
+			      RequestGroup* requestGroup,
+			      DownloadEngine* e,
 			      const BtContextHandle& btContext,
-			      int32_t interval)
-    :BtContextAwareCommand(cuid, btContext),
-     interval(interval),
-     e(e),
-    _lowestSpeedLimit(20*1024),
-    _numNewConnection(5)
-    {}
+			      int32_t interval);
      
-  virtual ~ActivePeerConnectionCommand() {}
+  virtual ~ActivePeerConnectionCommand();
 
   virtual bool execute();
 

+ 2 - 2
src/AlphaNumberDecorator.h

@@ -36,7 +36,7 @@
 #define _D_ALPHA_NUMBER_DECORATOR_H_
 
 #include "NumberDecorator.h"
-#include "FatalException.h"
+#include "DlAbortEx.h"
 
 class AlphaNumberDecorator : public NumberDecorator
 {
@@ -64,7 +64,7 @@ public:
   virtual string decorate(int32_t number)
   {
     if(number < 0) {
-      throw new FatalException("The number must be greater than 0.");
+      throw new DlAbortEx("The number must be greater than 0.");
     }
     if(number == 0) {
       return widen(_zero, _width);

+ 8 - 1
src/AutoSaveCommand.cc

@@ -33,10 +33,17 @@
  */
 /* copyright --> */
 #include "AutoSaveCommand.h"
+#include "DownloadEngine.h"
+#include "RequestGroupMan.h"
+
+AutoSaveCommand::AutoSaveCommand(int32_t cuid, DownloadEngine* e, int32_t interval):
+  TimeBasedCommand(cuid, e, interval) {}
+
+AutoSaveCommand::~AutoSaveCommand() {}
 
 void AutoSaveCommand::preProcess()
 {
-  if(_e->_requestGroupMan->downloadFinished()) {
+  if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
     _exit = true;
   }
 }

+ 2 - 3
src/AutoSaveCommand.h

@@ -40,10 +40,9 @@
 class AutoSaveCommand : public TimeBasedCommand
 {
 public:
-  AutoSaveCommand(int32_t cuid, DownloadEngine* e, int32_t interval):
-    TimeBasedCommand(cuid, e, interval) {}
+  AutoSaveCommand(int32_t cuid, DownloadEngine* e, int32_t interval);
 
-  virtual ~AutoSaveCommand() {}
+  virtual ~AutoSaveCommand();
 
   virtual void preProcess();
 

+ 52 - 0
src/BinaryStream.h

@@ -0,0 +1,52 @@
+/* <!-- 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_BINARY_STREAM_H_
+#define _D_BINARY_STREAM_H_
+
+#include "common.h"
+#include "DlAbortEx.h"
+
+class BinaryStream {
+public:
+  virtual ~BinaryStream() {}
+  
+  virtual void writeData(const unsigned char* data, int32_t len, int64_t offset) = 0;
+
+  virtual int32_t readData(unsigned char* data, int32_t len, int64_t offset) = 0;
+};
+
+typedef SharedHandle<BinaryStream> BinaryStreamHandle;
+
+#endif // _D_BINARY_STREAM_H_

+ 22 - 30
src/ConsoleDownloadEngine.h → src/BtCheckIntegrityEntry.cc

@@ -32,37 +32,29 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#ifndef _D_CONSOLE_DOWNLOAD_ENGINE_H_
-#define _D_CONSOLE_DOWNLOAD_ENGINE_H_
-
+#include "BtCheckIntegrityEntry.h"
+#include "BtSetup.h"
+#include "BtFileAllocationEntry.h"
+#include "CUIDCounter.h"
+#include "RequestGroup.h"
+#include "PieceStorage.h"
 #include "DownloadEngine.h"
-#include "TimeA2.h"
+#include "FileAllocationMan.h"
+#include "DiskAdaptor.h"
 
-class ConsoleDownloadEngine : public DownloadEngine {
-private:
-  Time cp;
-  int64_t psize;
-  int32_t speed;
-  // The time when startup
-  Time startup;
-  // The number of bytes downloaded at startup
-  int64_t startupLength;
-  bool isStartupLengthSet;
-  // The average speed(bytes per second) since startup
-  int32_t avgSpeed;
-  // The estimated remaining time to complete the download.
-  int32_t eta;
-protected:
-  void sendStatistics(int64_t currentSize, int64_t totalSize);
-  virtual void initStatistics();
-  virtual void calculateStatistics();
-  virtual void onEndOfRun();
-  virtual void afterEachIteration();
-public:
-  ConsoleDownloadEngine();
-  ~ConsoleDownloadEngine();
+BtCheckIntegrityEntry::BtCheckIntegrityEntry(RequestGroup* requestGroup):
+  CheckIntegrityEntry(requestGroup, 0) {}
 
-  void fillCommand();
-};
+BtCheckIntegrityEntry::~BtCheckIntegrityEntry() {}
 
-#endif // _D_CONSOLE_DOWNLOAD_ENGINE_H_
+Commands BtCheckIntegrityEntry::prepareForNextAction(DownloadEngine* e)
+{
+  Commands commands;
+  FileAllocationEntryHandle entry = new BtFileAllocationEntry(_requestGroup);
+  if(_requestGroup->isFileAllocationEnabled() && !_requestGroup->getPieceStorage()->getDiskAdaptor()->fileAllocationIterator()->finished()) {
+    e->_fileAllocationMan->pushFileAllocationEntry(entry);
+  } else {
+    commands = entry->prepareForNextAction(e);
+  }
+  return commands;
+}

+ 51 - 0
src/BtCheckIntegrityEntry.h

@@ -0,0 +1,51 @@
+/* <!-- 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_CHECK_INTEGRITY_ENTRY_H_
+#define _D_BT_CHECK_INTEGRITY_ENTRY_H_
+
+#include "CheckIntegrityEntry.h"
+
+class BtCheckIntegrityEntry : public CheckIntegrityEntry {
+public:
+  BtCheckIntegrityEntry(RequestGroup* requestGroup);
+
+  virtual ~BtCheckIntegrityEntry();
+
+  virtual Commands prepareForNextAction(DownloadEngine* e);
+};
+
+typedef SharedHandle<BtCheckIntegrityEntry> BtCheckIntegrityEntryHandle;
+
+#endif // _D_BT_FILE_ALLOCATION_ENTRY_H_

+ 8 - 25
src/BtContext.h

@@ -35,57 +35,40 @@
 #ifndef _D_BT_CONTEXT_H_
 #define _D_BT_CONTEXT_H_
 
-#include "common.h"
-#include "FileEntry.h"
-#include "AnnounceTier.h"
+#include "DownloadContext.h"
 
 #define INFO_HASH_LENGTH 20
 #define MAX_PEER_ERROR 5
 #define MAX_PEERS 55
 
+class AnnounceTier;
+extern typedef SharedHandle<AnnounceTier> AnnounceTierHandle;
 typedef deque<AnnounceTierHandle> AnnounceTiers;
 
-class BtContext {
+class RequestGroup;
+
+class BtContext:public DownloadContext {
 public:
   virtual ~BtContext() {}
 
-  enum FILE_MODE {
-    SINGLE,
-    MULTI
-  };
-
   virtual const unsigned char* getInfoHash() const = 0;
 
   virtual int32_t getInfoHashLength() const = 0;
 
   virtual string getInfoHashAsString() const = 0;
 
-  virtual string getPieceHash(int32_t index) const = 0;
-  
-  virtual const Strings& getPieceHashes() const = 0;
-
-  virtual int64_t 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 int32_t getPieceLength() const = 0;
-
-  virtual int32_t getNumPieces() const = 0;
-
   /**
    * Returns the peer id of localhost, 20 byte length
    */
   virtual const unsigned char* getPeerId() = 0;
 
   virtual Integers computeFastSet(const string& ipaddr, int32_t fastSetSize) = 0;
+  
+  virtual RequestGroup* getOwnerRequestGroup() = 0;
 
 };
 

+ 1 - 3
src/BtContextAwareCommand.cc

@@ -35,9 +35,7 @@
 #include "BtContextAwareCommand.h"
 #include "BtRegistry.h"
 
-BtContextAwareCommand::BtContextAwareCommand(int cuid,
-					     const BtContextHandle& btContext):
-  Command(cuid),
+BtContextAwareCommand::BtContextAwareCommand(const BtContextHandle& btContext):
   btContext(btContext),
   btRuntime(BT_RUNTIME(btContext)),
   pieceStorage(PIECE_STORAGE(btContext)),

+ 4 - 3
src/BtContextAwareCommand.h

@@ -35,7 +35,7 @@
 #ifndef _D_BT_CONTEXT_AWARE_COMMAND_H_
 #define _D_BT_CONTEXT_AWARE_COMMAND_H_
 
-#include "Command.h"
+#include "common.h"
 #include "BtContext.h"
 #include "BtRuntime.h"
 #include "PieceStorage.h"
@@ -43,7 +43,8 @@
 #include "BtAnnounce.h"
 #include "BtProgressInfoFile.h"
 
-class BtContextAwareCommand : public Command {
+class BtContextAwareCommand
+{
 protected:
   BtContextHandle btContext;
   BtRuntimeHandle btRuntime;
@@ -52,7 +53,7 @@ protected:
   BtAnnounceHandle btAnnounce;
   BtProgressInfoFileHandle btProgressInfoFile;
 public:
-  BtContextAwareCommand(int cuid, const BtContextHandle& btContext);
+  BtContextAwareCommand(const BtContextHandle& btContext);
 
   virtual ~BtContextAwareCommand();
 };

+ 83 - 0
src/BtDependency.cc

@@ -0,0 +1,83 @@
+/* <!-- 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 "BtDependency.h"
+#include "RequestGroup.h"
+#include "Option.h"
+#include "LogFactory.h"
+#include "DefaultBtContext.h"
+#include "RecoverableException.h"
+#include "message.h"
+#include "prefs.h"
+
+BtDependency::BtDependency(const RequestGroupWeakHandle& dependant,
+			   const RequestGroupWeakHandle& dependee,
+			   const Option* option):
+  _dependant(dependant),
+  _dependee(dependee),
+  _option(option),
+  _logger(LogFactory::getInstance()) {}
+
+BtDependency::~BtDependency() {}
+
+bool BtDependency::resolve()
+{
+  if(_dependee->getNumCommand() == 0 && _dependee->downloadFinished()) {
+    DefaultBtContextHandle btContext = new DefaultBtContext();
+    try {
+      btContext->load(_dependee->getFilePath());
+      if(_option->defined(PREF_PEER_ID_PREFIX)) {
+	btContext->setPeerIdPrefix(_option->get(PREF_PEER_ID_PREFIX));
+      }
+      btContext->setDir(_dependant->getDownloadContext()->getDir());
+    } catch(RecoverableException* e) {
+      _logger->error(EX_EXCEPTION_CAUGHT, e);
+      delete e;
+      _logger->debug("BtDependency for GID#%d failed. Go without Bt.",
+		     _dependant->getGID());
+      return true;
+    }
+    _logger->debug("Dependency resolved for GID#%d", _dependant->getGID());
+    _dependant->setDownloadContext(btContext);
+    btContext->setOwnerRequestGroup(_dependant.get());
+    return true;
+  } else if(_dependee->getNumCommand() == 0) {
+    // _dependee's download failed.
+    _logger->debug("BtDependency for GID#%d failed. Go without Bt.",
+		   _dependant->getGID());    
+    return true;
+  } else {
+    return false;
+  }
+}

+ 22 - 19
src/TorrentRequestInfo.h → src/BtDependency.h

@@ -32,30 +32,33 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#ifndef _D_TORRENT_REQUEST_INFO_H_
-#define _D_TORRENT_REQUEST_INFO_H_
+#ifndef _D_BT_DEPENDENCY_H_
+#define _D_BT_DEPENDENCY_H_
 
-#include "RequestInfo.h"
-#include "TorrentDownloadEngine.h"
-#include "BtContext.h"
+#include "Dependency.h"
 
-class TorrentRequestInfo : public RequestInfo {
-private:
-  string torrentFile;
-  Strings targetFiles;
+class RequestGroup;
+extern typedef WeakHandle<RequestGroup> RequestGroupWeakHandle;
+class Option;
+class Logger;
 
+class BtDependency : public Dependency
+{
+private:
+  RequestGroupWeakHandle _dependant;
+  RequestGroupWeakHandle _dependee;
+  const Option* _option;
+  const Logger* _logger;
 public:
-  TorrentRequestInfo(const string& torrentFile, Option* op):
-    RequestInfo(op),
-    torrentFile(torrentFile) {}
+  BtDependency(const RequestGroupWeakHandle& dependant,
+	       const RequestGroupWeakHandle& dependee,
+	       const Option* option);
 
-  virtual ~TorrentRequestInfo() {}
+  virtual ~BtDependency();
 
-  virtual RequestInfos execute();
-
-  void setTargetFiles(const Strings& targetFiles) {
-    this->targetFiles = targetFiles;
-  }
+  virtual bool resolve();
 };
 
-#endif // _D_TORRENT_REQUEST_INFO_H_
+typedef SharedHandle<BtDependency> BtDependencyHandle;
+
+#endif // _D_BT_DEPENDENCY_H_

+ 15 - 20
src/TorrentAutoSaveCommand.cc → src/BtFileAllocationEntry.cc

@@ -32,27 +32,22 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#include "TorrentAutoSaveCommand.h"
-#include "Util.h"
+#include "BtFileAllocationEntry.h"
+#include "BtSetup.h"
+#include "RequestGroup.h"
+#include "Command.h"
+#include "DownloadEngine.h"
 
-TorrentAutoSaveCommand::TorrentAutoSaveCommand(int32_t cuid,
-					       TorrentDownloadEngine* e,
-					       const BtContextHandle& btContext,
-					       int32_t interval):
-  BtContextAwareCommand(cuid, btContext),
-  e(e),
-  interval(interval) {}
+BtFileAllocationEntry::BtFileAllocationEntry(RequestGroup* requestGroup):
+  FileAllocationEntry(requestGroup, 0) {}
 
-TorrentAutoSaveCommand::~TorrentAutoSaveCommand() {}
+BtFileAllocationEntry::~BtFileAllocationEntry() {}
 
-bool TorrentAutoSaveCommand::execute() {
-  if(checkPoint.elapsed(interval) || btRuntime->isHalt()) {
-    checkPoint.reset();
-    btProgressInfoFile->save();
-    if(btRuntime->isHalt()) {
-      return true;
-    }
-  }
-  e->commands.push_back(this);
-  return false;
+Commands BtFileAllocationEntry::prepareForNextAction(DownloadEngine* e)
+{
+  Commands commands = BtSetup().setup(_requestGroup, e, e->option);
+  // TODO don't integerate http/ftp when multi-file torrent
+  Commands streamCommands = _requestGroup->createNextCommandWithAdj(e, 0);
+  copy(streamCommands.begin(), streamCommands.end(), back_inserter(commands));
+  return commands;
 }

+ 56 - 0
src/BtFileAllocationEntry.h

@@ -0,0 +1,56 @@
+/* <!-- 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_FILE_ALLOCATION_ENTRY_H_
+#define _D_BT_FILE_ALLOCATION_ENTRY_H_
+
+#include "FileAllocationEntry.h"
+
+class RequestGroup;
+class DownloadEngine;
+class Command;
+extern typedef deque<Command*> Commands;
+
+class BtFileAllocationEntry : public FileAllocationEntry {
+public:
+  BtFileAllocationEntry(RequestGroup* requestGroup);
+
+  virtual ~BtFileAllocationEntry();
+
+  virtual Commands prepareForNextAction(DownloadEngine* e);
+};
+
+typedef SharedHandle<BtFileAllocationEntry> BtFileAllocationEntryHandle;
+
+#endif // _D_BT_FILE_ALLOCATION_ENTRY_H_

+ 2 - 2
src/BtPieceMessage.cc

@@ -39,8 +39,8 @@
 #include "DlAbortEx.h"
 #include "BtChokingEvent.h"
 #include "BtCancelSendingPieceEvent.h"
-#include "DiskAdaptorWriter.h"
 #include "MessageDigestHelper.h"
+#include "DiskAdaptor.h"
 
 void BtPieceMessage::setBlock(const unsigned char* block, int32_t blockLength) {
   delete [] this->block;
@@ -193,7 +193,7 @@ bool BtPieceMessage::checkPieceHash(const PieceHandle& piece) {
   int64_t offset =
     ((int64_t)piece->getIndex())*btContext->getPieceLength();
   
-  return MessageDigestHelper::digest("sha1", new DiskAdaptorWriter(pieceStorage->getDiskAdaptor()), offset, piece->getLength())
+  return MessageDigestHelper::digest("sha1", pieceStorage->getDiskAdaptor(), offset, piece->getLength())
     == btContext->getPieceHash(piece->getIndex());
 }
 

+ 24 - 21
src/ConsoleFileAllocationMonitor.cc → src/BtPostDownloadHandler.cc

@@ -32,28 +32,31 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#include "ConsoleFileAllocationMonitor.h"
-#include "Util.h"
+#include "BtPostDownloadHandler.h"
+#include "DefaultBtContext.h"
+#include "prefs.h"
+#include "RequestGroup.h"
+#include "Option.h"
 
-void ConsoleFileAllocationMonitor::showProgress() {
-  int32_t progressPercentage = (int32_t)(((current-min)*1.0/(max-min))*100);
-  int32_t numOfStar = progressPercentage/10*2;
+BtPostDownloadHandler::BtPostDownloadHandler(const Option* option):
+  PostDownloadHandler(".torrent", option)
+{}
 
-  cout << "\r                                                                                ";
-  cout << "\r";
-  cout << "|";
-  for(int32_t i = 0; i < numOfStar; ++i) {
-    cout << "*";
-  }
-  for(int32_t i = 0; i < 20-numOfStar; ++i) {
-    cout << " ";
+BtPostDownloadHandler::~BtPostDownloadHandler() {}
+
+RequestGroups BtPostDownloadHandler::getNextRequestGroups(const string& path)
+{
+  RequestGroupHandle rg = new RequestGroup(_option, Strings());
+  DefaultBtContextHandle btContext = new DefaultBtContext();
+  btContext->load(path);
+  if(_option->defined(PREF_PEER_ID_PREFIX)) {
+    btContext->setPeerIdPrefix(_option->get(PREF_PEER_ID_PREFIX));
   }
-  cout << "|";
-  cout << progressPercentage << "%";
-  cout << "(";
-  cout << Util::ullitos(current, true) << "/" << Util::ullitos(max, true);
-  cout << ")";
-  cout << flush;
-  // Example,
-  // |******************* | 95%(1,333,3256/1,553,3232 bytes)
+  btContext->setDir(_option->get(PREF_DIR));
+  rg->setDownloadContext(btContext);
+  btContext->setOwnerRequestGroup(rg.get());
+  
+  RequestGroups groups;
+  groups.push_back(rg);
+  return groups;
 }

+ 51 - 0
src/BtPostDownloadHandler.h

@@ -0,0 +1,51 @@
+/* <!-- 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_POST_DOWNLOAD_HANDLER_H_
+#define _D_BT_POST_DOWNLOAD_HANDLER_H_
+
+#include "PostDownloadHandler.h"
+
+class BtPostDownloadHandler:public PostDownloadHandler
+{
+public:
+  BtPostDownloadHandler(const Option* option);
+
+  virtual ~BtPostDownloadHandler();
+
+  virtual RequestGroups getNextRequestGroups(const string& path);
+};
+
+typedef SharedHandle<BtPostDownloadHandler> BtPostDownloadHandlerHandle;
+#endif // _D_BT_POST_DOWNLOAD_HANDLER_H_

+ 0 - 2
src/BtProgressInfoFile.h

@@ -43,8 +43,6 @@ public:
 
   virtual string getFilename() = 0;
 
-  virtual void setFilename(const string& filename) = 0;
-
   virtual bool exists() = 0;
 
   virtual void save() = 0;

+ 62 - 65
src/BtRegistry.cc

@@ -35,6 +35,7 @@
 #include "BtRegistry.h"
 #include "DlAbortEx.h"
 
+BtContextMap BtRegistry::btContextMap;
 PeerStorageMap BtRegistry::peerStorageMap;
 PieceStorageMap BtRegistry::pieceStorageMap;
 BtAnnounceMap BtRegistry::btAnnounceMap;
@@ -42,93 +43,77 @@ BtRuntimeMap BtRegistry::btRuntimeMap;
 BtProgressInfoFileMap BtRegistry::btProgressInfoFileMap;
 PeerObjectClusterRegistry BtRegistry::peerObjectClusterRegistry;
 
-PeerStorageHandle BtRegistry::getPeerStorage(const string& key) {
-  PeerStorageMap::iterator itr = peerStorageMap.find(key);
-  if(itr == peerStorageMap.end()) {
-    return PeerStorageHandle(0);
-  } else {
-    return itr->second;
-  }
+PeerStorageHandle BtRegistry::getPeerStorage(const string& key)
+{
+  return peerStorageMap.getHandle(key);
 }
 
-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;
+void BtRegistry::registerPeerStorage(const string& key,
+				     const PeerStorageHandle& peerStorage)
+{
+  peerStorageMap.registerHandle(key, peerStorage);
 }
 				  
 PieceStorageHandle
-BtRegistry::getPieceStorage(const string& key) {
-  PieceStorageMap::iterator itr = pieceStorageMap.find(key);
-  if(itr == pieceStorageMap.end()) {
-    return PieceStorageHandle(0);
-  } else {
-    return itr->second;
-  }
+BtRegistry::getPieceStorage(const string& key)
+{
+  return pieceStorageMap.getHandle(key);
 }
 
-bool
+void
 BtRegistry::registerPieceStorage(const string& key,
-				 const PieceStorageHandle& pieceStorage) {
-  pieceStorageMap.erase(key);
-  PieceStorageMap::value_type p(key, pieceStorage);
-  pair<PieceStorageMap::iterator, bool> retval = pieceStorageMap.insert(p);
-  return retval.second;
+				 const PieceStorageHandle& pieceStorage)
+{
+  pieceStorageMap.registerHandle(key, pieceStorage);
 }
 
-BtRuntimeHandle BtRegistry::getBtRuntime(const string& key) {
-  BtRuntimeMap::iterator itr = btRuntimeMap.find(key);
-  if(itr == btRuntimeMap.end()) {
-    return BtRuntimeHandle(0);
-  } else {
-    return itr->second;
-  }
+BtRuntimeHandle BtRegistry::getBtRuntime(const string& key)
+{
+  return btRuntimeMap.getHandle(key);
 }
 
-bool
+void
 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;
+			      const BtRuntimeHandle& btRuntime)
+{
+  btRuntimeMap.registerHandle(key, btRuntime);
 }
 
-BtAnnounceHandle BtRegistry::getBtAnnounce(const string& key) {
-  BtAnnounceMap::iterator itr = btAnnounceMap.find(key);
-  if(itr == btAnnounceMap.end()) {
-    return BtAnnounceHandle(0);
-  } else {
-    return itr->second;
-  }
+BtAnnounceHandle BtRegistry::getBtAnnounce(const string& key)
+{
+  return btAnnounceMap.getHandle(key);
 }
 
-bool
+void
 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;
+			       const BtAnnounceHandle& btAnnounce)
+{
+  btAnnounceMap.registerHandle(key, btAnnounce);
 }
 
-BtProgressInfoFileHandle BtRegistry::getBtProgressInfoFile(const string& key) {
-  BtProgressInfoFileMap::iterator itr = btProgressInfoFileMap.find(key);
-  if(itr == btProgressInfoFileMap.end()) {
-    return BtProgressInfoFileHandle(0);
-  } else {
-    return itr->second;
-  }
+BtProgressInfoFileHandle BtRegistry::getBtProgressInfoFile(const string& key)
+{
+  return btProgressInfoFileMap.getHandle(key);
 }
 
-bool
+void
 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;
+				       const BtProgressInfoFileHandle& btProgressInfoFile)
+{
+  btProgressInfoFileMap.registerHandle(key, btProgressInfoFile);
+}
+
+BtContextHandle
+BtRegistry::getBtContext(const string& key)
+{
+  return btContextMap.getHandle(key);
+}
+
+void
+BtRegistry::registerBtContext(const string& key,
+			      const BtContextHandle& btContext)
+{
+  btContextMap.registerHandle(key, btContext);
 }
 
 PeerObjectClusterHandle
@@ -150,7 +135,8 @@ BtRegistry::unregisterPeerObjectCluster(const string& key)
   peerObjectClusterRegistry.unregisterHandle(key);
 }
 
-void BtRegistry::clear() {
+void BtRegistry::unregisterAll() {
+  btContextMap.clear();
   peerStorageMap.clear();
   pieceStorageMap.clear();
   btAnnounceMap.clear();
@@ -158,3 +144,14 @@ void BtRegistry::clear() {
   btProgressInfoFileMap.clear();
   peerObjectClusterRegistry.clear();
 }
+
+void BtRegistry::unregister(const string& key)
+{
+  btContextMap.unregisterHandle(key);
+  peerStorageMap.unregisterHandle(key);
+  pieceStorageMap.unregisterHandle(key);
+  btAnnounceMap.unregisterHandle(key);
+  btRuntimeMap.unregisterHandle(key);
+  btProgressInfoFileMap.unregisterHandle(key);
+  peerObjectClusterRegistry.unregisterHandle(key);
+}

+ 20 - 11
src/BtRegistry.h

@@ -36,6 +36,7 @@
 #define _D_BT_REGISTRY_H_
 
 #include "common.h"
+#include "BtContext.h"
 #include "PeerStorage.h"
 #include "PieceStorage.h"
 #include "BtAnnounce.h"
@@ -45,11 +46,12 @@
 #include "HandleRegistry.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;
+typedef HandleRegistry<string, PeerStorage> PeerStorageMap;
+typedef HandleRegistry<string, PieceStorage> PieceStorageMap;
+typedef HandleRegistry<string, BtAnnounce> BtAnnounceMap;
+typedef HandleRegistry<string, BtRuntime> BtRuntimeMap;
+typedef HandleRegistry<string, BtProgressInfoFile> BtProgressInfoFileMap;
+typedef HandleRegistry<string, BtContext>  BtContextMap;
 
 // for BtMessageFactory
 typedef HandleRegistry<string, PeerObject> PeerObjectCluster;
@@ -60,6 +62,7 @@ class BtRegistry {
 private:
   BtRegistry() {}
 
+  static BtContextMap btContextMap;
   static PeerStorageMap peerStorageMap;
   static PieceStorageMap pieceStorageMap;
   static BtAnnounceMap btAnnounceMap;
@@ -67,24 +70,28 @@ private:
   static BtProgressInfoFileMap btProgressInfoFileMap;
   static PeerObjectClusterRegistry peerObjectClusterRegistry;
 public:
+  static BtContextHandle getBtContext(const string& key);
+  static void registerBtContext(const string& key,
+				const BtContextHandle& btContext);
+
   static PeerStorageHandle getPeerStorage(const string& key);
-  static bool registerPeerStorage(const string& key,
+  static void registerPeerStorage(const string& key,
 				  const PeerStorageHandle& peer);
 				  
   static PieceStorageHandle getPieceStorage(const string& key);
-  static bool registerPieceStorage(const string& key,
+  static void registerPieceStorage(const string& key,
 				   const PieceStorageHandle& pieceStorage);
 
   static BtRuntimeHandle getBtRuntime(const string& key);
-  static bool registerBtRuntime(const string& key,
+  static void registerBtRuntime(const string& key,
 				const BtRuntimeHandle& btRuntime);
 
   static BtAnnounceHandle getBtAnnounce(const string& key);
-  static bool registerBtAnnounce(const string& key,
+  static void registerBtAnnounce(const string& key,
 				 const BtAnnounceHandle& btAnnounce);
 
   static BtProgressInfoFileHandle getBtProgressInfoFile(const string& key);
-  static bool registerBtProgressInfoFile(const string& key,
+  static void registerBtProgressInfoFile(const string& key,
 					 const BtProgressInfoFileHandle& btProgressInfoFile);
 
   // for PeerObject
@@ -98,7 +105,9 @@ public:
   static void
   unregisterPeerObjectCluster(const string& key);
 
-  static void clear();
+  static void unregisterAll();
+
+  static void unregister(const string& key);
 };
 
 #define PEER_STORAGE(btContext) \

+ 8 - 2
src/BtRuntime.h

@@ -46,12 +46,14 @@ private:
   int32_t port;
   bool halt;
   int32_t connections;
+  bool _ready;
 public:
   BtRuntime():
     uploadLengthAtStartup(0),
     port(0),
     halt(false),
-    connections(0)
+    connections(0),
+    _ready(false)
     {}
   ~BtRuntime() {}
 
@@ -83,7 +85,11 @@ public:
 
   bool lessThanMinPeer() const { return connections < MIN_PEERS; }
 
-  bool lessThanEqMinPeer() const { return connections <= MIN_PEERS; }  
+  bool lessThanEqMinPeer() const { return connections <= MIN_PEERS; }
+
+  bool ready() { return _ready; }
+
+  void setReady(bool go) { _ready = go; }
 };
 
 typedef SharedHandle<BtRuntime> BtRuntimeHandle;

+ 97 - 0
src/BtSetup.cc

@@ -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 --> */
+#include "BtSetup.h"
+#include "RequestGroup.h"
+#include "DownloadEngine.h"
+#include "Option.h"
+#include "BtRegistry.h"
+#include "PeerListenCommand.h"
+#include "TrackerWatcherCommand.h"
+#include "SeedCheckCommand.h"
+#include "PeerChokeCommand.h"
+#include "ActivePeerConnectionCommand.h"
+#include "UnionSeedCriteria.h"
+#include "TimeSeedCriteria.h"
+#include "ShareRatioSeedCriteria.h"
+#include "DefaultPieceStorage.h"
+#include "DefaultBtProgressInfoFile.h"
+#include "CUIDCounter.h"
+#include "prefs.h"
+
+Commands BtSetup::setup(RequestGroup* requestGroup,
+			DownloadEngine* e,
+			const Option* option)
+{
+  Commands commands;
+  BtContextHandle btContext = requestGroup->getDownloadContext();
+  if(btContext.isNull()) {
+    return commands;
+  }
+  // TODO following process is moved to BtSetup
+
+  // commands
+  commands.push_back(new TrackerWatcherCommand(CUIDCounterSingletonHolder::instance()->newID(),
+					       requestGroup,
+					       e,
+					       btContext));
+  commands.push_back(new PeerChokeCommand(CUIDCounterSingletonHolder::instance()->newID(),
+					  requestGroup,
+					  e,
+					  btContext,
+					  10));
+  commands.push_back(new ActivePeerConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(),
+						     requestGroup,
+						     e,
+						     btContext,
+						     30));
+
+  SharedHandle<UnionSeedCriteria> unionCri = new UnionSeedCriteria();
+  if(option->defined(PREF_SEED_TIME)) {
+    unionCri->addSeedCriteria(new TimeSeedCriteria(option->getAsInt(PREF_SEED_TIME)*60));
+  }
+  if(option->defined(PREF_SEED_RATIO)) {
+    unionCri->addSeedCriteria(new ShareRatioSeedCriteria(option->getAsDouble(PREF_SEED_RATIO), btContext));
+      }
+  if(unionCri->getSeedCriterion().size() > 0) {
+    commands.push_back(new SeedCheckCommand(CUIDCounterSingletonHolder::instance()->newID(),
+					    requestGroup,
+					    e,
+					    btContext,
+					    unionCri));
+  }
+
+  BT_RUNTIME(btContext)->setReady(true);
+  return commands;
+}

+ 14 - 12
src/DefaultFileAllocator.h → src/BtSetup.h

@@ -32,20 +32,22 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#ifndef _D_DEFAULT_FILE_ALLOCATOR_H_
-#define _D_DEFAULT_FILE_ALLOCATOR_H_
+#ifndef _D_BT_SETUP_H_
+#define _D_BT_SETUP_H_
 
-#include "FileAllocator.h"
+#include "common.h"
 
-class DefaultFileAllocator : public FileAllocator {
-public:
-  DefaultFileAllocator() {}
-
-  virtual ~DefaultFileAllocator() {}
+class RequestGroup;
+class DownloadEngine;
+class Option;
+class Command;
+extern typedef deque<Command*> Commands;
 
-  virtual void allocate(int fd, int64_t totalLength);
+class BtSetup {
+public:
+  Commands setup(RequestGroup* requestGroup,
+		 DownloadEngine* e,
+		 const Option* option);
 };
 
-typedef SharedHandle<DefaultFileAllocator> DefaultFileAllocatorHandle;
-
-#endif // _D_DEFAULT_FILE_ALLOCATOR_H_
+#endif // _D_BT_SETUP_H_

+ 17 - 15
src/ByteArrayDiskWriter.cc

@@ -38,34 +38,35 @@
 ByteArrayDiskWriter::ByteArrayDiskWriter() {
 }
 
-ByteArrayDiskWriter::~ByteArrayDiskWriter() {
-  closeFile();
-}
+ByteArrayDiskWriter::~ByteArrayDiskWriter() {}
 
-void ByteArrayDiskWriter::clear() {
+void ByteArrayDiskWriter::clear()
+{
   buf.str("");
 }
 
 void ByteArrayDiskWriter::initAndOpenFile(const string& filename,
-					  int64_t totalLength) {
+					  int64_t totalLength)
+{
   clear();
 }
 
 void ByteArrayDiskWriter::openFile(const string& filename,
-				   int64_t totalLength) {
-  initAndOpenFile(filename);
+				   int64_t totalLength)
+{
 }
 
-void ByteArrayDiskWriter::closeFile() {
-  clear();
-}
+void ByteArrayDiskWriter::closeFile()
+{}
 
 void ByteArrayDiskWriter::openExistingFile(const string& filename,
-					   int64_t totalLength) {
+					   int64_t totalLength)
+{
   openFile(filename);
 }
 
-void ByteArrayDiskWriter::writeData(const char* data, int32_t dataLength, int64_t position) {
+void ByteArrayDiskWriter::writeData(const unsigned char* data, int32_t dataLength, int64_t position)
+{
   if(size() < position) {
     buf.seekg(0, ios::end);
     for(int32_t i = size(); i < position; ++i) {
@@ -74,12 +75,13 @@ void ByteArrayDiskWriter::writeData(const char* data, int32_t dataLength, int64_
   } else {
     buf.seekg(position, ios::beg);
   }
-  buf.write(data, dataLength);
+  buf.write(reinterpret_cast<const char*>(data), dataLength);
 }
 
-int32_t ByteArrayDiskWriter::readData(char* data, int32_t len, int64_t position) {
+int32_t ByteArrayDiskWriter::readData(unsigned char* data, int32_t len, int64_t position)
+{
   buf.seekg(position, ios::beg);
-  buf.read(data, len);
+  buf.read(reinterpret_cast<char*>(data), len);
   // TODO we have to call buf.clear() here? YES
   buf.clear();
   return buf.gcount();

+ 2 - 3
src/ByteArrayDiskWriter.h

@@ -55,9 +55,8 @@ public:
 
   virtual void openExistingFile(const string& filename, int64_t totalLength = 0);
 
-  // position is ignored
-  virtual void writeData(const char* data, int32_t len, int64_t position = 0);
-  virtual int32_t readData(char* data, int32_t len, int64_t position);
+  virtual void writeData(const unsigned char* data, int32_t len, int64_t position);
+  virtual int32_t readData(unsigned char* data, int32_t len, int64_t position);
 
   // Not implemented yet
   virtual void truncate(int64_t length) {}

+ 52 - 0
src/ByteArrayDiskWriterFactory.h

@@ -0,0 +1,52 @@
+/* <!-- 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_BYTE_ARRAY_DISK_WRITER_FACTORY_H_
+#define _D_BYTE_ARRAY_DISK_WRITER_FACTORY_H_
+
+#include "DiskWriterFactory.h"
+#include "ByteArrayDiskWriter.h"
+
+class ByteArrayDiskWriterFactory:public DiskWriterFactory
+{
+public:
+  DiskWriterHandle newDiskWriter()
+  {
+    return new ByteArrayDiskWriter();
+  }
+};
+
+typedef SharedHandle<ByteArrayDiskWriterFactory> ByteArrayDiskWriterFactoryHandle;
+
+#endif // _D_BYTE_ARRAY_DISK_WRITER_FACTORY_H_

+ 9 - 21
src/CheckIntegrityCommand.cc

@@ -33,6 +33,9 @@
  */
 /* copyright --> */
 #include "CheckIntegrityCommand.h"
+#include "CheckIntegrityMan.h"
+#include "CheckIntegrityEntry.h"
+#include "RequestGroup.h"
 #include "FileAllocationEntry.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "DlAbortEx.h"
@@ -40,7 +43,7 @@
 #include "DownloadCommand.h"
 #include "prefs.h"
 
-CheckIntegrityCommand::CheckIntegrityCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const CheckIntegrityEntryHandle& entry):
+CheckIntegrityCommand::CheckIntegrityCommand(int32_t cuid, RequestGroup* requestGroup, DownloadEngine* e, const CheckIntegrityEntryHandle& entry):
   RealtimeCommand(cuid, requestGroup, e),
   _entry(entry)
 {
@@ -54,25 +57,16 @@ CheckIntegrityCommand::~CheckIntegrityCommand()
 
 bool CheckIntegrityCommand::executeInternal()
 {
+  if(_requestGroup->isHaltRequested()) {
+    return true;
+  }
   _entry->validateChunk();
   if(_entry->finished()) {
+    _entry->updatePieceStorage();
     if(_requestGroup->downloadFinished()) {
       logger->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, cuid, _requestGroup->getFilePath().c_str());
-      return true;
-    }
-    if(_requestGroup->needsFileAllocation()) {
-      FileAllocationEntryHandle entry = new FileAllocationEntry(cuid, _entry->getCurrentRequest(), _requestGroup, _entry->popNextDownloadCommand(), _requestGroup->getExistingFileLength());
-      _e->_fileAllocationMan->pushFileAllocationEntry(entry); 
     } else {
-      if(_timer.difference() <= _e->option->getAsInt(PREF_DIRECT_DOWNLOAD_TIMEOUT) &&
-	 _entry->getNextDownloadCommand()) {
-	_e->commands.push_back(_entry->popNextDownloadCommand());
-      } else {
-	Commands commands = _requestGroup->createNextCommandWithAdj(_e, -1);
-	Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, _entry->getCurrentRequest(), _requestGroup, _e);
-	commands.push_front(command);
-	_e->addCommand(commands);
-      }
+      _e->addCommand(_entry->prepareForNextAction(_e));
     }
     return true;
   } else {
@@ -84,12 +78,6 @@ bool CheckIntegrityCommand::executeInternal()
 bool CheckIntegrityCommand::handleException(Exception* e)
 {
   logger->error(MSG_FILE_VALIDATION_FAILURE, e, cuid);
-  delete e;
   logger->error(MSG_DOWNLOAD_NOT_COMPLETE, cuid, _requestGroup->getFilePath().c_str());
-  // TODO this is wrong. There may exist invalid chunk data before catching
-  // exception. Fix this.
-  // The one of the solution is having a copy of bitfield before settting its
-  // all bit to 1. If exception is thrown, then assign the copy to the bitfield.
-  _requestGroup->markPieceDone(_entry->getCurrentLength());
   return true;
 }

+ 4 - 3
src/CheckIntegrityCommand.h

@@ -36,16 +36,17 @@
 #define _D_CHECK_INTEGRITY_COMMAND_H_
 
 #include "RealtimeCommand.h"
-#include "IteratableChunkChecksumValidator.h"
-#include "CheckIntegrityEntry.h"
 #include "TimeA2.h"
 
+class CheckIntegrityEntry;
+extern typedef SharedHandle<CheckIntegrityEntry> CheckIntegrityEntryHandle;
+
 class CheckIntegrityCommand : public RealtimeCommand {
 private:
   CheckIntegrityEntryHandle _entry;
   Time _timer;
 public:
-  CheckIntegrityCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const CheckIntegrityEntryHandle& entry);
+  CheckIntegrityCommand(int32_t cuid, RequestGroup* requestGroup, DownloadEngine* e, const CheckIntegrityEntryHandle& entry);
 
   virtual ~CheckIntegrityCommand();
 

+ 43 - 12
src/CheckIntegrityEntry.cc

@@ -34,33 +34,64 @@
 /* copyright --> */
 #include "CheckIntegrityEntry.h"
 #include "DlAbortEx.h"
+#include "Command.h"
+#include "RequestGroup.h"
+#include "IteratableChunkChecksumValidator.h"
+#include "DownloadContext.h"
+#include "DownloadEngine.h"
+
+CheckIntegrityEntry::CheckIntegrityEntry(RequestGroup* requestGroup,
+					 Command* nextCommand):
+  RequestGroupEntry(requestGroup, nextCommand),
+  _validator(0)
+{}
+
+CheckIntegrityEntry::~CheckIntegrityEntry() {}
 
 void CheckIntegrityEntry::validateChunk()
 {
   _validator->validateChunk();
 }
 
-bool CheckIntegrityEntry::finished() const
+int64_t CheckIntegrityEntry::getTotalLength()
+{
+  if(_validator.isNull()) {
+    return 0;
+  } else {
+    return _validator->getTotalLength();
+  }
+}
+
+int64_t CheckIntegrityEntry::getCurrentLength()
+{
+  if(_validator.isNull()) {
+    return 0;
+  } else {
+    return _validator->getCurrentOffset();
+  }
+}
+
+bool CheckIntegrityEntry::finished()
 {
   return _validator->finished();
 }
 
-int64_t CheckIntegrityEntry::getCurrentLength() const
+bool CheckIntegrityEntry::isValidationReady()
 {
-  return _validator->getCurrentOffset();
+  DownloadContextHandle dctx = _requestGroup->getDownloadContext();
+  return dctx->getPieceHashes().size() > 0 &&
+    dctx->getPieceHashes().size() == (uint32_t)dctx->getNumPieces();
 }
 
 void CheckIntegrityEntry::initValidator()
 {
   IteratableChunkChecksumValidatorHandle validator =
-    new IteratableChunkChecksumValidator();
-  validator->setChunkChecksum(_requestGroup->getChunkChecksum());
-  validator->setDiskWriter(_requestGroup->getSegmentMan()->diskWriter);
-  validator->setBitfield(_requestGroup->getSegmentMan()->getBitfield());
-  if(!validator->canValidate()) {
-    // insufficient checksums.
-    throw new DlAbortEx("Insufficient checksums.");
-  }
-  validator->init();
+    new IteratableChunkChecksumValidator(_requestGroup->getDownloadContext(),
+					 _requestGroup->getPieceStorage());
   _validator = validator;
 }
+
+void CheckIntegrityEntry::updatePieceStorage()
+{
+  _validator->updatePieceStorage();
+}

+ 20 - 12
src/CheckIntegrityEntry.h

@@ -36,29 +36,37 @@
 #define _D_CHECK_INTEGRITY_ENTRY_H_
 
 #include "RequestGroupEntry.h"
-#include "IteratableChunkChecksumValidator.h"
 
-class CheckIntegrityEntry : public RequestGroupEntry {
+class IteratableChunkChecksumValidator;
+extern typedef SharedHandle<IteratableChunkChecksumValidator> IteratableChunkChecksumValidatorHandle;
+class Command;
+extern typedef deque<Command*> Commands;
+class DownloadEngine;
+
+class CheckIntegrityEntry : public RequestGroupEntry,
+			    public ProgressAwareEntry {
 private:
   IteratableChunkChecksumValidatorHandle _validator;
 public:
-  CheckIntegrityEntry(int cuid,
-		      const RequestHandle& currentRequest,
-		      RequestGroup* requestGroup,
-		      DownloadCommand* nextDownloadCommand = 0):
-    RequestGroupEntry(cuid, currentRequest, requestGroup, nextDownloadCommand),
-    _validator(0)
-  {}
+  CheckIntegrityEntry(RequestGroup* requestGroup, Command* nextCommand = 0);
+
+  virtual ~CheckIntegrityEntry();
+
+  virtual int64_t getTotalLength();
 
-  virtual ~CheckIntegrityEntry() {}
+  virtual int64_t getCurrentLength();
 
-  virtual int64_t getCurrentLength() const;
+  virtual bool finished();
 
-  virtual bool finished() const;
+  bool isValidationReady();
 
   void initValidator();
 
   void validateChunk();
+
+  void updatePieceStorage();
+
+  virtual Commands prepareForNextAction(DownloadEngine* e) = 0;
 };
 
 typedef SharedHandle<CheckIntegrityEntry> CheckIntegrityEntryHandle;

+ 72 - 0
src/CheckIntegrityMan.cc

@@ -0,0 +1,72 @@
+/* <!-- 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 "CheckIntegrityMan.h"
+#include "CheckIntegrityEntry.h"
+
+CheckIntegrityMan::CheckIntegrityMan() {}
+
+CheckIntegrityMan::~CheckIntegrityMan() {}
+
+void CheckIntegrityMan::addCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry)
+{
+  _checkIntegrityEntries.push_back(entry);
+}
+
+bool CheckIntegrityMan::removeCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry)
+{
+  CheckIntegrityEntries::iterator itr = find(_checkIntegrityEntries.begin(),
+					     _checkIntegrityEntries.end(),
+					     entry);
+  if(itr == _checkIntegrityEntries.end()) {
+    return false;
+  } else {
+    _checkIntegrityEntries.erase(itr);
+    return true;
+  }
+}
+
+CheckIntegrityEntryHandle CheckIntegrityMan::getFirstCheckIntegrityEntry() const
+{
+  if(_checkIntegrityEntries.empty()) {
+    return 0;
+  } else {
+    return _checkIntegrityEntries.front();
+  }
+}
+
+int32_t CheckIntegrityMan::countCheckIntegrityEntry() const
+{
+  return _checkIntegrityEntries.size();
+}

+ 12 - 29
src/CheckIntegrityMan.h

@@ -36,43 +36,26 @@
 #define _D_CHECK_INTEGRITY_MAN_H_
 
 #include "common.h"
-#include "CheckIntegrityEntry.h"
+
+class CheckIntegrityEntry;
+extern typedef SharedHandle<CheckIntegrityEntry> CheckIntegrityEntryHandle;
+extern typedef deque<CheckIntegrityEntryHandle> CheckIntegrityEntries;
 
 class CheckIntegrityMan {
 private:
   CheckIntegrityEntries _checkIntegrityEntries;
 public:
-  void addCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry)
-  {
-    _checkIntegrityEntries.push_back(entry);
-  }
+  CheckIntegrityMan();
+
+  ~CheckIntegrityMan();
+
+  void addCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry);
 
-  bool removeCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry)
-  {
-    CheckIntegrityEntries::iterator itr = find(_checkIntegrityEntries.begin(),
-					       _checkIntegrityEntries.end(),
-					       entry);
-    if(itr == _checkIntegrityEntries.end()) {
-      return false;
-    } else {
-      _checkIntegrityEntries.erase(itr);
-      return true;
-    }
-  }
+  bool removeCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry);
 
-  CheckIntegrityEntryHandle getFirstCheckIntegrityEntry() const
-  {
-    if(_checkIntegrityEntries.empty()) {
-      return 0;
-    } else {
-      return _checkIntegrityEntries.front();
-    }
-  }
+  CheckIntegrityEntryHandle getFirstCheckIntegrityEntry() const;
 
-  int32_t countCheckIntegrityEntry() const
-  {
-    return _checkIntegrityEntries.size();
-  }
+  int32_t countCheckIntegrityEntry() const;
 };
 
 typedef SharedHandle<CheckIntegrityMan> CheckIntegrityManHandle;

+ 8 - 4
src/ChecksumCommand.cc

@@ -39,9 +39,11 @@
 void ChecksumCommand::initValidator()
 {
   _validator = new IteratableChecksumValidator();
-  _validator->setChecksum(_requestGroup->getChecksum());
-  _validator->setDiskWriter(_requestGroup->getSegmentMan()->diskWriter);
-  _validator->setBitfield(_requestGroup->getSegmentMan()->getBitfield());
+  // TODO checksum will be held by DownloadContext
+  _validator->setChecksum(0);
+  //_validator->setDiskWriter(new DiskAdaptorWriter(_requestGroup->getSegmentMan()->getDiskAdaptor()));
+  // TODO we should use PieceStorage instead of BitfieldMan
+  //_validator->setBitfield(_requestGroup->getSegmentMan()->getBitfield());
   if(!_validator->canValidate()) {
     // insufficient checksums.
     throw new DlAbortEx(EX_INSUFFICIENT_CHECKSUM);
@@ -51,6 +53,9 @@ void ChecksumCommand::initValidator()
 
 bool ChecksumCommand::executeInternal()
 {
+  if(_e->isHaltRequested()) {
+    return true;
+  }
   _validator->validateChunk();
   if(_validator->finished()) {
     if(_requestGroup->downloadFinished()) {
@@ -70,7 +75,6 @@ bool ChecksumCommand::executeInternal()
 bool ChecksumCommand::handleException(Exception* e)
 {
   logger->error(MSG_FILE_VALIDATION_FAILURE, e, cuid);
-  delete e;
   logger->error(MSG_DOWNLOAD_NOT_COMPLETE, cuid, _requestGroup->getFilePath().c_str());
   // TODO We need to set bitfield back to the state when validation begun.
   // The one of the solution is having a copy of bitfield before settting its

+ 2 - 2
src/ChecksumCommand.h

@@ -47,12 +47,12 @@ public:
     RealtimeCommand(cuid, requestGroup, e),
     _validator(0)
   {
-    ++_requestGroup->numConnection;
+    _requestGroup->increaseNumCommand();
   }
 
   virtual ~ChecksumCommand()
   {
-    --_requestGroup->numConnection;
+    _requestGroup->decreaseNumCommand();
   }
 
   void initValidator();

+ 5 - 0
src/ChunkChecksum.h

@@ -79,6 +79,11 @@ public:
       return "";
     }
   }
+  
+  const Strings& getChecksums() const
+  {
+    return _checksums;
+  }
 
   int32_t getChecksumLength() const
   {

+ 2 - 0
src/ChunkChecksumValidator.cc

@@ -38,6 +38,7 @@
 
 void ChunkChecksumValidator::validate()
 {
+  /*
   if(!_validator->canValidate()) {
     // insufficient checksums.
     logger->error(MSG_INSUFFICIENT_CHECKSUM,
@@ -63,4 +64,5 @@ void ChunkChecksumValidator::validate()
   }
   fileAllocationMonitor->setCurrentValue(numChecksum);
   fileAllocationMonitor->showProgress();
+*/
 }

+ 0 - 210
src/ConsoleDownloadEngine.cc

@@ -1,210 +0,0 @@
-/* <!-- 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 "ConsoleDownloadEngine.h"
-#include "Util.h"
-#include <signal.h>
-#include <iomanip>
-
-volatile sig_atomic_t haltRequested = 0;
-
-ConsoleDownloadEngine::ConsoleDownloadEngine() {}
-
-ConsoleDownloadEngine::~ConsoleDownloadEngine() {}
-
-void ConsoleDownloadEngine::sendStatistics(int64_t currentSize, int64_t totalSize) {
-  cout << "\r                                                                             ";
-  cout << "\r";
-  if(_requestGroupMan->countRequestGroup() > 0) {
-    RequestGroupHandle firstRequestGroup = _requestGroupMan->getRequestGroup(0);
-    int32_t dlSpeed = firstRequestGroup->calculateDownloadSpeed();
-    int32_t eta = 0;
-    if(firstRequestGroup->getTotalLength() > 0 && dlSpeed > 0) {
-      eta = (firstRequestGroup->getTotalLength()-firstRequestGroup->getDownloadLength())/dlSpeed;
-    }
-
-    cout << "["
-	 << "#" << firstRequestGroup->getGID() << " "
-	 << "SIZE:"
-	 << Util::abbrevSize(firstRequestGroup->getDownloadLength())
-	 << "B"
-	 << "/"
-	 << Util::abbrevSize(firstRequestGroup->getTotalLength())
-	 << "B";
-    if(firstRequestGroup->getTotalLength() > 0) {
-      cout << "("
-	   << 100*firstRequestGroup->getDownloadLength()/firstRequestGroup->getTotalLength()
-	   << "%)";
-    }
-    cout << " "
-	 << "CN:"
-	 << firstRequestGroup->numConnection;
-    cout << " "
-	 << "SPD:"
-	 << fixed << setprecision(2) << dlSpeed/1024.0 << "KiB/s";
-    if(eta > 0) {
-      cout << " "
-	   << "ETA:"
-	   << Util::secfmt(eta);
-    }
-    cout << "]";
-    if(_requestGroupMan->countRequestGroup() > 1) {
-      cout << "("
-	   << _requestGroupMan->countRequestGroup()-1
-	   << "more...)";
-    }
-  }
-
-  if(_requestGroupMan->countRequestGroup() > 1) {
-    cout << " "
-	 << "[TOTAL SPD:"
-	 << fixed << setprecision(2) << speed/1024.0 << "KiB/s" << "]";
-  }
-
-  {
-    FileAllocationEntryHandle entry = _fileAllocationMan->getCurrentFileAllocationEntry();
-    if(!entry.isNull()) {
-      cout << " "
-	   << "[FileAlloc:"
-	   << "#" << entry->getRequestGroup()->getGID() << " "
-	   << Util::abbrevSize(entry->getCurrentLength())
-	   << "B"
-	   << "/"
-	   << Util::abbrevSize(entry->getTotalLength())
-	   << "B"
-	   << "("
-	   << 100*entry->getCurrentLength()/entry->getTotalLength()
-	   << "%)";
-      cout << "]";
-      if(_fileAllocationMan->countFileAllocationEntryInQueue() > 0) {
-	cout << "("
-	     << _fileAllocationMan->countFileAllocationEntryInQueue()
-	     << "waiting...)";
-      }
-    }
-  }
-#ifdef ENABLE_MESSAGE_DIGEST
-  {
-    CheckIntegrityEntryHandle entry = _checkIntegrityMan->getFirstCheckIntegrityEntry();
-    if(!entry.isNull()) {
-      cout << " "
-	   << "[Checksum:"
-	   << "#" << entry->getRequestGroup()->getGID() << " "
-	   << Util::abbrevSize(entry->getCurrentLength())
-	   << "B"
-	   << "/"
-	   << Util::abbrevSize(entry->getTotalLength())
-	   << "B"
-	   << "("
-	   << 100*entry->getCurrentLength()/entry->getTotalLength()
-	   << "%)";
-      cout << "]";
-      if(_checkIntegrityMan->countCheckIntegrityEntry() > 1) {
-	cout << "("
-	     << _checkIntegrityMan->countCheckIntegrityEntry()-1
-	     << "more...)";
-      }
-    }
-  }
-#endif // ENABLE_MESSAGE_DIGEST
-  cout << flush;
-}
-
-void ConsoleDownloadEngine::initStatistics() {
-  cp.reset();
-  startup.reset();
-  speed = 0;
-  psize = 0;
-  avgSpeed = 0;
-  eta = 0;
-  startupLength = 0;
-  isStartupLengthSet = false;
-}
-
-void ConsoleDownloadEngine::calculateStatistics() {
-  int64_t dlSize = _requestGroupMan->getDownloadLength();
-  if(!isStartupLengthSet && dlSize > 0) {
-    startupLength = dlSize;
-    psize = dlSize;
-    isStartupLengthSet = true;
-  }
-  int32_t elapsed = cp.difference();
-  if(elapsed >= 1) {
-    int32_t nspeed = (dlSize-psize)/elapsed;
-    if(nspeed < 0) {
-      nspeed = 0;
-    }
-    speed = (nspeed+speed)/2;
-    cp.reset();
-    psize = dlSize;
-
-    int32_t elapsedFromStartup = startup.difference();
-    if(elapsedFromStartup > 0) {
-      avgSpeed = (dlSize-startupLength)/elapsedFromStartup;
-    }
-    int64_t totalLength = _requestGroupMan->getTotalLength();
-    if(avgSpeed < 0) {
-      avgSpeed = 0;
-    } else if(avgSpeed != 0 && totalLength > 0) {
-      eta = (totalLength-dlSize)/avgSpeed;
-    }
-    
-    sendStatistics(dlSize, totalLength);
-  }
-}
-
-void ConsoleDownloadEngine::onEndOfRun() {
-  _requestGroupMan->closeFile();
-//   if(segmentMan->finished()) {
-//     segmentMan->remove();
-//   } else {
-//     segmentMan->save();
-//   }
-}
-
-void ConsoleDownloadEngine::afterEachIteration() {
-  if(haltRequested) {
-    printf(_("\nstopping application...\n"));
-    fflush(stdout);
-    _requestGroupMan->save();
-    _requestGroupMan->closeFile();
-    printf(_("done\n"));
-    exit(EXIT_SUCCESS);
-  }
-}
-
-void ConsoleDownloadEngine::fillCommand()
-{
-  addCommand(_requestGroupMan->getInitialCommands(this));
-}

+ 162 - 0
src/ConsoleStatCalc.cc

@@ -0,0 +1,162 @@
+/* <!-- 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 "ConsoleStatCalc.h"
+#include "RequestGroupMan.h"
+#include "RequestGroup.h"
+#include "FileAllocationMan.h"
+#include "FileAllocationEntry.h"
+#include "CheckIntegrityMan.h"
+#include "CheckIntegrityEntry.h"
+#include "Util.h"
+#include <iomanip>
+
+void
+ConsoleStatCalc::calculateStat(const RequestGroupManHandle& requestGroupMan,
+			       const FileAllocationManHandle& fileAllocationMan,
+			       const CheckIntegrityManHandle& checkIntegrityMan)
+{
+  if(!_cp.elapsed(1)) {
+    return;
+  }
+  _cp.reset();
+
+  cout << "\r                                                                             ";
+  cout << "\r";
+  if(requestGroupMan->countRequestGroup() > 0) {
+    RequestGroupHandle firstRequestGroup = requestGroupMan->getRequestGroup(0);
+    TransferStat stat = firstRequestGroup->calculateStat();
+    //int32_t dlSpeed = firstRequestGroup->calculateDownloadSpeed();
+    int32_t eta = 0;
+    if(firstRequestGroup->getTotalLength() > 0 && stat.getDownloadSpeed() > 0) {
+      eta = (firstRequestGroup->getTotalLength()-firstRequestGroup->getCompletedLength())/stat.getDownloadSpeed();
+    }
+
+    cout << "["
+	 << "#" << firstRequestGroup->getGID() << " "
+	 << "SIZE:"
+	 << Util::abbrevSize(firstRequestGroup->getCompletedLength())
+	 << "B"
+	 << "/"
+	 << Util::abbrevSize(firstRequestGroup->getTotalLength())
+	 << "B";
+    if(firstRequestGroup->getTotalLength() > 0) {
+      cout << "("
+	   << 100*firstRequestGroup->getCompletedLength()/firstRequestGroup->getTotalLength()
+	   << "%)";
+    }
+    cout << " "
+	 << "CN:"
+	 << firstRequestGroup->getNumConnection();
+    cout << " "
+	 << "SPD:"
+	 << fixed << setprecision(2) << stat.getDownloadSpeed()/1024.0 << "KiB/s";
+    if(stat.getSessionUploadLength() > 0) {
+      cout << " "
+	   << "UP:"
+	   << fixed << setprecision(2) << stat.getUploadSpeed()/1024.0 << "KiB/s"
+	   << "(" << Util::abbrevSize(stat.getAllTimeUploadLength()) << ")";
+    }
+    if(eta > 0) {
+      cout << " "
+	   << "ETA:"
+	   << Util::secfmt(eta);
+    }
+    cout << "]";
+    if(requestGroupMan->countRequestGroup() > 1) {
+      cout << "("
+	   << requestGroupMan->countRequestGroup()-1
+	   << "more...)";
+    }
+  }
+
+  if(requestGroupMan->countRequestGroup() > 1) {
+    TransferStat stat = requestGroupMan->calculateStat();
+    cout << " "
+	 << "[TOTAL SPD:"
+	 << fixed << setprecision(2) << stat.getDownloadSpeed()/1024.0 << "KiB/s" << "]";
+  }
+
+  {
+    FileAllocationEntryHandle entry = fileAllocationMan->getCurrentFileAllocationEntry();
+    if(!entry.isNull()) {
+      cout << " "
+	   << "[FileAlloc:"
+	   << "#" << entry->getRequestGroup()->getGID() << " "
+	   << Util::abbrevSize(entry->getCurrentLength())
+	   << "B"
+	   << "/"
+	   << Util::abbrevSize(entry->getTotalLength())
+	   << "B"
+	   << "(";
+      if(entry->getTotalLength() > 0) {
+	cout << 100*entry->getCurrentLength()/entry->getTotalLength();
+      } else {
+	cout << "--";
+      }
+      cout << "%)"
+	   << "]";
+      if(fileAllocationMan->countFileAllocationEntryInQueue() > 0) {
+	cout << "("
+	     << fileAllocationMan->countFileAllocationEntryInQueue()
+	     << "waiting...)";
+      }
+    }
+  }
+#ifdef ENABLE_MESSAGE_DIGEST
+  {
+    CheckIntegrityEntryHandle entry = checkIntegrityMan->getFirstCheckIntegrityEntry();
+    if(!entry.isNull()) {
+      cout << " "
+	   << "[Checksum:"
+	   << "#" << entry->getRequestGroup()->getGID() << " "
+	   << Util::abbrevSize(entry->getCurrentLength())
+	   << "B"
+	   << "/"
+	   << Util::abbrevSize(entry->getTotalLength())
+	   << "B"
+	   << "("
+	   << 100*entry->getCurrentLength()/entry->getTotalLength()
+	   << "%)";
+      cout << "]";
+      if(checkIntegrityMan->countCheckIntegrityEntry() > 1) {
+	cout << "("
+	     << checkIntegrityMan->countCheckIntegrityEntry()-1
+	     << "more...)";
+      }
+    }
+  }
+#endif // ENABLE_MESSAGE_DIGEST
+  cout << flush;
+}

+ 14 - 10
src/TrackerSegmentManFactory.h → src/ConsoleStatCalc.h

@@ -32,20 +32,24 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#ifndef _D_TRACKER_SEGMENT_MAN_FACTORY_H_
-#define _D_TRACKER_SEGMENT_MAN_FACTORY_H_
+#ifndef _D_CONSOLE_STAT_CALC_H_
+#define _D_CONSOLE_STAT_CALC_H_
 
-#include "AbstractSegmentManFactory.h"
+#include "StatCalc.h"
+#include "TimeA2.h"
 
-class TrackerSegmentManFactory : public AbstractSegmentManFactory {
+class ConsoleStatCalc:public StatCalc
+{
+private:
+  Time _cp;
 public:
-  TrackerSegmentManFactory(const Option* option):AbstractSegmentManFactory(option) {}
+  virtual ~ConsoleStatCalc() {}
 
-  virtual ~TrackerSegmentManFactory() {}
-
-  virtual SegmentManHandle createNewInstance();
+  virtual void calculateStat(const RequestGroupManHandle& requestGroupMan,
+			     const FileAllocationManHandle& fileAllocationMan,
+			     const CheckIntegrityManHandle& checkIntegrityMan);
 };
 
-typedef SharedHandle<TrackerSegmentManFactory> TrackerSegmentManFactoryHandle;
+typedef SharedHandle<ConsoleStatCalc> ConsoleStatCalcHandle;
 
-#endif // _D_TRACKER_SEGMENT_MAN_FACTORY_H_
+#endif // _D_CONSOLE_STAT_CALC_H_

+ 8 - 3
src/CopyDiskAdaptor.cc

@@ -36,13 +36,17 @@
 #include "Util.h"
 #include "message.h"
 
-void CopyDiskAdaptor::onDownloadComplete() {
+void CopyDiskAdaptor::onDownloadComplete()
+  throw(DlAbortEx*)
+{
   closeFile();
   fixFilename();
   openFile();
 }
 
-void CopyDiskAdaptor::fixFilename() {
+void CopyDiskAdaptor::fixFilename()
+  throw(DlAbortEx*)
+{
   int64_t offset = 0;
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
@@ -59,6 +63,7 @@ void CopyDiskAdaptor::fixFilename() {
   }
 }
 
-string CopyDiskAdaptor::getFilePath() {
+string CopyDiskAdaptor::getFilePath()
+{
   return storeDir+"/"+tempFilename;
 }

+ 3 - 2
src/CopyDiskAdaptor.h

@@ -36,13 +36,14 @@
 #define _D_COPY_DISK_ADAPTOR_H_
 
 #include "AbstractSingleDiskAdaptor.h"
+#include "DlAbortEx.h"
 
 class CopyDiskAdaptor : public AbstractSingleDiskAdaptor {
 private:
   string tempFilename;
   string topDir;
 
-  void fixFilename();
+  void fixFilename() throw(DlAbortEx*);
 public:
   CopyDiskAdaptor() {}
 
@@ -50,7 +51,7 @@ public:
 
   virtual string getFilePath();
 
-  virtual void onDownloadComplete();
+  virtual void onDownloadComplete() throw(DlAbortEx*);
 
   // tempFilename is relative to storeDir
   void setTempFilename(const string& tempFilename) {

+ 7 - 1
src/DefaultBtContext.cc

@@ -42,9 +42,10 @@
 #include "Util.h"
 #include "MessageDigestHelper.h"
 #include "a2netcompat.h"
+#include "AnnounceTier.h"
 #include <libgen.h>
 
-DefaultBtContext::DefaultBtContext():_peerIdPrefix("-aria2-") {}
+DefaultBtContext::DefaultBtContext():_peerIdPrefix("-aria2-"), _ownerRequestGroup(0) {}
 
 DefaultBtContext::~DefaultBtContext() {}
 
@@ -248,6 +249,11 @@ int32_t DefaultBtContext::getNumPieces() const {
   return numPieces;
 }
 
+string DefaultBtContext::getActualBasePath() const
+{
+  return _dir+"/"+name;
+}
+
 Integers DefaultBtContext::computeFastSet(const string& ipaddr, int32_t fastSetSize)
 {
   Integers fastSet;

+ 19 - 1
src/DefaultBtContext.h

@@ -59,6 +59,8 @@ private:
   string _peerIdPrefix;
   AnnounceTiers announceTiers;
 
+  RequestGroup* _ownerRequestGroup;
+
   void clear();
   void extractPieceHash(const unsigned char* hashData,
 			int32_t hashDataLength,
@@ -90,6 +92,11 @@ private:
 
   virtual FileEntries getFileEntries() const;
 
+  virtual string getPieceHashAlgo() const
+  {
+    return "sha1";
+  }
+
   virtual AnnounceTiers getAnnounceTiers() const;
 
   virtual void load(const string& torrentFile);
@@ -100,6 +107,8 @@ private:
   
   virtual int32_t getNumPieces() const;
 
+  virtual string getActualBasePath() const;
+
   virtual const unsigned char* getPeerId() {
     if(peerId == "") {
       peerId = generatePeerId();
@@ -109,6 +118,11 @@ private:
 
   virtual Integers computeFastSet(const string& ipaddr, int32_t fastSetSize);
 
+  virtual RequestGroup* getOwnerRequestGroup()
+  {
+    return _ownerRequestGroup;
+  }
+
   string generatePeerId() const;
 
   void setPeerIdPrefix(const string& peerIdPrefix)
@@ -126,7 +140,11 @@ private:
   {
     this->numPieces = numPieces;
   }
-      
+   
+  void setOwnerRequestGroup(RequestGroup* owner)
+  {
+    _ownerRequestGroup = owner;
+  }
 };
 
 typedef SharedHandle<DefaultBtContext> DefaultBtContextHandle;

+ 198 - 93
src/DefaultBtProgressInfoFile.cc

@@ -33,6 +33,9 @@
  */
 /* copyright --> */
 #include "DefaultBtProgressInfoFile.h"
+#include "DownloadContext.h"
+#include "PieceStorage.h"
+#include "Option.h"
 #include "BtRegistry.h"
 #include "LogFactory.h"
 #include "prefs.h"
@@ -41,143 +44,245 @@
 #include "File.h"
 #include "Util.h"
 #include "a2io.h"
+#include <fstream>
 #include <errno.h>
 
-DefaultBtProgressInfoFile::DefaultBtProgressInfoFile(const BtContextHandle& btContext,
+DefaultBtProgressInfoFile::DefaultBtProgressInfoFile(const DownloadContextHandle& dctx,
+						     const PieceStorageHandle& pieceStorage,
 						     const Option* option):
-  btContext(btContext),
-  option(option),
-  pieceStorage(PIECE_STORAGE(btContext)),
-  btRuntime(BT_RUNTIME(btContext)),
-  peerStorage(PEER_STORAGE(btContext))
+  _dctx(dctx),
+  _pieceStorage(pieceStorage),
+  _option(option),
+  _logger(LogFactory::getInstance())
 {
-  logger = LogFactory::getInstance();
-  string storeDir = option->get(PREF_DIR);
-  filename = storeDir+"/"+btContext->getName()+".aria2";
+  _filename = _dctx->getActualBasePath()+".aria2";
 }
 
 DefaultBtProgressInfoFile::~DefaultBtProgressInfoFile() {}
 
+bool DefaultBtProgressInfoFile::isTorrentDownload()
+{
+  return !BtContextHandle(_dctx).isNull();
+}
+
 void DefaultBtProgressInfoFile::save() {
-  logger->info(MSG_SAVING_SEGMENT_FILE, filename.c_str());
-  string filenameTemp = filename+"__temp";
-  FILE* file = openFile(filenameTemp, "wb");
+  _logger->info(MSG_SAVING_SEGMENT_FILE, _filename.c_str());
+  string filenameTemp = _filename+"__temp";
+  ofstream o(filenameTemp.c_str(), ios::out|ios::binary);
+  o.exceptions(ios::failbit);
   try {
-    if(fwrite(btContext->getInfoHash(),
-	      btContext->getInfoHashLength(), 1, file) < 1) {
-      throw string("writeError:info hash");
+    bool torrentDownload = isTorrentDownload();
+    // file version: 16 bits
+    // value: '0'
+    int16_t version = 0;
+    o.write(reinterpret_cast<const char*>(&version), sizeof(int16_t));
+    // extension: 32 bits
+    // If this is BitTorrent download, then 0x00000001
+    // Otherwise, 0x00000000
+    char extension[4];
+    memset(extension, 0, sizeof(extension));
+    if(torrentDownload) {
+      extension[3] = 1;
     }
-    if(fwrite(pieceStorage->getBitfield(),
-	      pieceStorage->getBitfieldLength(), 1, file) < 1) {
-      throw string("writeError:bitfield");
+    o.write(reinterpret_cast<const char*>(&extension), sizeof(extension));
+    if(torrentDownload) {
+      // infoHashLength:
+      // length: 32 bits
+      BtContextHandle btContext = _dctx;
+      int32_t infoHashLength = btContext->getInfoHashLength();
+      o.write(reinterpret_cast<const char*>(&infoHashLength), sizeof(int32_t));
+      // infoHash:
+      o.write(reinterpret_cast<const char*>(btContext->getInfoHash()),
+	      btContext->getInfoHashLength());
+    } else {
+      // infoHashLength:
+      // length: 32 bits
+      int32_t infoHashLength = 0;
+      o.write(reinterpret_cast<const char*>(&infoHashLength), sizeof(int32_t));
     }
-    TransferStat stat = peerStorage->calculateStat();
-    int64_t allTimeDownloadLength = pieceStorage->getCompletedLength();
-    if(fwrite(&allTimeDownloadLength,
-	      sizeof(allTimeDownloadLength), 1, file) < 1) {
-      throw string("writeError:download length");
+    // pieceLength: 32 bits
+    int32_t pieceLength = _dctx->getPieceLength();
+    o.write(reinterpret_cast<const char*>(&pieceLength), sizeof(int32_t));
+    // totalLength: 64 bits
+    int64_t totalLength = _dctx->getTotalLength();
+    o.write(reinterpret_cast<const char*>(&totalLength), sizeof(int64_t));
+    // uploadLength: 64 bits
+    int64_t uploadLength = 0;
+    if(torrentDownload) {
+      BtContextHandle btContext = _dctx;
+      TransferStat stat = PEER_STORAGE(btContext)->calculateStat();
+      uploadLength = stat.getAllTimeUploadLength();
     }
-    int64_t allTimeUploadLength =
-      btRuntime->getUploadLengthAtStartup()+
-      stat.getSessionUploadLength();
-    if(fwrite(&allTimeUploadLength,
-	      sizeof(allTimeUploadLength), 1, file) < 1) {
-      throw string("writeError:upload length");
+    o.write(reinterpret_cast<const char*>(&uploadLength), sizeof(int64_t));
+    // bitfieldLength: 32 bits
+    int32_t bitfieldLength = _pieceStorage->getBitfieldLength();
+    o.write(reinterpret_cast<const char*>(&bitfieldLength), sizeof(int32_t));
+    // bitfield
+    o.write(reinterpret_cast<const char*>(_pieceStorage->getBitfield()), _pieceStorage->getBitfieldLength());
+    // the number of in-flight piece: 32 bits
+    // TODO implement this
+    int32_t numInFlightPiece = _pieceStorage->countInFlightPiece();
+    o.write(reinterpret_cast<const char*>(&numInFlightPiece), sizeof(int32_t));
+    Pieces inFlightPieces = _pieceStorage->getInFlightPieces();
+    for(Pieces::const_iterator itr = inFlightPieces.begin();
+	itr != inFlightPieces.end(); ++itr) {
+      int32_t index = (*itr)->getIndex();
+      o.write(reinterpret_cast<const char*>(&index), sizeof(int32_t));
+      int32_t length = (*itr)->getLength();
+      o.write(reinterpret_cast<const char*>(&length), sizeof(int32_t));
+      int32_t bitfieldLength = (*itr)->getBitfieldLength();
+      o.write(reinterpret_cast<const char*>(&bitfieldLength), sizeof(int32_t));
+      o.write(reinterpret_cast<const char*>((*itr)->getBitfield()), bitfieldLength);
     }
-    fclose(file);
-    logger->info(MSG_SAVED_SEGMENT_FILE);
-  } catch(string ex) {
-    fclose(file);
+
+    o.close();
+    _logger->info(MSG_SAVED_SEGMENT_FILE);
+  } catch(ios::failure const& exception) {
+    // TODO ios::failure doesn't give us the reasons of failure...
     throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
-			filename.c_str(), strerror(errno));
+			_filename.c_str(), strerror(errno));
   }
-
-  if(rename(filenameTemp.c_str(), filename.c_str()) == -1) {
+  if(rename(filenameTemp.c_str(), _filename.c_str()) == -1) {
     throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
-			filename.c_str(), strerror(errno));
+			_filename.c_str(), strerror(errno));
   }
 }
 
-void DefaultBtProgressInfoFile::load() {
-  logger->info(MSG_LOADING_SEGMENT_FILE, filename.c_str());
-  FILE* file = openFile(filename, "r+b");
+void DefaultBtProgressInfoFile::load() 
+{
+  _logger->info(MSG_LOADING_SEGMENT_FILE, _filename.c_str());
+  ifstream in(_filename.c_str(), ios::in|ios::binary);
+  in.exceptions(ios::failbit);
   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");
+    unsigned char version[2];
+    in.read((char*)version, sizeof(version));
+    if(string("0000") != Util::toHex(version, sizeof(version))) {
+      throw new DlAbortEx("Unsupported ctrl file version: %s",
+			  Util::toHex(version, sizeof(version)).c_str());
+    }
+    unsigned char extension[4];
+    in.read((char*)extension, sizeof(extension));
+
+    bool infoHashCheckEnabled = false;
+    if(extension[3]&1 && isTorrentDownload()) {
+      infoHashCheckEnabled = true;
+      _logger->debug("InfoHash checking enabled.");
+    }
+
+    int32_t infoHashLength;
+    in.read(reinterpret_cast<char*>(&infoHashLength), sizeof(infoHashLength));
+    if(infoHashLength < 0 || infoHashLength == 0 && infoHashCheckEnabled) {
+      throw new DlAbortEx("Invalid info hash length: %d", infoHashLength);
+    }
+    if(infoHashLength > 0) {
+      savedInfoHash = new unsigned char[infoHashLength];
+      in.read(reinterpret_cast<char*>(savedInfoHash), infoHashLength);
+      BtContextHandle btContext = _dctx;
+      if(infoHashCheckEnabled &&
+	 Util::toHex(savedInfoHash, infoHashLength) != btContext->getInfoHashAsString()) {
+	throw new DlAbortEx("info hash mismatch. expected: %s, actual: %s",
+			    btContext->getInfoHashAsString().c_str(),
+			    Util::toHex(savedInfoHash, infoHashLength).c_str());
+      }
+      delete [] savedInfoHash;
+      savedInfoHash = 0;
     }
-    if(Util::toHex(savedInfoHash, btContext->getInfoHashLength()) != 
-       btContext->getInfoHashAsString()) {
-      throw string("infoHashMismatch");
+
+    // TODO implement the conversion mechanism between different piece length.
+    int32_t pieceLength;
+    in.read(reinterpret_cast<char*>(&pieceLength), sizeof(pieceLength));
+    if(pieceLength != _dctx->getPieceLength()) {
+      throw new DlAbortEx("piece length mismatch. expected: %d, actual: %d",
+			  _dctx->getPieceLength(), pieceLength);
     }
-    if(fread(savedBitfield, pieceStorage->getBitfieldLength(), 1, file) < 1) {
-      throw string("readError");
+
+    int64_t totalLength;
+    in.read(reinterpret_cast<char*>(&totalLength), sizeof(totalLength));
+    if(totalLength != _dctx->getTotalLength()) {
+      throw new DlAbortEx("total length mismatch. expected: %s, actual: %s",
+			  Util::llitos(_dctx->getTotalLength()).c_str(),
+			  Util::llitos(totalLength).c_str());
     }
-    pieceStorage->setBitfield(savedBitfield,
-			      pieceStorage->getBitfieldLength());
-    // allTimeDownloadLength exists for only a compatibility reason.
-    int64_t allTimeDownloadLength;
-    if(fread(&allTimeDownloadLength,
-	     sizeof(allTimeDownloadLength), 1, file) < 1) {
-      throw string("readError");
+    int64_t uploadLength;
+    in.read(reinterpret_cast<char*>(&uploadLength), sizeof(uploadLength));
+    if(isTorrentDownload()) {
+      BT_RUNTIME(BtContextHandle(_dctx))->setUploadLengthAtStartup(uploadLength);
     }
-    int64_t allTimeUploadLength;
-    if(fread(&allTimeUploadLength,
-	     sizeof(allTimeUploadLength), 1, file) < 1) {
-      throw string("readError");
+
+    // TODO implement the conversion mechanism between different piece length.
+    int32_t bitfieldLength;
+    in.read(reinterpret_cast<char*>(&bitfieldLength), sizeof(bitfieldLength));
+    if(_pieceStorage->getBitfieldLength() != bitfieldLength) {
+      throw new DlAbortEx("bitfield length mismatch. expected: %d, actual: %d",
+			  _pieceStorage->getBitfieldLength(),
+			  bitfieldLength);
     }
-    btRuntime->setUploadLengthAtStartup(allTimeUploadLength);
+
+    // TODO implement the conversion mechanism between different piece length.
+    savedBitfield = new unsigned char[bitfieldLength];
+    in.read(reinterpret_cast<char*>(savedBitfield), bitfieldLength);
+    _pieceStorage->setBitfield(savedBitfield, bitfieldLength);
     delete [] savedBitfield;
     savedBitfield = 0;
-    delete [] savedInfoHash;
-    savedInfoHash = 0;
-    fclose(file);
-  } catch(string ex) {
-    if(savedBitfield) {
+
+    int32_t numInFlightPiece;
+    in.read(reinterpret_cast<char*>(&numInFlightPiece), sizeof(numInFlightPiece));
+    
+    Pieces inFlightPieces;
+    while(numInFlightPiece--) {
+      int32_t index;
+      in.read(reinterpret_cast<char*>(&index), sizeof(index));
+      if(!(0 <= index && index < _dctx->getNumPieces())) {
+	throw new DlAbortEx("piece index out of range: %d", index);
+      }
+      int32_t length;
+      in.read(reinterpret_cast<char*>(&length), sizeof(length));
+      if(!(0 < length && length <=_dctx->getPieceLength())) {
+	throw new DlAbortEx("piece length out of range: %d", length);
+      }
+      PieceHandle piece = new Piece(index, length);
+      int32_t bitfieldLength;
+      in.read(reinterpret_cast<char*>(&bitfieldLength), sizeof(bitfieldLength));
+      if(piece->getBitfieldLength() != bitfieldLength) {
+	throw new DlAbortEx("piece bitfield length mismatch. expected: %d actual: %d",
+			    piece->getBitfieldLength(), bitfieldLength);
+      }
+      savedBitfield = new unsigned char[bitfieldLength];
+      in.read(reinterpret_cast<char*>(savedBitfield), bitfieldLength);
+      piece->setBitfield(savedBitfield, bitfieldLength);
       delete [] savedBitfield;
+      savedBitfield = 0;
+      
+      inFlightPieces.push_back(piece);
     }
-    if(savedInfoHash) {
-      delete [] savedInfoHash;
-    }
-    fclose(file);
-    if(ex == "infoHashMismatch") {
-      throw new DlAbortEx(EX_INFOHASH_MISMATCH_IN_SEGFILE);
-    } else {
-      throw new DlAbortEx(EX_SEGMENT_FILE_READ,
-			  filename.c_str(), strerror(errno));
-    }
-  }
-  logger->info(MSG_LOADED_SEGMENT_FILE);
+    _pieceStorage->addInFlightPiece(inFlightPieces);
+
+    _logger->info(MSG_LOADED_SEGMENT_FILE);
+  } catch(ios::failure const& exception) {
+    delete [] savedBitfield;
+    delete [] savedInfoHash;
+    // TODO ios::failure doesn't give us the reasons of failure...
+    throw new DlAbortEx(EX_SEGMENT_FILE_READ,
+			_filename.c_str(), strerror(errno));
+  } 
 }
 
 void DefaultBtProgressInfoFile::removeFile() {
   if(exists()) {
-    File f(filename);
+    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);
+  File f(_filename);
   if(f.isFile()) {
-    logger->info(MSG_SEGMENT_FILE_EXISTS, filename.c_str());
+    _logger->info(MSG_SEGMENT_FILE_EXISTS, _filename.c_str());
     return true;
   } else {
-    logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, filename.c_str());
+    _logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, _filename.c_str());
     return false;
   }
 }

+ 19 - 35
src/DefaultBtProgressInfoFile.h

@@ -36,49 +36,33 @@
 #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 DownloadContext;
+extern typedef SharedHandle<DownloadContext> DownloadContextHandle;
+class PieceStorage;
+extern typedef SharedHandle<PieceStorage> PieceStorageHandle;
+class Logger;
+class Option;
 
 class DefaultBtProgressInfoFile : public BtProgressInfoFile {
 private:
-  BtContextHandle btContext;
-  const Option* option;
-  Logger* logger;
-  PieceStorageHandle pieceStorage;
-  BtRuntimeHandle btRuntime;
-  PeerStorageHandle peerStorage;
-  string filename;
+  DownloadContextHandle _dctx;
+  PieceStorageHandle _pieceStorage;
+  const Option* _option;
+  const Logger* _logger;
+  string _filename;
+
+  bool isTorrentDownload();
 
-  FILE* openFile(const string& filename, const string& mode) const;
 public:
-  DefaultBtProgressInfoFile(const BtContextHandle& btContext,
+  DefaultBtProgressInfoFile(const DownloadContextHandle& btContext,
+			    const PieceStorageHandle& pieceStorage,
 			    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 ~DefaultBtProgressInfoFile();
 
+  virtual string getFilename() { return _filename; }
+  
   virtual bool exists();
 
   virtual void save();

+ 1 - 35
src/DefaultDiskWriter.cc

@@ -33,10 +33,7 @@
  */
 /* copyright --> */
 #include "DefaultDiskWriter.h"
-#include "DlAbortEx.h"
 #include "message.h"
-#include "DefaultFileAllocator.h"
-#include "GlowFileAllocator.h"
 #include "prefs.h"
 #include "Util.h"
 #include <errno.h>
@@ -48,38 +45,7 @@ DefaultDiskWriter::~DefaultDiskWriter() {}
 
 void DefaultDiskWriter::initAndOpenFile(const string& filename,
 					int64_t totalLength)
+  throw(DlAbortEx*)
 {
   createFile(filename);
-  try {
-    if(totalLength > 0) {
-      if(fileAllocator.isNull()) {
-	ftruncate(fd, 0);
-      } else {
-	logger->notice(MSG_ALLOCATING_FILE,
-		       filename.c_str(),
-		       Util::ullitos(totalLength).c_str());
-	fileAllocator->allocate(fd, totalLength);
-      }
-    }
-  } catch(RecoverableException *e) {
-    throw new DlAbortEx(e, EX_FILE_WRITE, filename.c_str(), strerror(errno));
-  }
-}
-
-DefaultDiskWriter* DefaultDiskWriter::createNewDiskWriter(const Option* option)
-{
-  DefaultDiskWriter* diskWriter = new DefaultDiskWriter();
-  if(option->get(PREF_FILE_ALLOCATION) == V_PREALLOC) {
-    DefaultFileAllocatorHandle allocator = new DefaultFileAllocator();
-    allocator->setFileAllocationMonitor(FileAllocationMonitorFactory::getFactory()->createNewMonitor());
-    diskWriter->setFileAllocator(allocator);
-
-    GlowFileAllocatorHandle glowAllocator = new GlowFileAllocator();
-    glowAllocator->setFileAllocationMonitor(FileAllocationMonitorFactory::getFactory()->createNewMonitor());
-    diskWriter->setGlowFileAllocator(glowAllocator);
-  } else {
-    diskWriter->setFileAllocator(0);
-    diskWriter->setGlowFileAllocator(0);
-  }
-  return diskWriter;
 }

+ 2 - 3
src/DefaultDiskWriter.h

@@ -37,6 +37,7 @@
 
 #include "AbstractDiskWriter.h"
 #include "Option.h"
+#include "DlAbortEx.h"
 
 class DefaultDiskWriter:public AbstractDiskWriter {
 public:
@@ -45,9 +46,7 @@ public:
   virtual ~DefaultDiskWriter();
 
   virtual void initAndOpenFile(const string& filename,
-			       int64_t totalLength = 0);
-
-  static DefaultDiskWriter* createNewDiskWriter(const Option* option);
+			       int64_t totalLength = 0) throw(DlAbortEx*);
 };
 
 typedef SharedHandle<DefaultDiskWriter> DefaultDiskWriterHandle;

+ 52 - 0
src/DefaultDiskWriterFactory.h

@@ -0,0 +1,52 @@
+/* <!-- 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_DISK_WRITER_FACTORY_H_
+#define _D_DEFAULT_DISK_WRITER_FACTORY_H_
+
+#include "DiskWriterFactory.h"
+#include "DefaultDiskWriter.h"
+
+class DefaultDiskWriterFactory:public DiskWriterFactory
+{
+public:
+  DiskWriterHandle newDiskWriter()
+  {
+    return new DefaultDiskWriter();
+  }
+};
+
+typedef SharedHandle<DefaultDiskWriterFactory> DefaultDiskWriterFactoryHandle;
+
+#endif // _D_DEFAULT_DISK_WRITER_FACTORY_H_

+ 2 - 0
src/DefaultPeerStorage.cc

@@ -192,6 +192,8 @@ TransferStat DefaultPeerStorage::calculateStat() {
   TransferStat stat = calStat.getTransferStat();
   stat.sessionDownloadLength += removedPeerSessionDownloadLength;
   stat.sessionUploadLength += removedPeerSessionUploadLength;
+  stat.setAllTimeUploadLength(btRuntime->getUploadLengthAtStartup()+
+			      stat.getSessionUploadLength());
   return stat;
 }
 

+ 157 - 83
src/DefaultPieceStorage.cc

@@ -33,29 +33,31 @@
  */
 /* copyright --> */
 #include "DefaultPieceStorage.h"
+#include "DownloadContext.h"
+#include "Piece.h"
+#include "Peer.h"
 #include "LogFactory.h"
 #include "prefs.h"
 #include "DirectDiskAdaptor.h"
 #include "MultiDiskAdaptor.h"
 #include "CopyDiskAdaptor.h"
-#include "DefaultDiskWriter.h"
-#include "DlAbortEx.h"
+#include "DiskWriter.h"
 #include "BitfieldManFactory.h"
-#include "FileAllocationMonitor.h"
-#include "DiskAdaptorWriter.h"
-#include "ChunkChecksumValidator.h"
 #include "message.h"
+#include "DefaultDiskWriterFactory.h"
+#include "DlAbortEx.h"
 
-DefaultPieceStorage::DefaultPieceStorage(BtContextHandle btContext, const Option* option):
-  btContext(btContext),
+DefaultPieceStorage::DefaultPieceStorage(const DownloadContextHandle& downloadContext, const Option* option):
+  downloadContext(downloadContext),
   diskAdaptor(0),
+  _diskWriterFactory(new DefaultDiskWriterFactory()),
   endGamePieceNum(END_GAME_PIECE_NUM),
   option(option)
 {
   bitfieldMan =
     BitfieldManFactory::getFactoryInstance()->
-    createBitfieldMan(btContext->getPieceLength(),
-		      btContext->getTotalLength());
+    createBitfieldMan(downloadContext->getPieceLength(),
+		      downloadContext->getTotalLength());
   logger = LogFactory::getInstance();
 }
 
@@ -63,16 +65,19 @@ DefaultPieceStorage::~DefaultPieceStorage() {
   delete bitfieldMan;
 }
 
-bool DefaultPieceStorage::hasMissingPiece(const PeerHandle& peer) {
+bool DefaultPieceStorage::hasMissingPiece(const PeerHandle& peer)
+{
   return bitfieldMan->hasMissingPiece(peer->getBitfield(),
 				      peer->getBitfieldLength());
 }
 
-bool DefaultPieceStorage::isEndGame() {
+bool DefaultPieceStorage::isEndGame()
+{
   return bitfieldMan->countMissingBlock() <= endGamePieceNum;
 }
 
-int32_t DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer) {
+int32_t DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer)
+{
   int32_t index = -1;
   if(isEndGame()) {
     index = bitfieldMan->getMissingIndex(peer->getBitfield(),
@@ -84,7 +89,8 @@ int32_t DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer) {
   return index;
 }
 
-PieceHandle DefaultPieceStorage::checkOutPiece(int32_t index) {
+PieceHandle DefaultPieceStorage::checkOutPiece(int32_t index)
+{
   if(index == -1) {
     return 0;
   }
@@ -104,7 +110,8 @@ PieceHandle DefaultPieceStorage::checkOutPiece(int32_t index) {
  * Newly instantiated piece is not added to usedPieces.
  * Because it is waste of memory and there is no chance to use them later.
  */
-PieceHandle DefaultPieceStorage::getPiece(int32_t index) {
+PieceHandle DefaultPieceStorage::getPiece(int32_t index)
+{
   if(0 <= index && index <= bitfieldMan->getMaxIndex()) {
     PieceHandle piece = findUsedPiece(index);
     if(piece.isNull()) {
@@ -119,7 +126,8 @@ PieceHandle DefaultPieceStorage::getPiece(int32_t index) {
   }
 }
 
-void DefaultPieceStorage::addUsedPiece(const PieceHandle& piece) {
+void DefaultPieceStorage::addUsedPiece(const PieceHandle& piece)
+{
   usedPieces.push_back(piece);
 }
 
@@ -134,7 +142,8 @@ public:
   }
 };
 
-PieceHandle DefaultPieceStorage::findUsedPiece(int32_t index) const {
+PieceHandle DefaultPieceStorage::findUsedPiece(int32_t index) const
+{
   Pieces::const_iterator itr = find_if(usedPieces.begin(),
 				       usedPieces.end(),
 				       FindPiece(index));
@@ -145,12 +154,14 @@ PieceHandle DefaultPieceStorage::findUsedPiece(int32_t index) const {
   }
 }
 
-PieceHandle DefaultPieceStorage::getMissingPiece(const PeerHandle& peer) {
+PieceHandle DefaultPieceStorage::getMissingPiece(const PeerHandle& peer)
+{
   int32_t index = getMissingPieceIndex(peer);
   return checkOutPiece(index);
 }
 
-int32_t DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer) {
+int32_t DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer)
+{
   int32_t index = -1;
   if(peer->isFastExtensionEnabled() && peer->countFastSet() > 0) {
     BitfieldMan tempBitfield(bitfieldMan->getBlockLength(),
@@ -172,12 +183,28 @@ int32_t DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer) {
   return index;
 }
 
-PieceHandle DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer) {
+PieceHandle DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer)
+{
   int32_t index = getMissingFastPieceIndex(peer);
   return checkOutPiece(index);
 }
 
-void DefaultPieceStorage::deleteUsedPiece(const PieceHandle& piece) {
+PieceHandle DefaultPieceStorage::getMissingPiece()
+{
+  return checkOutPiece(bitfieldMan->getSparseMissingUnusedIndex());
+}
+
+PieceHandle DefaultPieceStorage::getMissingPiece(int32_t index)
+{
+  if(hasPiece(index) || isPieceUsed(index)) {
+    return 0;
+  } else {
+    return checkOutPiece(index);
+  }
+}
+
+void DefaultPieceStorage::deleteUsedPiece(const PieceHandle& piece)
+{
   if(piece.isNull()) {
     return;
   }
@@ -187,7 +214,8 @@ void DefaultPieceStorage::deleteUsedPiece(const PieceHandle& piece) {
   }
 }
 
-void DefaultPieceStorage::reduceUsedPieces(int32_t delMax) {
+void DefaultPieceStorage::reduceUsedPieces(int32_t delMax)
+{
   int32_t toDelete = usedPieces.size()-delMax;
   if(toDelete <= 0) {
     return;
@@ -204,7 +232,8 @@ void DefaultPieceStorage::reduceUsedPieces(int32_t delMax) {
 }
 
 int32_t DefaultPieceStorage::deleteUsedPiecesByFillRate(int32_t fillRate,
-							   int32_t toDelete) {
+							int32_t toDelete)
+{
   int32_t deleted = 0;
   for(Pieces::iterator itr = usedPieces.begin();
       itr != usedPieces.end() && deleted < toDelete;) {
@@ -224,7 +253,8 @@ int32_t DefaultPieceStorage::deleteUsedPiecesByFillRate(int32_t fillRate,
   return deleted;
 }
 
-void DefaultPieceStorage::completePiece(const PieceHandle& piece) {
+void DefaultPieceStorage::completePiece(const PieceHandle& piece)
+{
   if(piece.isNull()) {
     return;
   }
@@ -250,17 +280,20 @@ void DefaultPieceStorage::completePiece(const PieceHandle& piece) {
   }
 }
 
-bool DefaultPieceStorage::isSelectiveDownloadingMode() {
+bool DefaultPieceStorage::isSelectiveDownloadingMode()
+{
   return bitfieldMan->isFilterEnabled();
 }
 
-void DefaultPieceStorage::finishSelectiveDownloadingMode() {
+void DefaultPieceStorage::finishSelectiveDownloadingMode()
+{
   bitfieldMan->clearFilter();
   diskAdaptor->addAllDownloadEntry();
 }
 
 // not unittested
-void DefaultPieceStorage::cancelPiece(const PieceHandle& piece) {
+void DefaultPieceStorage::cancelPiece(const PieceHandle& piece)
+{
   if(piece.isNull()) {
     return;
   }
@@ -272,29 +305,40 @@ void DefaultPieceStorage::cancelPiece(const PieceHandle& piece) {
   }
 }
 
-bool DefaultPieceStorage::hasPiece(int32_t index) {
+bool DefaultPieceStorage::hasPiece(int32_t index)
+{
   return bitfieldMan->isBitSet(index);
 }
 
-int64_t DefaultPieceStorage::getTotalLength() {
+bool DefaultPieceStorage::isPieceUsed(int32_t index)
+{
+  return bitfieldMan->isUseBitSet(index);
+}
+
+int64_t DefaultPieceStorage::getTotalLength()
+{
   return bitfieldMan->getTotalLength();
 }
 
-int64_t DefaultPieceStorage::getFilteredTotalLength() {
+int64_t DefaultPieceStorage::getFilteredTotalLength()
+{
   return bitfieldMan->getFilteredTotalLength();
 }
 
-int64_t DefaultPieceStorage::getCompletedLength() {
+int64_t DefaultPieceStorage::getCompletedLength()
+{
   return bitfieldMan->getCompletedLength();
 }
 
-int64_t DefaultPieceStorage::getFilteredCompletedLength() {
+int64_t DefaultPieceStorage::getFilteredCompletedLength()
+{
   return bitfieldMan->getFilteredCompletedLength();
 }
 
 // not unittested
-void DefaultPieceStorage::setFileFilter(const Strings& filePaths) {
-  if(btContext->getFileMode() != BtContext::MULTI || filePaths.empty()) {
+void DefaultPieceStorage::setFileFilter(const Strings& filePaths)
+{
+  if(downloadContext->getFileMode() != DownloadContext::MULTI || filePaths.empty()) {
     return;
   }
   diskAdaptor->removeAllDownloadEntry();
@@ -309,7 +353,8 @@ void DefaultPieceStorage::setFileFilter(const Strings& filePaths) {
   bitfieldMan->enableFilter();
 }
 
-void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) {
+void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes)
+{
   Strings filePaths;
   const FileEntries& entries = diskAdaptor->getFileEntries();
   for(int32_t i = 0; i < (int32_t)entries.size(); i++) {
@@ -322,66 +367,77 @@ void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) {
 }
 
 // not unittested
-void DefaultPieceStorage::clearFileFilter() {
+void DefaultPieceStorage::clearFileFilter()
+{
   bitfieldMan->clearFilter();
   diskAdaptor->addAllDownloadEntry();
 }
 
 // not unittested
-bool DefaultPieceStorage::downloadFinished() {
+bool DefaultPieceStorage::downloadFinished()
+{
   return bitfieldMan->isFilteredAllBitSet();
 }
 
 // not unittested
-bool DefaultPieceStorage::allDownloadFinished() {
+bool DefaultPieceStorage::allDownloadFinished()
+{
   return bitfieldMan->isAllBitSet();
 }
 
 // not unittested
-void DefaultPieceStorage::initStorage() {
-  if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
-    if(btContext->getFileMode() == BtContext::SINGLE) {
-      DefaultDiskWriterHandle writer = DefaultDiskWriter::createNewDiskWriter(option);
-      DirectDiskAdaptorHandle directDiskAdaptor = new DirectDiskAdaptor();
-      directDiskAdaptor->setDiskWriter(writer);
-      directDiskAdaptor->setTotalLength(btContext->getTotalLength());
-      this->diskAdaptor = directDiskAdaptor;
-    } else {
+void DefaultPieceStorage::initStorage()
+{
+  if(downloadContext->getFileMode() == DownloadContext::SINGLE) {
+    logger->debug("Instantiating DirectDiskAdaptor");
+    DiskWriterHandle writer = _diskWriterFactory->newDiskWriter();
+    DirectDiskAdaptorHandle directDiskAdaptor = new DirectDiskAdaptor();
+    directDiskAdaptor->setDiskWriter(writer);
+    directDiskAdaptor->setTotalLength(downloadContext->getTotalLength());
+    this->diskAdaptor = directDiskAdaptor;
+  } else {
+    // file mode == DownloadContext::MULTI
+    if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
+      logger->debug("Instantiating MultiDiskAdaptor");
       MultiDiskAdaptorHandle multiDiskAdaptor = new MultiDiskAdaptor();
-      multiDiskAdaptor->setPieceLength(btContext->getPieceLength());
-      multiDiskAdaptor->setTopDir(btContext->getName());
+      multiDiskAdaptor->setPieceLength(downloadContext->getPieceLength());
+      multiDiskAdaptor->setTopDir(downloadContext->getName());
       multiDiskAdaptor->setOption(option);
       this->diskAdaptor = multiDiskAdaptor;
+    } else {
+      logger->debug("Instantiating CopyDiskAdaptor");
+      DiskWriterHandle writer = _diskWriterFactory->newDiskWriter();
+      CopyDiskAdaptorHandle copyDiskAdaptor = new CopyDiskAdaptor();
+      copyDiskAdaptor->setDiskWriter(writer);
+      copyDiskAdaptor->setTempFilename(downloadContext->getName()+".a2tmp");
+      copyDiskAdaptor->setTotalLength(downloadContext->getTotalLength());
+      if(downloadContext->getFileMode() == DownloadContext::MULTI) {
+	copyDiskAdaptor->setTopDir(downloadContext->getName());
+      }
+      this->diskAdaptor = copyDiskAdaptor;
     }
-  } else {
-    DefaultDiskWriterHandle writer = DefaultDiskWriter::createNewDiskWriter(option);
-    CopyDiskAdaptorHandle copyDiskAdaptor = new CopyDiskAdaptor();
-    copyDiskAdaptor->setDiskWriter(writer);
-    copyDiskAdaptor->setTempFilename(btContext->getName()+".a2tmp");
-    copyDiskAdaptor->setTotalLength(btContext->getTotalLength());
-    if(btContext->getFileMode() == BtContext::MULTI) {
-      copyDiskAdaptor->setTopDir(btContext->getName());
-    }
-    this->diskAdaptor = copyDiskAdaptor;
-  }
-  string storeDir = option->get(PREF_DIR);
-  if(storeDir == "") {
-    storeDir = ".";
   }
+  string storeDir = downloadContext->getDir();//option->get(PREF_DIR);
+//   if(storeDir == "") {
+//     storeDir = ".";
+//   }
   diskAdaptor->setStoreDir(storeDir);
-  diskAdaptor->setFileEntries(btContext->getFileEntries());
+  diskAdaptor->setFileEntries(downloadContext->getFileEntries());
 }
 
 void DefaultPieceStorage::setBitfield(const unsigned char* bitfield,
-				      int32_t bitfieldLength) {
+				      int32_t bitfieldLength)
+{
   bitfieldMan->setBitfield(bitfield, bitfieldLength);
 }
   
-int32_t DefaultPieceStorage::getBitfieldLength() {
+int32_t DefaultPieceStorage::getBitfieldLength()
+{
   return bitfieldMan->getBitfieldLength();
 }
 
-const unsigned char* DefaultPieceStorage::getBitfield() {
+const unsigned char* DefaultPieceStorage::getBitfield()
+{
   return bitfieldMan->getBitfield();
 }
 
@@ -389,17 +445,20 @@ DiskAdaptorHandle DefaultPieceStorage::getDiskAdaptor() {
   return diskAdaptor;
 }
 
-int32_t DefaultPieceStorage::getPieceLength(int32_t index) {
+int32_t DefaultPieceStorage::getPieceLength(int32_t index)
+{
   return bitfieldMan->getBlockLength(index);
 }
 
-void DefaultPieceStorage::advertisePiece(int32_t cuid, int32_t index) {
+void DefaultPieceStorage::advertisePiece(int32_t cuid, int32_t index)
+{
   HaveEntry entry(cuid, index);
   haves.push_front(entry);
 }
 
 Integers DefaultPieceStorage::getAdvertisedPieceIndexes(int32_t myCuid,
-							const Time& lastCheckTime) {
+							const Time& lastCheckTime)
+{
   Integers indexes;
   for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) {
     const Haves::value_type& have = *itr;
@@ -430,7 +489,8 @@ public:
   }
 };
   
-void DefaultPieceStorage::removeAdvertisedPiece(int32_t elapsed) {
+void DefaultPieceStorage::removeAdvertisedPiece(int32_t elapsed)
+{
   Haves::iterator itr =
     find_if(haves.begin(), haves.end(), FindElapsedHave(elapsed));
   if(itr != haves.end()) {
@@ -444,19 +504,33 @@ void DefaultPieceStorage::markAllPiecesDone()
   bitfieldMan->setAllBit();
 }
 
-void DefaultPieceStorage::checkIntegrity()
+void DefaultPieceStorage::markPiecesDone(int64_t length)
 {
-  logger->notice(MSG_VALIDATING_FILE,
-		 diskAdaptor->getFilePath().c_str());
-  ChunkChecksumHandle chunkChecksum = new ChunkChecksum("sha1",
-							btContext->getPieceHashes(),
-							btContext->getPieceLength());
-  IteratableChunkChecksumValidatorHandle iv = new IteratableChunkChecksumValidator();
-  iv->setDiskWriter(new DiskAdaptorWriter(diskAdaptor));
-  iv->setBitfield(bitfieldMan);
-  iv->setChunkChecksum(chunkChecksum);
+  // TODO implement this
+  abort();
+}
 
-  ChunkChecksumValidator v(iv);
-  v.setFileAllocationMonitor(FileAllocationMonitorFactory::getFactory()->createNewMonitor());
-  v.validate();
+void DefaultPieceStorage::markPieceMissing(int32_t index)
+{
+  bitfieldMan->unsetBit(index);
+}
+
+void DefaultPieceStorage::addInFlightPiece(const Pieces& pieces)
+{
+  copy(pieces.begin(), pieces.end(), back_inserter(usedPieces));
+}
+
+int32_t DefaultPieceStorage::countInFlightPiece()
+{
+  return usedPieces.size();
+}
+
+Pieces DefaultPieceStorage::getInFlightPieces()
+{
+  return usedPieces;
+}
+
+void DefaultPieceStorage::setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory)
+{
+  _diskWriterFactory = diskWriterFactory;
 }

+ 30 - 11
src/DefaultPieceStorage.h

@@ -36,13 +36,15 @@
 #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"
-#include "FileAllocator.h"
+
+class DownloadContext;
+extern typedef SharedHandle<DownloadContext> DownloadContextHandle;
+class BitfieldMan;
+class Logger;
+class Option;
+extern typedef deque<PieceHandle> Pieces;
+class DiskWriterFactory;
+extern typedef SharedHandle<DiskWriterFactory> DiskWriterFactoryHandle;
 
 #define END_GAME_PIECE_NUM 20
 
@@ -67,15 +69,15 @@ typedef deque<HaveEntry> Haves;
 
 class DefaultPieceStorage : public PieceStorage {
 private:
-  BtContextHandle btContext;
+  DownloadContextHandle downloadContext;
   BitfieldMan* bitfieldMan;
   DiskAdaptorHandle diskAdaptor;
+  DiskWriterFactoryHandle _diskWriterFactory;
   Pieces usedPieces;
   int32_t endGamePieceNum;
   Logger* logger;
   const Option* option;
   Haves haves;
-  FileAllocatorHandle createFileAllocator();
 
   int32_t getMissingPieceIndex(const PeerHandle& peer);
   int32_t getMissingFastPieceIndex(const PeerHandle& peer);
@@ -85,7 +87,7 @@ private:
   void deleteUsedPiece(const PieceHandle& piece);
   PieceHandle findUsedPiece(int32_t index) const;
 public:
-  DefaultPieceStorage(BtContextHandle btContext, const Option* option);
+  DefaultPieceStorage(const DownloadContextHandle& downloadContext, const Option* option);
   virtual ~DefaultPieceStorage();
 
   virtual bool hasMissingPiece(const PeerHandle& peer);
@@ -94,6 +96,10 @@ public:
 
   virtual PieceHandle getMissingFastPiece(const PeerHandle& peer);
 
+  virtual PieceHandle getMissingPiece();
+
+  virtual PieceHandle getMissingPiece(int32_t index);
+
   virtual PieceHandle getPiece(int32_t index);
 
   virtual void completePiece(const PieceHandle& piece);
@@ -102,6 +108,8 @@ public:
 
   virtual bool hasPiece(int32_t index);
 
+  virtual bool isPieceUsed(int32_t index);
+
   virtual int64_t getTotalLength();
 
   virtual int64_t getFilteredTotalLength();
@@ -156,13 +164,24 @@ public:
 
   virtual void markAllPiecesDone();
 
-  virtual void checkIntegrity();
+  virtual void markPiecesDone(int64_t length);
+
+  virtual void markPieceMissing(int32_t index);
+
+  virtual void addInFlightPiece(const Pieces& pieces);
+
+  virtual int32_t countInFlightPiece();
+
+  virtual Pieces getInFlightPieces();
 
   /**
    * This method is made private for test purpose only.
    */
   void addUsedPiece(const PieceHandle& piece);
 
+  void setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory);
 };
 
+typedef SharedHandle<DefaultPieceStorage> DefaultPieceStorageHandle;
+
 #endif // _D_DEFAULT_PIECE_STORAGE_H_

+ 6 - 5
src/DefaultSegmentManFactory.cc

@@ -36,13 +36,14 @@
 #include "prefs.h"
 #include "DefaultDiskWriter.h"
 
-SegmentManHandle DefaultSegmentManFactory::createNewInstance()
+SegmentManHandle DefaultSegmentManFactory::createNewInstance(const DownloadContextHandle& dctx,
+							     const PieceStorageHandle& ps)
 {
-  SegmentManHandle segmentMan = new SegmentMan();
-  segmentMan->diskWriter = new DefaultDiskWriter();
-  segmentMan->dir = _option->get(PREF_DIR);
+  SegmentManHandle segmentMan = new SegmentMan(_option, dctx, ps);
+  //segmentMan->diskWriter = new DefaultDiskWriter();
+  //segmentMan->dir = _option->get(PREF_DIR);
   // TODO disable this in multi-simultaneous download mode.
   //segmentMan->ufilename = _option->get(PREF_OUT);
-  segmentMan->option = _option;
+  //segmentMan->option = _option;
   return segmentMan;
 }

+ 2 - 1
src/DefaultSegmentManFactory.h

@@ -43,7 +43,8 @@ public:
 
   virtual ~DefaultSegmentManFactory() {}
 
-  virtual SegmentManHandle createNewInstance();
+  virtual SegmentManHandle createNewInstance(const DownloadContextHandle& dc,
+					     const PieceStorageHandle& ps);
 };
 
 typedef SharedHandle<DefaultSegmentManFactory> DefaultSegmentManFactoryHandle;

+ 14 - 2
src/FileAllocationMonitor.cc → src/Dependency.h

@@ -32,6 +32,18 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#include "FileAllocationMonitor.h"
+#ifndef _D_DEPENDENCY_H_
+#define _D_DEPENDENCY_H_
 
-FileAllocationMonitorFactoryHandle FileAllocationMonitorFactory::factory = 0;
+#include "common.h"
+
+class Dependency {
+public:
+  virtual ~Dependency() {}
+
+  virtual bool resolve() = 0;
+};
+
+typedef SharedHandle<Dependency> DependencyHandle;
+
+#endif // _D_DEPENDENCY_H_

+ 5 - 2
src/DirectDiskAdaptor.cc

@@ -34,11 +34,14 @@
 /* copyright --> */
 #include "DirectDiskAdaptor.h"
 
-string DirectDiskAdaptor::getFilePath() {
+string DirectDiskAdaptor::getFilePath()
+{
   return storeDir+"/"+fileEntries.front()->getPath();
 }
 
-void DirectDiskAdaptor::onDownloadComplete() {
+void DirectDiskAdaptor::onDownloadComplete()
+  throw(DlAbortEx*)
+{
   closeFile();
   openFile();
 }

+ 2 - 1
src/DirectDiskAdaptor.h

@@ -36,6 +36,7 @@
 #define _D_DIRECT_DISK_ADAPTOR_H_
 
 #include "AbstractSingleDiskAdaptor.h"
+#include "DlAbortEx.h"
 
 class DirectDiskAdaptor : public AbstractSingleDiskAdaptor {
 public:
@@ -44,7 +45,7 @@ public:
 
   virtual string getFilePath();
 
-  virtual void onDownloadComplete();
+  virtual void onDownloadComplete() throw(DlAbortEx*);
 };
 
 typedef SharedHandle<DirectDiskAdaptor> DirectDiskAdaptorHandle;

+ 11 - 6
src/DiskAdaptor.cc

@@ -33,7 +33,6 @@
  */
 /* copyright --> */
 #include "DiskAdaptor.h"
-#include "DlAbortEx.h"
 #include "LogFactory.h"
 #include "message.h"
 
@@ -41,7 +40,9 @@ DiskAdaptor::DiskAdaptor():logger(LogFactory::getInstance()) {}
 
 DiskAdaptor::~DiskAdaptor() {}
 
-FileEntryHandle DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const {
+FileEntryHandle DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const
+  throw(DlAbortEx*)
+{
   for(FileEntries::const_iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
     if((*itr)->getPath() == fileEntryPath) {
@@ -51,7 +52,8 @@ FileEntryHandle DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) c
   throw new DlAbortEx(EX_NO_SUCH_FILE_ENTRY, fileEntryPath.c_str());
 }
 
-bool DiskAdaptor::addDownloadEntry(const string& fileEntryPath) {
+bool DiskAdaptor::addDownloadEntry(const string& fileEntryPath)
+{
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
     if((*itr)->getPath() == fileEntryPath) {
@@ -62,7 +64,8 @@ bool DiskAdaptor::addDownloadEntry(const string& fileEntryPath) {
   return false;
 }
 
-bool DiskAdaptor::addDownloadEntry(int index) {
+bool DiskAdaptor::addDownloadEntry(int index)
+{
   if(fileEntries.size() <= (unsigned int)index) {
     return false;
   }
@@ -70,14 +73,16 @@ bool DiskAdaptor::addDownloadEntry(int index) {
   return true;
 }
 
-void DiskAdaptor::addAllDownloadEntry() {
+void DiskAdaptor::addAllDownloadEntry()
+{
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
     (*itr)->setRequested(true);
   }
 }
 
-void DiskAdaptor::removeAllDownloadEntry() {
+void DiskAdaptor::removeAllDownloadEntry()
+{
   for(FileEntries::iterator itr = fileEntries.begin();
       itr != fileEntries.end(); itr++) {
     (*itr)->setRequested(false);

+ 11 - 7
src/DiskAdaptor.h

@@ -35,11 +35,13 @@
 #ifndef _D_DISK_ADAPTOR_H_
 #define _D_DISK_ADAPTOR_H_
 
-#include "common.h"
+#include "BinaryStream.h"
 #include "FileEntry.h"
 #include "Logger.h"
+#include "FileAllocationIterator.h"
+#include "DlAbortEx.h"
 
-class DiskAdaptor {
+class DiskAdaptor:public BinaryStream {
 protected:
   string storeDir;
   FileEntries fileEntries;
@@ -56,10 +58,6 @@ public:
 
   virtual void initAndOpenFile() = 0;
 
-  virtual void writeData(const unsigned char* data, int32_t len, int64_t offset) = 0;
-
-  virtual int32_t readData(unsigned char* data, int32_t len, int64_t offset) = 0;
-
   virtual void onDownloadComplete() = 0;  
 
   virtual bool fileExists() = 0;
@@ -68,11 +66,15 @@ public:
 
   virtual int64_t size() const = 0;
 
+  // optional behavior
+  virtual void truncate(int64_t length) {}
+
   void setFileEntries(const FileEntries& fileEntries) {
     this->fileEntries = fileEntries;
   }
 
-  FileEntryHandle getFileEntryFromPath(const string& fileEntryPath) const;
+  FileEntryHandle
+  getFileEntryFromPath(const string& fileEntryPath) const throw(DlAbortEx*);
 
   const FileEntries& getFileEntries() const { return fileEntries; }
 
@@ -87,6 +89,8 @@ public:
   void setStoreDir(const string& storeDir) { this->storeDir = storeDir; }
 
   const string& getStoreDir() const { return this->storeDir; }
+
+  virtual FileAllocationIteratorHandle fileAllocationIterator() = 0;
 };
 
 typedef SharedHandle<DiskAdaptor> DiskAdaptorHandle;

+ 5 - 25
src/DiskWriter.h

@@ -35,15 +35,14 @@
 #ifndef _D_DISK_WRITER_H_
 #define _D_DISK_WRITER_H_
 
-#include "common.h"
-
-using namespace std;
+#include "BinaryStream.h"
+#include "DlAbortEx.h"
 
 /**
  * Interface for writing to a binary stream of bytes.
  *
  */
-class DiskWriter {
+class DiskWriter:public BinaryStream {
 public:
   virtual ~DiskWriter() {}
   /**
@@ -51,13 +50,14 @@ public:
    * If the file exists, then it is truncated to 0 length.
    * @param filename the file name to be opened.
    */
-  virtual void initAndOpenFile(const string& filename, int64_t totalLength = 0) = 0;
+  virtual void initAndOpenFile(const string& filename, int64_t totalLength = 0)  = 0;
   
   virtual void openFile(const string& filename, int64_t totalLength = 0) = 0;
 
   /**
    * Closes this output stream.
    */
+  // TODO we have to examine the return value of close()
   virtual void closeFile() = 0;
 
   /**
@@ -68,26 +68,6 @@ public:
    */
   virtual void openExistingFile(const string& filename, int64_t totalLength = 0) = 0;
 
-  /*
-   * Writes len bytes from data to this binary stream at offset position.
-   * In case where offset position is not concerned(just write data
-   * sequencially, for example), those subclasses can ignore the offset value.
-   *
-   * @param data the data
-   * @param len the number of bytes to write
-   * @param position the offset of this binary stream
-   */
-  virtual void writeData(const char* data, int32_t len, int64_t position = 0) = 0;
-  virtual void writeData(const unsigned char* data, int32_t len, int64_t position = 0)
-  {
-    writeData((const char*)data, len, position);
-  }
-
-  virtual int32_t readData(char* data, int32_t len, int64_t position) = 0;
-  virtual int32_t readData(unsigned char* data, int32_t len, int64_t position) {
-    return readData((char*)data, len, position);
-  }
-
   virtual void truncate(int64_t length) = 0;
 
   // Returns file length

+ 9 - 10
src/GlowFileAllocator.h → src/DiskWriterFactory.h

@@ -32,20 +32,19 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#ifndef _D_GLOW_FILE_ALLOCATOR_H_
-#define _D_GLOW_FILE_ALLOCATOR_H_
+#ifndef _D_DISK_WRITER_FACTORY_H_
+#define _D_DISK_WRITER_FACTORY_H_
 
-#include "FileAllocator.h"
+#include "common.h"
+#include "DiskWriter.h"
 
-class GlowFileAllocator : public FileAllocator {
+class DiskWriterFactory {
 public:
-  GlowFileAllocator() {}
+  virtual ~DiskWriterFactory() {}
 
-  virtual ~GlowFileAllocator() {}
-
-  virtual void allocate(int fd, int64_t totalLength);
+  virtual DiskWriterHandle newDiskWriter() = 0;
 };
 
-typedef SharedHandle<GlowFileAllocator> GlowFileAllocatorHandle;
+typedef SharedHandle<DiskWriterFactory> DiskWriterFactoryHandle;
 
-#endif // _D_GLOW_FILE_ALLOCATOR_H_
+#endif // _D_DISK_WRITER_FACTORY_H_

+ 45 - 16
src/DownloadCommand.cc

@@ -33,16 +33,20 @@
  */
 /* copyright --> */
 #include "DownloadCommand.h"
+#include "SegmentMan.h"
+#include "PeerStat.h"
+#include "TransferEncoding.h"
+#include "DownloadContext.h"
 #include "Util.h"
 #include "DlRetryEx.h"
 #include "DlAbortEx.h"
-#include "HttpInitiateConnectionCommand.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "message.h"
 #include "prefs.h"
-#ifdef ENABLE_MESSAGE_DIGEST
-# include "ChecksumCommand.h"
-#endif // ENABLE_MESSAGE_DIGEST
+#include "DiskAdaptor.h"
+#include "Segment.h"
+#include "PieceStorage.h"
+#include "Option.h"
 #include <stdlib.h>
 
 DownloadCommand::DownloadCommand(int cuid,
@@ -80,17 +84,23 @@ bool DownloadCommand::executeInternal() {
   socket->readData(buf, bufSize);
 
   if(transferDecoder.isNull()) {
-    _requestGroup->getSegmentMan()->diskWriter->writeData(buf, bufSize,
-							  segment->getPositionToWrite());
-    segment->writtenLength += bufSize;
+    _requestGroup->getPieceStorage()->getDiskAdaptor()->writeData((const unsigned char*)buf, bufSize,
+								segment->getPositionToWrite());
+    //logger->debug("bufSize = %d, posToWrite = %lld", bufSize, segment->getPositionToWrite());
+    segment->updateWrittenLength(bufSize);
+    //logger->debug("overflow length = %d, next posToWrite = %lld", segment->getOverflowLength(), segment->getPositionToWrite());
+    //logger->debug("%s", Util::toHex(segment->getPiece()->getBitfield(),
+    //segment->getPiece()->getBitfieldLength()).c_str());
+    //segment->writtenLength += bufSize;
     peerStat->updateDownloadLength(bufSize);
   } else {
     int32_t infbufSize = 16*1024;
     char infbuf[infbufSize];
     transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
-    _requestGroup->getSegmentMan()->diskWriter->writeData(infbuf, infbufSize,
-							  segment->getPositionToWrite());
-    segment->writtenLength += infbufSize;
+    _requestGroup->getPieceStorage()->getDiskAdaptor()->writeData((const unsigned char*)infbuf, infbufSize,
+								segment->getPositionToWrite());
+    segment->updateWrittenLength(infbufSize);
+    //segment->writtenLength += infbufSize;
     peerStat->updateDownloadLength(infbufSize);
   }
   // calculate downloading speed
@@ -103,7 +113,7 @@ bool DownloadCommand::executeInternal() {
 			  req->getHost().c_str());
     }
   }
-  if(_requestGroup->getSegmentMan()->totalSize != 0 && bufSize == 0) {
+  if(_requestGroup->getTotalLength() != 0 && bufSize == 0) {
     throw new DlRetryEx(EX_GOT_EOF);
   }
   if(!transferDecoder.isNull() && transferDecoder->finished()
@@ -112,11 +122,22 @@ bool DownloadCommand::executeInternal() {
     if(!transferDecoder.isNull()) transferDecoder->end();
     logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid);
     _requestGroup->getSegmentMan()->completeSegment(cuid, segment);
+    // TODO According to the current plan, checksum is held by DownloadContext.
+#ifdef ENABLE_MESSAGE_DIGEST
+    if(e->option->get(PREF_REALTIME_CHUNK_CHECKSUM) == V_TRUE) {
+      string pieceHash = _requestGroup->getDownloadContext()->getPieceHash(segment->getIndex());
+      if(!pieceHash.empty()) {
+	_requestGroup->getSegmentMan()->validatePieceHash(segment, pieceHash);
+      }
+    }
+#endif // ENABLE_MESSAGE_DIGEST
+    /*
 #ifdef ENABLE_MESSAGE_DIGEST
     if(e->option->get(PREF_REALTIME_CHUNK_CHECKSUM) == V_TRUE) {
       _requestGroup->getSegmentMan()->tryChunkChecksumValidation(segment, _requestGroup->getChunkChecksum());
     }
 #endif // ENABLE_MESSAGE_DIGEST
+    */
     // this unit is going to download another segment.
     return prepareForNextSegment();
   } else {
@@ -127,7 +148,9 @@ bool DownloadCommand::executeInternal() {
 }
 
 bool DownloadCommand::prepareForNextSegment() {
-  if(_requestGroup->getSegmentMan()->finished()) {
+  if(_requestGroup->downloadFinished()) {
+    // TODO According to the current plan, checksum is held by DownloadContext.
+    /*
 #ifdef ENABLE_MESSAGE_DIGEST
     if(!_requestGroup->getChecksum().isNull() &&
        !_requestGroup->getChecksum()->isEmpty()) {
@@ -136,6 +159,7 @@ bool DownloadCommand::prepareForNextSegment() {
       e->commands.push_back(command);
     }
 #endif // ENABLE_MESSAGE_DIGEST
+    */
     return true;
   } else {
     // Merge segment with next segment, if segment.index+1 == nextSegment.index
@@ -143,15 +167,15 @@ bool DownloadCommand::prepareForNextSegment() {
     while(1) {
       SegmentHandle nextSegment =
 	_requestGroup->getSegmentMan()->getSegment(cuid,
-						   tempSegment->index+1);
+						   tempSegment->getIndex()+1);
       if(nextSegment.isNull()) {
 	break;
       } else {
-	if(nextSegment->writtenLength > 0) {
+	if(nextSegment->getWrittenLength() > 0) {
 	  return prepareForRetry(0);
 	}
-	nextSegment->writtenLength =
-	  tempSegment->writtenLength-tempSegment->length;
+	nextSegment->updateWrittenLength(tempSegment->getOverflowLength());
+	//tempSegment->writtenLength-tempSegment->length;
 	if(nextSegment->complete()) {
 	  _requestGroup->getSegmentMan()->completeSegment(cuid, nextSegment);
 	  tempSegment = nextSegment;
@@ -165,3 +189,8 @@ bool DownloadCommand::prepareForNextSegment() {
     return prepareForRetry(0);
   }
 }
+
+void DownloadCommand::setTransferDecoder(const TransferEncodingHandle& transferDecoder)
+{
+  this->transferDecoder = transferDecoder;
+}

+ 5 - 8
src/DownloadCommand.h

@@ -36,11 +36,11 @@
 #define _D_DOWNLOAD_COMMAND_H_
 
 #include "AbstractCommand.h"
-#include "TransferEncoding.h"
-#include "TimeA2.h"
-#include "PeerStat.h"
 
-using namespace std;
+class TransferEncoding;
+extern typedef SharedHandle<TransferEncoding> TransferEncodingHandle;
+class PeerStat;
+extern typedef SharedHandle<PeerStat> PeerStatHandle;
 
 class DownloadCommand : public AbstractCommand {
 private:
@@ -62,10 +62,7 @@ public:
 		  const SocketHandle& s);
   virtual ~DownloadCommand();
 
-  void setTransferDecoder(const TransferEncodingHandle& transferDecoder)
-  {
-    this->transferDecoder = transferDecoder;
-  }
+  void setTransferDecoder(const TransferEncodingHandle& transferDecoder);
 
   void setMaxDownloadSpeedLimit(int32_t maxDownloadSpeedLimit) {
     this->maxDownloadSpeedLimit = maxDownloadSpeedLimit;

+ 99 - 0
src/DownloadContext.h

@@ -0,0 +1,99 @@
+/* <!-- 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_DOWNLOAD_CONTEXT_H_
+#define _D_DOWNLOAD_CONTEXT_H_
+
+#include "common.h"
+#include "FileEntry.h"
+
+class DownloadContext
+{
+protected:
+  string _dir;
+
+public:
+  DownloadContext():_dir(".") {}
+
+  virtual ~DownloadContext() {}
+
+
+  enum FILE_MODE {
+    SINGLE,
+    MULTI
+  };
+
+  virtual string getPieceHash(int32_t index) const = 0;
+  
+  virtual const Strings& getPieceHashes() const = 0;
+
+  virtual int64_t getTotalLength() const = 0;
+
+  virtual FILE_MODE getFileMode() const = 0;
+
+  virtual FileEntries getFileEntries() const = 0;
+
+  virtual string getName() const = 0;
+  
+  virtual int32_t getPieceLength() const = 0;
+
+  virtual int32_t getNumPieces() const = 0;
+
+  virtual string getPieceHashAlgo() const = 0;
+
+  /**
+   * Returns an actual file path.
+   * If this contains a single file entry, then returns its file path,
+   * for example, "/tmp/downloads/aria2.txt"
+   * If this contains multiple file entries(i,e /tmp/downloads/aria2.txt,
+   * /tmp/downloads/aria2.bin), then returns its base dir path,
+   * for example, "/tmp/downloads"
+   */
+  virtual string getActualBasePath() const = 0;
+
+  string getDir() const
+  {
+    return _dir;
+  }
+
+  void setDir(const string& dir)
+  {
+    _dir = dir;
+  }
+
+};
+
+typedef SharedHandle<DownloadContext> DownloadContextHandle;
+
+#endif // _D_DOWNLOAD_CONTEXT_H_

+ 75 - 2
src/DownloadEngine.cc

@@ -33,6 +33,15 @@
  */
 /* copyright --> */
 #include "DownloadEngine.h"
+#include "Socket.h"
+#include "NameResolver.h"
+#include "StatCalc.h"
+#include "RequestGroup.h"
+#include "RequestGroupMan.h"
+#include "FileAllocationMan.h"
+#ifdef ENABLE_MESSAGE_DIGEST
+#include "CheckIntegrityMan.h"
+#endif // ENABLE_MESSAGE_DIGEST
 #include "Util.h"
 #include "LogFactory.h"
 #include "TimeA2.h"
@@ -41,11 +50,38 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <signal.h>
 #include <algorithm>
 
-using namespace std;
+volatile sig_atomic_t globalHaltRequested;
+
+SocketEntry::SocketEntry(const SocketHandle& socket,
+			 Command* command,
+			 TYPE type):
+  socket(socket), command(command), type(type) {}
+
+bool SocketEntry::operator==(const SocketEntry& entry)
+{
+  return socket == entry.socket &&
+    command == entry.command &&
+    type == entry.type;
+}
+
+#ifdef ENABLE_ASYNC_DNS
+NameResolverEntry::NameResolverEntry(const NameResolverHandle& nameResolver,
+					     Command* command):
+  nameResolver(nameResolver), command(command) {}
+
+bool NameResolverEntry::operator==(const NameResolverEntry& entry)
+{
+  return nameResolver == entry.nameResolver &&
+    command == entry.command;
+}
+#endif // ENABLE_ASYNC_DNS
 
 DownloadEngine::DownloadEngine():logger(LogFactory::getInstance()),
+				 _statCalc(0),
+				 _haltRequested(false),
 				 noWait(false),
 				 _requestGroupMan(0),
 				 _fileAllocationMan(0)
@@ -83,7 +119,6 @@ void DownloadEngine::executeCommand(Command::STATUS statusFilter)
 }
 
 void DownloadEngine::run() {
-  initStatistics();
   Time cp;
   cp.setTimeInSec(0);
   Commands activeCommands;
@@ -232,6 +267,38 @@ bool DownloadEngine::deleteSocketForWriteCheck(const SocketHandle& socket,
   return deleteSocket(entry);
 }
 
+void DownloadEngine::calculateStatistics()
+{
+  if(!_statCalc.isNull()) {
+    _statCalc->calculateStat(_requestGroupMan, _fileAllocationMan, _checkIntegrityMan);
+  }
+}
+
+void DownloadEngine::onEndOfRun()
+{
+  _requestGroupMan->closeFile();
+  _requestGroupMan->save();
+}
+
+void DownloadEngine::afterEachIteration()
+{
+  if(globalHaltRequested) {
+    globalHaltRequested = false;
+    _haltRequested = true;
+    _requestGroupMan->halt();
+  }
+}
+
+void DownloadEngine::fillCommand()
+{
+  addCommand(_requestGroupMan->getInitialCommands(this));
+}
+
+void DownloadEngine::setStatCalc(const StatCalcHandle& statCalc)
+{
+  _statCalc = statCalc;
+}
+
 #ifdef ENABLE_ASYNC_DNS
 bool DownloadEngine::addNameResolverCheck(const NameResolverHandle& resolver,
 					  Command* command) {
@@ -262,4 +329,10 @@ bool DownloadEngine::deleteNameResolverCheck(const NameResolverHandle& resolver,
     return true;
   }
 }
+
+void DownloadEngine::addCommand(const Commands& commands)
+{
+  this->commands.insert(this->commands.end(), commands.begin(), commands.end());
+}
+
 #endif // ENABLE_ASYNC_DNS

+ 48 - 35
src/DownloadEngine.h

@@ -35,21 +35,27 @@
 #ifndef _D_DOWNLOAD_ENGINE_H_
 #define _D_DOWNLOAD_ENGINE_H_
 
-#include "Command.h"
-#include "Socket.h"
-#include "SegmentMan.h"
 #include "common.h"
-#include "Logger.h"
-#include "Option.h"
-#include "NameResolver.h"
-#include "RequestGroupMan.h"
-#include "FileAllocationMan.h"
+#include "Command.h"
+
+class SocketCore;
+extern typedef SharedHandle<SocketCore> SocketHandle;
+extern typedef deque<SocketHandle> Sockets;
+class Logger;
+class Option;
+class NameResolver;
+extern typedef SharedHandle<NameResolver> NameResolverHandle;
+class RequestGroupMan;
+extern typedef SharedHandle<RequestGroupMan> RequestGroupManHandle;
+class FileAllocationMan;
+extern typedef SharedHandle<FileAllocationMan> FileAllocationManHandle;
+class StatCalc;
+extern typedef SharedHandle<StatCalc> StatCalcHandle;
 #ifdef ENABLE_MESSAGE_DIGEST
-# include "CheckIntegrityMan.h"
+class CheckIntegrityMan;
+extern typedef SharedHandle<CheckIntegrityMan> CheckIntegrityManHandle;
 #endif // ENABLE_MESSAGE_DIGEST
 
-typedef deque<SocketHandle> Sockets;
-
 class SocketEntry {
 public:
   enum TYPE {
@@ -63,15 +69,9 @@ public:
 public:
   SocketEntry(const SocketHandle& socket,
 	      Command* command,
-	      TYPE type):
-    socket(socket), command(command), type(type) {}
-  ~SocketEntry() {}
-
-  bool operator==(const SocketEntry& entry) {
-    return socket == entry.socket &&
-      command == entry.command &&
-      type == entry.type;
-  }
+	      TYPE type);
+
+  bool operator==(const SocketEntry& entry);
 };
 
 typedef deque<SocketEntry> SocketEntries;
@@ -83,14 +83,9 @@ public:
   Command* command;
 public:
   NameResolverEntry(const NameResolverHandle& nameResolver,
-		    Command* command):
-    nameResolver(nameResolver), command(command) {}
-  ~NameResolverEntry() {}
+		    Command* command);
 
-  bool operator==(const NameResolverEntry& entry) {
-    return nameResolver == entry.nameResolver &&
-      command == entry.command;
-  }
+  bool operator==(const NameResolverEntry& entry);
 };
 
 typedef deque<NameResolverEntry> NameResolverEntries;
@@ -108,16 +103,26 @@ private:
   fd_set wfdset;
   int32_t fdmax;
 
+  const Logger* logger;
+  
+  StatCalcHandle _statCalc;
+
+  bool _haltRequested;
+
   void shortSleep() const;
   bool addSocket(const SocketEntry& socketEntry);
   bool deleteSocket(const SocketEntry& socketEntry);
   void executeCommand(Command::STATUS statusFilter);
-protected:
-  const Logger* logger;
-  virtual void initStatistics() = 0;
-  virtual void calculateStatistics() = 0;
-  virtual void onEndOfRun() = 0;
-  virtual void afterEachIteration() {}
+
+  /**
+   * Delegates to StatCalc
+   */
+  void calculateStatistics();
+
+  void onEndOfRun();
+
+  void afterEachIteration();
+
 public:
   bool noWait;
   Commands commands;
@@ -152,11 +157,19 @@ public:
 			       Command* command);
 #endif // ENABLE_ASYNC_DNS
 
-  void addCommand(const Commands& commands)
+  void addCommand(const Commands& commands);
+
+  void fillCommand();
+
+  void setStatCalc(const StatCalcHandle& statCalc);
+
+  bool isHaltRequested() const
   {
-    this->commands.insert(this->commands.end(), commands.begin(), commands.end());
+    return _haltRequested;
   }
 };
 
+typedef SharedHandle<DownloadEngine> DownloadEngineHandle;
+
 #endif // _D_DOWNLOAD_ENGINE_H_
 

+ 34 - 169
src/DownloadEngineFactory.cc

@@ -33,46 +33,31 @@
  */
 /* copyright --> */
 #include "DownloadEngineFactory.h"
+#include "LogFactory.h"
+#include "Option.h"
+#include "RequestGroup.h"
+#include "DownloadEngine.h"
+#include "RequestGroupMan.h"
+#include "FileAllocationMan.h"
+#ifdef ENABLE_MESSAGE_DIGEST
+# include "CheckIntegrityMan.h"
+#endif // ENABLE_MESSAGE_DIGEST
 #include "prefs.h"
-#include "DefaultDiskWriter.h"
-#include "InitiateConnectionCommandFactory.h"
 #include "Util.h"
-#include "FileAllocator.h"
-#include "FileAllocationMonitor.h"
-#include "FillRequestGroupCommand.h"
 #include "CUIDCounter.h"
+#include "FillRequestGroupCommand.h"
 #include "FileAllocationDispatcherCommand.h"
-#include "FileAllocationMan.h"
 #include "AutoSaveCommand.h"
-#ifdef ENABLE_MESSAGE_DIGEST
-# include "CheckIntegrityMan.h"
-#endif // ENABLE_MESSAGE_DIGEST
-#ifdef ENABLE_BITTORRENT
-# include "PeerListenCommand.h"
-# include "TrackerWatcherCommand.h"
-# include "TrackerUpdateCommand.h"
-# include "TorrentAutoSaveCommand.h"
-# include "SeedCheckCommand.h"
-# include "PeerChokeCommand.h"
-# include "HaveEraseCommand.h"
-# include "ActivePeerConnectionCommand.h"
-# include "UnionSeedCriteria.h"
-# include "TimeSeedCriteria.h"
-# include "ShareRatioSeedCriteria.h"
-# include "DefaultPieceStorage.h"
-# include "DefaultPeerStorage.h"
-# include "DefaultBtAnnounce.h"
-# include "DefaultBtProgressInfoFile.h"
-#endif // ENABLE_BITTORRENT
+#include "HaveEraseCommand.h"
+#include "PeerListenCommand.h"
 
-ConsoleDownloadEngine*
-DownloadEngineFactory::newConsoleEngine(const Option* op,
-					const RequestGroups& requestGroups)
+DownloadEngineFactory::DownloadEngineFactory():
+  _logger(LogFactory::getInstance()) {}
+
+DownloadEngineHandle
+DownloadEngineFactory::newDownloadEngine(Option* op,
+					 const RequestGroups& requestGroups)
 {
-  // set PREF_OUT parameter to requestGroup in non-multi download mode.
-  if(requestGroups.size() == 1) {
-    requestGroups.front()->setUserDefinedFilename(op->get(PREF_OUT));
-  }
   RequestGroups workingSet;
   RequestGroups reservedSet;
   if(op->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS) < (int32_t)requestGroups.size()) {
@@ -83,109 +68,24 @@ DownloadEngineFactory::newConsoleEngine(const Option* op,
     workingSet = requestGroups;
   }
 
-  ConsoleDownloadEngine* e = new ConsoleDownloadEngine();
+  DownloadEngineHandle e = new DownloadEngine();
   e->option = op;
-  RequestGroupManHandle requestGroupMan = new RequestGroupMan(workingSet,
-							      op->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
+  RequestGroupManHandle requestGroupMan =
+    new RequestGroupMan(workingSet,
+			op->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
   requestGroupMan->addReservedGroup(reservedSet);
   e->_requestGroupMan = requestGroupMan;
   e->_fileAllocationMan = new FileAllocationMan();
 #ifdef ENABLE_MESSAGE_DIGEST
   e->_checkIntegrityMan = new CheckIntegrityMan();
 #endif // ENABLE_MESSAGE_DIGEST
-  e->commands.push_back(new FillRequestGroupCommand(CUIDCounterSingletonHolder::instance()->newID(), e, 1));
-  e->commands.push_back(new FileAllocationDispatcherCommand(CUIDCounterSingletonHolder::instance()->newID(), e));
-  e->commands.push_back(new AutoSaveCommand(CUIDCounterSingletonHolder::instance()->newID(), e, op->getAsInt(PREF_AUTO_SAVE_INTERVAL)));
-  return e;
-}
-
-ConsoleDownloadEngine*
-DownloadEngineFactory::newConsoleEngine(const Option* op,
-					const Requests& requests,
-					const Requests& reserved)
-{
-  ConsoleDownloadEngine* e = new ConsoleDownloadEngine();
-  e->option = op;
-//   e->segmentMan = new SegmentMan();
-//   e->segmentMan->diskWriter = DefaultDiskWriter::createNewDiskWriter(op);
-//   e->segmentMan->dir = op->get(PREF_DIR);
-//   e->segmentMan->ufilename = op->get(PREF_OUT);
-//   e->segmentMan->option = op;
-//   e->segmentMan->reserved = reserved;
-  
-//   int cuidCounter = 1;
-//   for(Requests::const_iterator itr = requests.begin();
-//       itr != requests.end();
-//       itr++, cuidCounter++) {
-//     e->commands.push_back(InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuidCounter, *itr, e));
-//   }
-  return e;
-}
-
-#ifdef ENABLE_BITTORRENT
-TorrentConsoleDownloadEngine*
-DownloadEngineFactory::newTorrentConsoleEngine(const BtContextHandle& btContext,
-					       const Option* op,
-					       const Strings& targetFiles)
-{
-  TorrentConsoleDownloadEngine* te = new TorrentConsoleDownloadEngine();
-  te->option = op;
-  RequestGroupManHandle requestGroupMan = new RequestGroupMan();
-  te->_requestGroupMan = requestGroupMan;
-  //  ByteArrayDiskWriter* byteArrayDiskWriter = new ByteArrayDiskWriter();
-//   te->segmentMan = new SegmentMan();
-//   te->segmentMan->diskWriter = byteArrayDiskWriter;
-//   te->segmentMan->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);
-
-  BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(),
-					new PeerObjectCluster());
-
-  /*
-  DefaultBtMessageFactoryAdaptorHandle factoryAdaptor =
-    new DefaultBtMessageFactoryAdaptor();
-  BtRegistry::registerBtMessageFactoryAdaptor(btContext->getInfoHashAsString(),
-					      factoryAdaptor);
-
-  BtMessageFactoryClusterHandle factoryCluster = new BtMessageFactoryCluster();
-  BtRegistry::registerBtMessageFactoryCluster(btContext->getInfoHashAsString(),
-					      factoryCluster);
-
-  BtMessageDispatcherClusterHandle dispatcherCluster =
-    new BtMessageDispatcherCluster();
-  BtRegistry::registerBtMessageDispatcherCluster(btContext->getInfoHashAsString(),
-						 dispatcherCluster);
-  */
-  te->setBtContext(btContext);
-  // initialize file storage
-  pieceStorage->initStorage();
-
-  Integers selectIndexes;
-  Util::unfoldRange(op->get(PREF_SELECT_FILE), selectIndexes);
-  if(selectIndexes.size()) {
-    pieceStorage->setFileFilter(selectIndexes);
-  } else {
-    pieceStorage->setFileFilter(targetFiles);
-  }
+  e->commands.push_back(new FillRequestGroupCommand(CUIDCounterSingletonHolder::instance()->newID(), e.get(), 1));
+  e->commands.push_back(new FileAllocationDispatcherCommand(CUIDCounterSingletonHolder::instance()->newID(), e.get()));
+  e->commands.push_back(new AutoSaveCommand(CUIDCounterSingletonHolder::instance()->newID(), e.get(), op->getAsInt(PREF_AUTO_SAVE_INTERVAL)));
+  e->commands.push_back(new HaveEraseCommand(CUIDCounterSingletonHolder::instance()->newID(), e.get(), 10));
 
   PeerListenCommand* listenCommand =
-    new PeerListenCommand(CUIDCounterSingletonHolder::instance()->newID(),
-			  te, btContext);
+    new PeerListenCommand(CUIDCounterSingletonHolder::instance()->newID(), e.get());
   int32_t port;
   int32_t listenPort = op->getAsInt(PREF_LISTEN_PORT);
   if(listenPort == -1) {
@@ -194,48 +94,13 @@ DownloadEngineFactory::newTorrentConsoleEngine(const BtContextHandle& btContext,
     port = listenCommand->bindPort(listenPort, listenPort);
   }
   if(port == -1) {
-    printf(_("Errors occurred while binding port.\n"));
-    exit(EXIT_FAILURE);
+    _logger->error(_("Errors occurred while binding port.\n"));
+    delete listenCommand;
+  } else {
+    op->put(PREF_LISTEN_PORT, Util::itos(port).c_str());
+    e->commands.push_back(listenCommand);
   }
-  btRuntime->setListenPort(port);
-  te->commands.push_back(listenCommand);
-  
-  te->commands.push_back(new TrackerWatcherCommand(CUIDCounterSingletonHolder::instance()->newID(),
-						   te,
-						   btContext));
-  te->commands.push_back(new TrackerUpdateCommand(CUIDCounterSingletonHolder::instance()->newID(),
-						  te,
-						  btContext));
-  te->commands.push_back(new TorrentAutoSaveCommand(CUIDCounterSingletonHolder::instance()->newID(),
-						    te,
-						    btContext,
-						    op->getAsInt(PREF_AUTO_SAVE_INTERVAL)));
-  te->commands.push_back(new PeerChokeCommand(CUIDCounterSingletonHolder::instance()->newID(),
-					      te,
-					      btContext,
-					      10));
-  te->commands.push_back(new HaveEraseCommand(CUIDCounterSingletonHolder::instance()->newID(),
-					      te,
-					      btContext,
-					      10));
-  te->commands.push_back(new ActivePeerConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(),
-							 te,
-							 btContext,
-							 30));
+  //btRuntime->setListenPort(port);
 
-  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), btContext));
-  }
-  if(unionCri->getSeedCriterion().size() > 0) {
-    te->commands.push_back(new SeedCheckCommand(CUIDCounterSingletonHolder::instance()->newID(),
-						te,
-						btContext,
-						unionCri));
-  }
-  return te;
+  return e;
 }
-#endif // ENABLE_BITTORRENT

+ 13 - 18
src/DownloadEngineFactory.h

@@ -36,28 +36,23 @@
 #define _D_DOWNLOAD_ENGINE_FACTORY_H_
 
 #include "common.h"
-#include "ConsoleDownloadEngine.h"
-#ifdef ENABLE_BITTORRENT
-# include "TorrentConsoleDownloadEngine.h"
-#endif // ENABLE_BITTORRENT
+
+class Logger;
+class Option;
+class RequestGroup;
+extern typedef SharedHandle<RequestGroup> RequestGroupHandle;
+extern typedef deque<RequestGroupHandle> RequestGroups;
+class DownloadEngine;
+extern typedef SharedHandle<DownloadEngine> DownloadEngineHandle;
 
 class DownloadEngineFactory {
+private:
+  const Logger* _logger;
 public:
-  static ConsoleDownloadEngine*
-  newConsoleEngine(const Option* op,
-		   const RequestGroups& requestGroups);
-
-  static ConsoleDownloadEngine*
-  newConsoleEngine(const Option* option,
-		   const Requests& requests,
-		   const Requests& reserved);
+  DownloadEngineFactory();
 
-#ifdef ENABLE_BITTORRENT
-  static TorrentConsoleDownloadEngine*
-  newTorrentConsoleEngine(const BtContextHandle& btContext,
-			  const Option* option, 
-			  const Strings& targetFiles);
-#endif // ENABLE_BITTORRENT
+  DownloadEngineHandle
+  newDownloadEngine(Option* op, const RequestGroups& requestGroups);
 };
 
 #endif // _D_DOWNLOAD_ENGINE_FACTORY_H_

+ 23 - 0
src/File.cc

@@ -37,6 +37,11 @@
 #include "a2io.h"
 #include <libgen.h>
 
+#ifdef __MINGW32__
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif // __MINGW32__
+
 File::File(const string& name):name(name) {}
 
 File::~File() {}
@@ -140,3 +145,21 @@ bool File::isDir(const string& filename)
 {
   return File(filename).isDir();
 }
+
+bool File::renameTo(const string& dest)
+{
+#ifdef __MINGW32__
+  /* MinGW's rename() doesn't delete an existing destination */
+  if (_access(dest.c_str(), 0) == 0) {
+    if (_unlink(dest.c_str()) != 0) {
+      return false;
+    }
+  }
+#endif // __MINGW32__
+  if(rename(name.c_str(), dest.c_str()) == 0) {
+    name = dest;
+    return true;
+  } else {
+    return false;
+  }
+}

+ 2 - 0
src/File.h

@@ -96,6 +96,8 @@ public:
   string getDirname() const;
 
   static bool isDir(const string& filename);
+
+  bool renameTo(const string& dest);
 };
 
 #endif // _D_FILE_H_

+ 27 - 24
src/FileAllocationCommand.cc

@@ -33,45 +33,48 @@
  */
 /* copyright --> */
 #include "FileAllocationCommand.h"
-#include "InitiateConnectionCommandFactory.h"
+#include "FileAllocationMan.h"
+#include "FileAllocationEntry.h"
 #include "message.h"
 #include "DownloadCommand.h"
 #include "prefs.h"
 #include "Util.h"
 
+FileAllocationCommand::FileAllocationCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const FileAllocationEntryHandle& fileAllocationEntry):
+  RealtimeCommand(cuid, requestGroup, e),
+  _fileAllocationEntry(fileAllocationEntry) {}
+
+FileAllocationCommand::~FileAllocationCommand() {}
+
 bool FileAllocationCommand::executeInternal()
 {
-  _fileAllocationEntry->allocateChunk();
-  
-  if(_fileAllocationEntry->finished()) {
-    logger->debug(MSG_ALLOCATION_COMPLETED,
-		  _timer.difference(),
-		  Util::llitos(_requestGroup->getTotalLength(), true).c_str());
-    
-    _e->_fileAllocationMan->markCurrentFileAllocationEntryDone();
-    
-    if(_timer.difference() <= _e->option->getAsInt(PREF_DIRECT_DOWNLOAD_TIMEOUT) &&
-       _fileAllocationEntry->getNextDownloadCommand()) {
-      _e->commands.push_back(_fileAllocationEntry->popNextDownloadCommand());
-    } else {
-      Commands commands = _requestGroup->createNextCommandWithAdj(_e, -1);
-      Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, _fileAllocationEntry->getCurrentRequest(), _requestGroup, _e);
+  if(_e->isHaltRequested()) {
+    return true;
+  }
+  try {
+    _fileAllocationEntry->allocateChunk();
+    if(_fileAllocationEntry->finished()) {
+      logger->debug(MSG_ALLOCATION_COMPLETED,
+		    _timer.difference(),
+		    Util::llitos(_requestGroup->getTotalLength(), true).c_str());
+      _e->_fileAllocationMan->markCurrentFileAllocationEntryDone();
+      
+      _e->addCommand(_fileAllocationEntry->prepareForNextAction(_e));
       
-      commands.push_front(command);
-    
-      _e->addCommand(commands);
+      return true;
+    } else {
+      _e->commands.push_back(this);
+      return false;
     }
-    return true;
-  } else {
-    _e->commands.push_back(this);
-    return false;
+  } catch(Exception* e) {
+    _e->_fileAllocationMan->markCurrentFileAllocationEntryDone();
+    throw;
   }
 }
 
 bool FileAllocationCommand::handleException(Exception* e)
 {
   logger->error(MSG_FILE_ALLOCATION_FAILURE, e, cuid);
-  delete e;
   logger->error(MSG_DOWNLOAD_NOT_COMPLETE, cuid, _requestGroup->getFilePath().c_str());
   return true;
 }

+ 7 - 4
src/FileAllocationCommand.h

@@ -37,16 +37,19 @@
 
 #include "RealtimeCommand.h"
 #include "TimeA2.h"
-#include "FileAllocationEntry.h"
+
+class FileAllocationEntry;
+extern typedef SharedHandle<FileAllocationEntry> FileAllocationEntryHandle;
+class Exception;
 
 class FileAllocationCommand : public RealtimeCommand {
 private:
   FileAllocationEntryHandle _fileAllocationEntry;
   Time _timer;
 public:
-  FileAllocationCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const FileAllocationEntryHandle& fileAllocationEntry):
-    RealtimeCommand(cuid, requestGroup, e),
-    _fileAllocationEntry(fileAllocationEntry) {}
+  FileAllocationCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const FileAllocationEntryHandle& fileAllocationEntry);
+
+  virtual ~FileAllocationCommand();
 
   virtual bool executeInternal();
 

+ 18 - 5
src/FileAllocationDispatcherCommand.cc

@@ -33,22 +33,35 @@
  */
 /* copyright --> */
 #include "FileAllocationDispatcherCommand.h"
+#include "DownloadEngine.h"
+#include "RequestGroupMan.h"
+#include "FileAllocationMan.h"
+#include "FileAllocationEntry.h"
 #include "FileAllocationCommand.h"
 #include "message.h"
+#include "CUIDCounter.h"
+
+FileAllocationDispatcherCommand::FileAllocationDispatcherCommand(int32_t cuid, DownloadEngine* e):
+  Command(cuid), _e(e)
+{
+  setStatusRealtime();
+}
+
+FileAllocationDispatcherCommand::~FileAllocationDispatcherCommand() {}
 
 bool FileAllocationDispatcherCommand::execute()
 {
-  if(_e->_requestGroupMan->downloadFinished()) {
+  if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
     return true;
   }
-  
   if(!_e->_fileAllocationMan->isFileAllocationBeingExecuted() &&
      _e->_fileAllocationMan->nextFileAllocationEntryExists()) {
     FileAllocationEntryHandle entry = _e->_fileAllocationMan->popNextFileAllocationEntry();
-    logger->info(MSG_FILE_ALLOCATION_DISPATCH,
-		 entry->getCUID());
+    // TODO we have to change message
+    int32_t newCUID = CUIDCounterSingletonHolder::instance()->newID();
+    logger->info(MSG_FILE_ALLOCATION_DISPATCH, newCUID);
     FileAllocationCommand* command =
-      new FileAllocationCommand(entry->getCUID(),
+      new FileAllocationCommand(newCUID,
 				entry->getRequestGroup(),
 				_e,
 				entry);

+ 5 - 6
src/FileAllocationDispatcherCommand.h

@@ -36,17 +36,16 @@
 #define _D_FILE_ALLOCATION_DISPATCHER_COMMAND_H_
 
 #include "Command.h"
-#include "DownloadEngine.h"
+
+class DownloadEngine;
 
 class FileAllocationDispatcherCommand : public Command {
 private:
   DownloadEngine* _e;
 public:
-  FileAllocationDispatcherCommand(int cuid, DownloadEngine* e):
-    Command(cuid), _e(e)
-  {
-    setStatusRealtime();
-  }
+  FileAllocationDispatcherCommand(int32_t cuid, DownloadEngine* e);
+  
+  virtual ~FileAllocationDispatcherCommand();
 
   virtual bool execute();
 };

+ 26 - 13
src/FileAllocationEntry.cc

@@ -33,22 +33,35 @@
  */
 /* copyright --> */
 #include "FileAllocationEntry.h"
+#include "FileAllocationIterator.h"
+#include "DownloadEngine.h"
+#include "RequestGroup.h"
+#include "PieceStorage.h"
+#include "DiskAdaptor.h"
 
-#define BUFSIZE 16*1024
+FileAllocationEntry::FileAllocationEntry(RequestGroup* requestGroup, Command* nextCommand):
+  RequestGroupEntry(requestGroup, nextCommand),
+  _fileAllocationIterator(requestGroup->getPieceStorage()->getDiskAdaptor()->fileAllocationIterator())
+{}
 
-void FileAllocationEntry::allocateChunk()
+FileAllocationEntry:: ~FileAllocationEntry() {}
+
+int64_t FileAllocationEntry::getCurrentLength()
+{
+  return _fileAllocationIterator->getCurrentLength();
+}
+
+int64_t FileAllocationEntry::getTotalLength()
 {
-  int32_t bufSize = BUFSIZE;
-  char buf[BUFSIZE];
-  memset(buf, 0, bufSize);
-  
-  _requestGroup->getSegmentMan()->diskWriter->writeData(buf, bufSize, _offset);
-  _offset += bufSize;
+  return _fileAllocationIterator->getTotalLength();
+}
 
-  int64_t totalLength = _requestGroup->getSegmentMan()->totalSize;
-  if(totalLength < _offset) {
-    _requestGroup->getSegmentMan()->diskWriter->truncate(totalLength);
-    _offset = totalLength;
-  }
+bool FileAllocationEntry::finished()
+{
+  return _fileAllocationIterator->finished();
 }
 
+void FileAllocationEntry::allocateChunk()
+{
+  _fileAllocationIterator->allocateChunk();
+}

+ 16 - 19
src/FileAllocationEntry.h

@@ -37,32 +37,29 @@
 
 #include "RequestGroupEntry.h"
 
-class FileAllocationEntry : public RequestGroupEntry {
+class FileAllocationIterator;
+extern typedef SharedHandle<FileAllocationIterator> FileAllocationIteratorHandle;
+class Command;
+extern typedef deque<Command*> Commands;
+class DownloadEngine;
+
+class FileAllocationEntry : public RequestGroupEntry, public ProgressAwareEntry {
 private:
-  int64_t _offset;
+  FileAllocationIteratorHandle _fileAllocationIterator;
 public:
-  FileAllocationEntry(int cuid,
-		      const RequestHandle& currentRequest,
-		      RequestGroup* requestGroup,
-		      DownloadCommand* nextDownloadCommand = 0,
-		      int64_t offset = 0):
-    RequestGroupEntry(cuid, currentRequest, requestGroup, nextDownloadCommand),
-    _offset(offset)
-  {}
+  FileAllocationEntry(RequestGroup* requestGroup, Command* nextCommand = 0);
+
+  ~FileAllocationEntry();
 
-  virtual ~FileAllocationEntry() {}
+  virtual int64_t getCurrentLength();
 
-  virtual int64_t getCurrentLength() const
-  {
-    return _offset;
-  }
+  virtual int64_t getTotalLength();
 
-  virtual bool finished() const
-  {
-    return _requestGroup->getTotalLength() <= _offset;
-  }
+  virtual bool finished();
 
   void allocateChunk();
+
+  virtual Commands prepareForNextAction(DownloadEngine* e) = 0;
 };
 
 typedef SharedHandle<FileAllocationEntry> FileAllocationEntryHandle;

+ 56 - 0
src/FileAllocationIterator.h

@@ -0,0 +1,56 @@
+/* <!-- 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_FILE_ALLOCATION_ITERATOR_H_
+#define _D_FILE_ALLOCATION_ITERATOR_H_
+
+#include "common.h"
+
+class FileAllocationIterator
+{
+public:
+  virtual ~FileAllocationIterator() {}
+
+  virtual void allocateChunk() = 0;
+
+  virtual bool finished() = 0;
+
+  virtual int64_t getCurrentLength() = 0;
+
+  virtual int64_t getTotalLength() = 0;
+};
+
+typedef SharedHandle<FileAllocationIterator> FileAllocationIteratorHandle;
+
+#endif // _D_FILE_ALLOCATION_ITERATOR_H_

+ 39 - 29
src/TorrentConsoleDownloadEngine.cc → src/FileAllocationMan.cc

@@ -32,40 +32,50 @@
  * files in the program, then also delete it here.
  */
 /* copyright --> */
-#include "TorrentConsoleDownloadEngine.h"
-#include "Util.h"
-#include <signal.h>
+#include "FileAllocationMan.h"
+#include "FileAllocationEntry.h"
 
-volatile sig_atomic_t btHaltRequested = 0;
+FileAllocationMan::FileAllocationMan():_currentFileAllocationEntry(0) {}
 
-TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {}
+FileAllocationMan::~FileAllocationMan() {}
 
-TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {}
+bool FileAllocationMan::isFileAllocationBeingExecuted() const
+{
+  return _currentFileAllocationEntry.get() != 0;
+}
 
-void TorrentConsoleDownloadEngine::sendStatistics() {
-  printf("\r                                                                             ");
-  printf("\r");
-  if(pieceStorage->downloadFinished()) {
-    printf("Download Completed.");
-  } else {
-    printf("%sB/%sB %d%% %s D:%.2f",
-	   Util::abbrevSize(downloadLength).c_str(),
-	   Util::abbrevSize(totalLength).c_str(),
-	   (totalLength == 0 ?
-	    0 : (int)((downloadLength*100)/totalLength)),
-	   avgSpeed == 0 ? "-" : Util::secfmt(eta).c_str(),
-	   downloadSpeed/1024.0);
-  }
-  printf(" U:%.2f(%sB) %d peers",
-	 uploadSpeed/1024.0,
-	 Util::abbrevSize(uploadLength).c_str(),
-	 btRuntime->getConnections());
-  fflush(stdout);	 
+FileAllocationEntryHandle FileAllocationMan::getCurrentFileAllocationEntry()
+{
+  return _currentFileAllocationEntry;
+}
+
+void FileAllocationMan::markCurrentFileAllocationEntryDone()
+{
+  _currentFileAllocationEntry = 0;
+}
+
+bool FileAllocationMan::nextFileAllocationEntryExists() const
+{
+  return !_fileAllocationEntries.empty();
 }
 
-void TorrentConsoleDownloadEngine::afterEachIteration() {
-  if(btHaltRequested) {
-    btRuntime->setHalt(true);
+FileAllocationEntryHandle FileAllocationMan::popNextFileAllocationEntry()
+{
+  if(!nextFileAllocationEntryExists()) {
+    return 0;
   }
-  TorrentDownloadEngine::afterEachIteration();
+  FileAllocationEntryHandle entry = _fileAllocationEntries.front();
+  _fileAllocationEntries.pop_front();
+  _currentFileAllocationEntry = entry;
+  return entry;
+}
+
+void FileAllocationMan::pushFileAllocationEntry(const FileAllocationEntryHandle& entry)
+{
+  _fileAllocationEntries.push_back(entry);
+}
+
+int32_t FileAllocationMan::countFileAllocationEntryInQueue() const
+{
+  return _fileAllocationEntries.size();
 }

+ 14 - 38
src/FileAllocationMan.h

@@ -36,57 +36,33 @@
 #define _D_FILE_ALLOCATION_MAN_H_
 
 #include "common.h"
-#include "Request.h"
-#include "RequestGroup.h"
-#include "FileAllocationEntry.h"
+
+class FileAllocationEntry;
+extern typedef SharedHandle<FileAllocationEntry> FileAllocationEntryHandle;
+extern typedef deque<FileAllocationEntryHandle> FileAllocationEntries;
 
 class FileAllocationMan {
 private:
   FileAllocationEntries _fileAllocationEntries;
   FileAllocationEntryHandle _currentFileAllocationEntry;
 public:
-  FileAllocationMan():_currentFileAllocationEntry(0) {}
+  FileAllocationMan();
+
+  ~FileAllocationMan();
 
-  bool isFileAllocationBeingExecuted() const
-  {
-    return _currentFileAllocationEntry.get() != 0;
-  }
+  bool isFileAllocationBeingExecuted() const;
 
-  FileAllocationEntryHandle getCurrentFileAllocationEntry()
-  {
-    return _currentFileAllocationEntry;
-  }
+  FileAllocationEntryHandle getCurrentFileAllocationEntry();
 
-  void markCurrentFileAllocationEntryDone()
-  {
-    _currentFileAllocationEntry = 0;
-  }
+  void markCurrentFileAllocationEntryDone();
 
-  bool nextFileAllocationEntryExists() const
-  {
-    return !_fileAllocationEntries.empty();
-  }
+  bool nextFileAllocationEntryExists() const;
 
-  FileAllocationEntryHandle popNextFileAllocationEntry()
-  {
-    if(!nextFileAllocationEntryExists()) {
-      return 0;
-    }
-    FileAllocationEntryHandle entry = _fileAllocationEntries.front();
-    _fileAllocationEntries.pop_front();
-    _currentFileAllocationEntry = entry;
-    return entry;
-  }
+  FileAllocationEntryHandle popNextFileAllocationEntry();
 
-  void pushFileAllocationEntry(const FileAllocationEntryHandle& entry)
-  {
-    _fileAllocationEntries.push_back(entry);
-  }
+  void pushFileAllocationEntry(const FileAllocationEntryHandle& entry);
 
-  int32_t countFileAllocationEntryInQueue() const
-  {
-    return _fileAllocationEntries.size();
-  }
+  int32_t countFileAllocationEntryInQueue() const;
 };
 
 typedef SharedHandle<FileAllocationMan> FileAllocationManHandle;

+ 14 - 1
src/FileEntry.cc

@@ -45,7 +45,8 @@ FileEntry::FileEntry(const string& path,
 
 FileEntry::~FileEntry() {}
 
-void FileEntry::setupDir(const string& parentDir) {
+void FileEntry::setupDir(const string& parentDir)
+{
   string absPath = parentDir+"/"+path;
   char* temp = strdup(absPath.c_str());
   string dir = string(dirname(temp));
@@ -62,3 +63,15 @@ void FileEntry::setupDir(const string& parentDir) {
     throw new DlAbortEx("Failed to create directory %s.", dir.c_str());
   }  
 }
+
+FileEntry& FileEntry::operator=(const FileEntry& entry)
+{
+  if(this != &entry) {
+    path = entry.path;
+    length = entry.length;
+    offset = entry.offset;
+    extracted = entry.extracted;
+    requested = entry.requested;
+  }
+  return *this;
+}

+ 2 - 12
src/FileEntry.h

@@ -50,20 +50,10 @@ public:
 
   FileEntry(const string& path, int64_t length, int64_t offset);
 
-  FileEntry& operator=(const FileEntry& entry)
-  {
-    if(this != &entry) {
-      path = entry.path;
-      length = entry.length;
-      offset = entry.offset;
-      extracted = entry.extracted;
-      requested = entry.requested;
-    }
-    return *this;
-  }
-
   ~FileEntry();
 
+  FileEntry& operator=(const FileEntry& entry);
+
   string getBasename() const
   {
     return File(path).getBasename();

+ 24 - 2
src/FillRequestGroupCommand.cc

@@ -33,11 +33,33 @@
  */
 /* copyright --> */
 #include "FillRequestGroupCommand.h"
+#include "DownloadEngine.h"
+#include "RequestGroupMan.h"
+#include "RequestGroup.h"
+#include "DlAbortEx.h"
+#include "message.h"
+
+FillRequestGroupCommand::FillRequestGroupCommand(int32_t cuid,
+						 DownloadEngine* e,
+						 int32_t interval):
+  Command(cuid),
+  _e(e),
+  _interval(interval)
+{
+  setStatusRealtime();
+}
+
+FillRequestGroupCommand::~FillRequestGroupCommand() {}
 
 bool FillRequestGroupCommand::execute()
 {
-  _e->_requestGroupMan->fillRequestGroupFromReserver(_e);
-  if(_e->_requestGroupMan->downloadFinished()) {
+  try {
+    _e->_requestGroupMan->fillRequestGroupFromReserver(_e);
+  } catch(DlAbortEx* ex) {
+    logger->error(EX_EXCEPTION_CAUGHT, ex);
+    delete ex;
+  }
+  if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
     return true;
   }
   _e->commands.push_back(this);

+ 8 - 9
src/FillRequestGroupCommand.h

@@ -37,8 +37,11 @@
 
 #include "Command.h"
 #include "TimeA2.h"
-#include "RequestGroup.h"
-#include "DownloadEngine.h"
+
+class RequestGroup;
+extern typedef SharedHandle<RequestGroup> RequestGroupHandle;
+extern typedef deque<RequestGroupHandle> RequestGroups;
+class DownloadEngine;
 
 class FillRequestGroupCommand : public Command {
 private:
@@ -47,13 +50,9 @@ private:
   int32_t _interval;
   Time _checkPoint;
 public:
-  FillRequestGroupCommand(int cuid, DownloadEngine* e, int32_t interval):
-    Command(cuid),
-    _e(e),
-    _interval(interval)
-  {
-    setStatusRealtime();
-  }
+  FillRequestGroupCommand(int32_t cuid, DownloadEngine* e, int32_t interval);
+
+  virtual ~FillRequestGroupCommand();
 
   virtual bool execute();
 

Some files were not shown because too many files changed in this diff