diff --git a/ChangeLog b/ChangeLog index 6ef39e4b..26b60622 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-10-12 Tatsuhiro Tsujikawa + + 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 Fixed the compilation error on 64bit platform. diff --git a/TODO b/TODO index eed20372..f805d677 100644 --- a/TODO +++ b/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 diff --git a/configure b/configure index a508fc93..583f6a51 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for aria2c 0.11.3. +# Generated by GNU Autoconf 2.61 for aria2c 0.12.0alpha. # # Report bugs to . # @@ -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='t-tujikawa@users.sourceforge.net' 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 ." _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'`\\" diff --git a/configure.ac b/configure.ac index f2bde30f..e8b26c77 100644 --- a/configure.ac +++ b/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, t-tujikawa@users.sourceforge.net) +AC_INIT(aria2c, 0.12.0alpha, t-tujikawa@users.sourceforge.net) AC_CANONICAL_HOST AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE() diff --git a/po/Makefile.in b/po/Makefile.in index b7b93a8a..1495014b 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -9,7 +9,7 @@ # General Public License and is *not* in the public domain. PACKAGE = aria2c -VERSION = 0.11.3 +VERSION = 0.12.0alpha SHELL = /bin/sh diff --git a/po/POTFILES b/po/POTFILES index e5c35ba8..88babce6 100644 --- a/po/POTFILES +++ b/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 \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 6871d2b7..22b3577c 100644 --- a/po/POTFILES.in +++ b/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 diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index 38a49a01..e4bd954b 100644 --- a/src/AbstractCommand.cc +++ b/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)); + } +} diff --git a/src/AbstractCommand.h b/src/AbstractCommand.h index 89f1d975..26fd4ddb 100644 --- a/src/AbstractCommand.h +++ b/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 RequestHandle; +class DownloadEngine; +class Segment; +extern typedef SharedHandle SegmentHandle; +class NameResolver; +extern typedef SharedHandle 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(); diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index c382fee1..af509244 100644 --- a/src/AbstractDiskWriter.cc +++ b/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; diff --git a/src/AbstractDiskWriter.h b/src/AbstractDiskWriter.h index f6b2d426..e5d8eb14 100644 --- a/src/AbstractDiskWriter.h +++ b/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_ diff --git a/src/AbstractProxyRequestCommand.cc b/src/AbstractProxyRequestCommand.cc index b0257a89..cd1f4a5a 100644 --- a/src/AbstractProxyRequestCommand.cc +++ b/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" diff --git a/src/AbstractProxyRequestCommand.h b/src/AbstractProxyRequestCommand.h index 184ccd92..18dc1336 100644 --- a/src/AbstractProxyRequestCommand.h +++ b/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 HttpConnectionHandle; class AbstractProxyRequestCommand : public AbstractCommand { protected: diff --git a/src/AbstractProxyResponseCommand.cc b/src/AbstractProxyResponseCommand.cc index eaf89762..1c25a0ca 100644 --- a/src/AbstractProxyResponseCommand.cc +++ b/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" diff --git a/src/AbstractProxyResponseCommand.h b/src/AbstractProxyResponseCommand.h index a5770903..44aa8647 100644 --- a/src/AbstractProxyResponseCommand.h +++ b/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 HttpConnectionHandle; class AbstractProxyResponseCommand : public AbstractCommand { protected: diff --git a/src/AbstractSingleDiskAdaptor.cc b/src/AbstractSingleDiskAdaptor.cc index e0bec6ee..44e2e846 100644 --- a/src/AbstractSingleDiskAdaptor.cc +++ b/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); +} diff --git a/src/AbstractSingleDiskAdaptor.h b/src/AbstractSingleDiskAdaptor.h index c4dc7e80..ee0733b8 100644 --- a/src/AbstractSingleDiskAdaptor.h +++ b/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; } diff --git a/src/ActivePeerConnectionCommand.cc b/src/ActivePeerConnectionCommand.cc index d85b1225..27c0798d 100644 --- a/src/ActivePeerConnectionCommand.cc +++ b/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()); diff --git a/src/ActivePeerConnectionCommand.h b/src/ActivePeerConnectionCommand.h index 2bc919f9..4877101e 100644 --- a/src/ActivePeerConnectionCommand.h +++ b/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(); diff --git a/src/AlphaNumberDecorator.h b/src/AlphaNumberDecorator.h index 03f9dc7a..db1543f8 100644 --- a/src/AlphaNumberDecorator.h +++ b/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); diff --git a/src/AutoSaveCommand.cc b/src/AutoSaveCommand.cc index a894ac7e..238eb655 100644 --- a/src/AutoSaveCommand.cc +++ b/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; } } diff --git a/src/AutoSaveCommand.h b/src/AutoSaveCommand.h index 6a1f23ff..e0a700c2 100644 --- a/src/AutoSaveCommand.h +++ b/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(); diff --git a/src/BinaryStream.h b/src/BinaryStream.h new file mode 100644 index 00000000..1d11d8e5 --- /dev/null +++ b/src/BinaryStream.h @@ -0,0 +1,52 @@ +/* */ +#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 BinaryStreamHandle; + +#endif // _D_BINARY_STREAM_H_ diff --git a/src/ConsoleDownloadEngine.h b/src/BtCheckIntegrityEntry.cc similarity index 65% rename from src/ConsoleDownloadEngine.h rename to src/BtCheckIntegrityEntry.cc index a1f61fcd..29558141 100644 --- a/src/ConsoleDownloadEngine.h +++ b/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; +} diff --git a/src/BtCheckIntegrityEntry.h b/src/BtCheckIntegrityEntry.h new file mode 100644 index 00000000..1b5e25cd --- /dev/null +++ b/src/BtCheckIntegrityEntry.h @@ -0,0 +1,51 @@ +/* */ +#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 BtCheckIntegrityEntryHandle; + +#endif // _D_BT_FILE_ALLOCATION_ENTRY_H_ diff --git a/src/BtContext.h b/src/BtContext.h index 69d52029..5d9d493a 100644 --- a/src/BtContext.h +++ b/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 AnnounceTierHandle; typedef deque 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; }; diff --git a/src/BtContextAwareCommand.cc b/src/BtContextAwareCommand.cc index b45d6ddc..ccc42f0b 100644 --- a/src/BtContextAwareCommand.cc +++ b/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)), diff --git a/src/BtContextAwareCommand.h b/src/BtContextAwareCommand.h index 44bbd9b6..3baf2ea7 100644 --- a/src/BtContextAwareCommand.h +++ b/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(); }; diff --git a/src/BtDependency.cc b/src/BtDependency.cc new file mode 100644 index 00000000..8be2266e --- /dev/null +++ b/src/BtDependency.cc @@ -0,0 +1,83 @@ +/* */ +#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; + } +} diff --git a/src/TorrentRequestInfo.h b/src/BtDependency.h similarity index 72% rename from src/TorrentRequestInfo.h rename to src/BtDependency.h index 7b71d89b..b688a957 100644 --- a/src/TorrentRequestInfo.h +++ b/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 { +class RequestGroup; +extern typedef WeakHandle RequestGroupWeakHandle; +class Option; +class Logger; + +class BtDependency : public Dependency +{ private: - string torrentFile; - Strings targetFiles; - + 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 BtDependencyHandle; + +#endif // _D_BT_DEPENDENCY_H_ diff --git a/src/TorrentAutoSaveCommand.cc b/src/BtFileAllocationEntry.cc similarity index 70% rename from src/TorrentAutoSaveCommand.cc rename to src/BtFileAllocationEntry.cc index 28f343dd..b3c72525 100644 --- a/src/TorrentAutoSaveCommand.cc +++ b/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; } diff --git a/src/BtFileAllocationEntry.h b/src/BtFileAllocationEntry.h new file mode 100644 index 00000000..9b21f856 --- /dev/null +++ b/src/BtFileAllocationEntry.h @@ -0,0 +1,56 @@ +/* */ +#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 Commands; + +class BtFileAllocationEntry : public FileAllocationEntry { +public: + BtFileAllocationEntry(RequestGroup* requestGroup); + + virtual ~BtFileAllocationEntry(); + + virtual Commands prepareForNextAction(DownloadEngine* e); +}; + +typedef SharedHandle BtFileAllocationEntryHandle; + +#endif // _D_BT_FILE_ALLOCATION_ENTRY_H_ diff --git a/src/BtPieceMessage.cc b/src/BtPieceMessage.cc index d3587583..a8def5ce 100644 --- a/src/BtPieceMessage.cc +++ b/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()); } diff --git a/src/ConsoleFileAllocationMonitor.cc b/src/BtPostDownloadHandler.cc similarity index 65% rename from src/ConsoleFileAllocationMonitor.cc rename to src/BtPostDownloadHandler.cc index b6245b90..b2fc19b9 100644 --- a/src/ConsoleFileAllocationMonitor.cc +++ b/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 << "*"; +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)); } - for(int32_t i = 0; i < 20-numOfStar; ++i) { - cout << " "; - } - 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; } diff --git a/src/BtPostDownloadHandler.h b/src/BtPostDownloadHandler.h new file mode 100644 index 00000000..f1cb1638 --- /dev/null +++ b/src/BtPostDownloadHandler.h @@ -0,0 +1,51 @@ +/* */ +#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 BtPostDownloadHandlerHandle; +#endif // _D_BT_POST_DOWNLOAD_HANDLER_H_ diff --git a/src/BtProgressInfoFile.h b/src/BtProgressInfoFile.h index e4d8f2ff..968e5525 100644 --- a/src/BtProgressInfoFile.h +++ b/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; diff --git a/src/BtRegistry.cc b/src/BtRegistry.cc index e74b86bf..3358da13 100644 --- a/src/BtRegistry.cc +++ b/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 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 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 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 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 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); +} diff --git a/src/BtRegistry.h b/src/BtRegistry.h index 7a9eafb0..d0722f05 100644 --- a/src/BtRegistry.h +++ b/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 -typedef map PeerStorageMap; -typedef map PieceStorageMap; -typedef map BtAnnounceMap; -typedef map BtRuntimeMap; -typedef map BtProgressInfoFileMap; +typedef HandleRegistry PeerStorageMap; +typedef HandleRegistry PieceStorageMap; +typedef HandleRegistry BtAnnounceMap; +typedef HandleRegistry BtRuntimeMap; +typedef HandleRegistry BtProgressInfoFileMap; +typedef HandleRegistry BtContextMap; // for BtMessageFactory typedef HandleRegistry 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) \ diff --git a/src/BtRuntime.h b/src/BtRuntime.h index 4b58f748..55644bc6 100644 --- a/src/BtRuntime.h +++ b/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 BtRuntimeHandle; diff --git a/src/BtSetup.cc b/src/BtSetup.cc new file mode 100644 index 00000000..d9a70fbb --- /dev/null +++ b/src/BtSetup.cc @@ -0,0 +1,97 @@ +/* */ +#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 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; +} diff --git a/src/DefaultFileAllocator.h b/src/BtSetup.h similarity index 80% rename from src/DefaultFileAllocator.h rename to src/BtSetup.h index 1a74939a..12636eee 100644 --- a/src/DefaultFileAllocator.h +++ b/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 { +class RequestGroup; +class DownloadEngine; +class Option; +class Command; +extern typedef deque Commands; + +class BtSetup { public: - DefaultFileAllocator() {} - - virtual ~DefaultFileAllocator() {} - - virtual void allocate(int fd, int64_t totalLength); + Commands setup(RequestGroup* requestGroup, + DownloadEngine* e, + const Option* option); }; -typedef SharedHandle DefaultFileAllocatorHandle; - -#endif // _D_DEFAULT_FILE_ALLOCATOR_H_ +#endif // _D_BT_SETUP_H_ diff --git a/src/ByteArrayDiskWriter.cc b/src/ByteArrayDiskWriter.cc index 0e8c2151..864d167c 100644 --- a/src/ByteArrayDiskWriter.cc +++ b/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(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(data), len); // TODO we have to call buf.clear() here? YES buf.clear(); return buf.gcount(); diff --git a/src/ByteArrayDiskWriter.h b/src/ByteArrayDiskWriter.h index a3583552..f35b4366 100644 --- a/src/ByteArrayDiskWriter.h +++ b/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) {} diff --git a/src/ByteArrayDiskWriterFactory.h b/src/ByteArrayDiskWriterFactory.h new file mode 100644 index 00000000..2c72194e --- /dev/null +++ b/src/ByteArrayDiskWriterFactory.h @@ -0,0 +1,52 @@ +/* */ +#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 ByteArrayDiskWriterFactoryHandle; + +#endif // _D_BYTE_ARRAY_DISK_WRITER_FACTORY_H_ diff --git a/src/CheckIntegrityCommand.cc b/src/CheckIntegrityCommand.cc index 5b1231cd..a2d4aad1 100644 --- a/src/CheckIntegrityCommand.cc +++ b/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; } diff --git a/src/CheckIntegrityCommand.h b/src/CheckIntegrityCommand.h index e66fe93d..c924b8b1 100644 --- a/src/CheckIntegrityCommand.h +++ b/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 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(); diff --git a/src/CheckIntegrityEntry.cc b/src/CheckIntegrityEntry.cc index d4ae1e7c..0377b907 100644 --- a/src/CheckIntegrityEntry.cc +++ b/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(); +} diff --git a/src/CheckIntegrityEntry.h b/src/CheckIntegrityEntry.h index b52b7ce6..e82076d1 100644 --- a/src/CheckIntegrityEntry.h +++ b/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 IteratableChunkChecksumValidatorHandle; +class Command; +extern typedef deque 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 ~CheckIntegrityEntry(); - virtual int64_t getCurrentLength() const; + virtual int64_t getTotalLength(); - virtual bool finished() const; + virtual int64_t getCurrentLength(); + + virtual bool finished(); + + bool isValidationReady(); void initValidator(); void validateChunk(); + + void updatePieceStorage(); + + virtual Commands prepareForNextAction(DownloadEngine* e) = 0; }; typedef SharedHandle CheckIntegrityEntryHandle; diff --git a/src/CheckIntegrityMan.cc b/src/CheckIntegrityMan.cc new file mode 100644 index 00000000..dcb7d157 --- /dev/null +++ b/src/CheckIntegrityMan.cc @@ -0,0 +1,72 @@ +/* */ +#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(); +} diff --git a/src/CheckIntegrityMan.h b/src/CheckIntegrityMan.h index bc0297ae..1e07cd78 100644 --- a/src/CheckIntegrityMan.h +++ b/src/CheckIntegrityMan.h @@ -36,43 +36,26 @@ #define _D_CHECK_INTEGRITY_MAN_H_ #include "common.h" -#include "CheckIntegrityEntry.h" + +class CheckIntegrityEntry; +extern typedef SharedHandle CheckIntegrityEntryHandle; +extern typedef deque CheckIntegrityEntries; class CheckIntegrityMan { private: CheckIntegrityEntries _checkIntegrityEntries; public: - void addCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry) - { - _checkIntegrityEntries.push_back(entry); - } + CheckIntegrityMan(); - 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; - } - } + ~CheckIntegrityMan(); - CheckIntegrityEntryHandle getFirstCheckIntegrityEntry() const - { - if(_checkIntegrityEntries.empty()) { - return 0; - } else { - return _checkIntegrityEntries.front(); - } - } + void addCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry); - int32_t countCheckIntegrityEntry() const - { - return _checkIntegrityEntries.size(); - } + bool removeCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry); + + CheckIntegrityEntryHandle getFirstCheckIntegrityEntry() const; + + int32_t countCheckIntegrityEntry() const; }; typedef SharedHandle CheckIntegrityManHandle; diff --git a/src/ChecksumCommand.cc b/src/ChecksumCommand.cc index 0d2166c4..b2ec0964 100644 --- a/src/ChecksumCommand.cc +++ b/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 diff --git a/src/ChecksumCommand.h b/src/ChecksumCommand.h index 06260380..f460f1a8 100644 --- a/src/ChecksumCommand.h +++ b/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(); diff --git a/src/ChunkChecksum.h b/src/ChunkChecksum.h index 9b91b351..e9dfbee2 100644 --- a/src/ChunkChecksum.h +++ b/src/ChunkChecksum.h @@ -79,6 +79,11 @@ public: return ""; } } + + const Strings& getChecksums() const + { + return _checksums; + } int32_t getChecksumLength() const { diff --git a/src/ChunkChecksumValidator.cc b/src/ChunkChecksumValidator.cc index 9e9b65ff..b6a5a5bf 100644 --- a/src/ChunkChecksumValidator.cc +++ b/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(); +*/ } diff --git a/src/ConsoleDownloadEngine.cc b/src/ConsoleDownloadEngine.cc deleted file mode 100644 index 5237ba16..00000000 --- a/src/ConsoleDownloadEngine.cc +++ /dev/null @@ -1,210 +0,0 @@ -/* */ -#include "ConsoleDownloadEngine.h" -#include "Util.h" -#include -#include - -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)); -} diff --git a/src/ConsoleStatCalc.cc b/src/ConsoleStatCalc.cc new file mode 100644 index 00000000..d30ce945 --- /dev/null +++ b/src/ConsoleStatCalc.cc @@ -0,0 +1,162 @@ +/* */ +#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 + +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; +} diff --git a/src/TrackerSegmentManFactory.h b/src/ConsoleStatCalc.h similarity index 76% rename from src/TrackerSegmentManFactory.h rename to src/ConsoleStatCalc.h index dcec0096..f221509b 100644 --- a/src/TrackerSegmentManFactory.h +++ b/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 TrackerSegmentManFactoryHandle; +typedef SharedHandle ConsoleStatCalcHandle; -#endif // _D_TRACKER_SEGMENT_MAN_FACTORY_H_ +#endif // _D_CONSOLE_STAT_CALC_H_ diff --git a/src/CopyDiskAdaptor.cc b/src/CopyDiskAdaptor.cc index 1cc92bfb..a08b0808 100644 --- a/src/CopyDiskAdaptor.cc +++ b/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; } diff --git a/src/CopyDiskAdaptor.h b/src/CopyDiskAdaptor.h index af6effdf..22b3fec9 100644 --- a/src/CopyDiskAdaptor.h +++ b/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) { diff --git a/src/DefaultBtContext.cc b/src/DefaultBtContext.cc index 17bc22a2..39a5a8cf 100644 --- a/src/DefaultBtContext.cc +++ b/src/DefaultBtContext.cc @@ -42,9 +42,10 @@ #include "Util.h" #include "MessageDigestHelper.h" #include "a2netcompat.h" +#include "AnnounceTier.h" #include -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; diff --git a/src/DefaultBtContext.h b/src/DefaultBtContext.h index 36c9a543..609cad18 100644 --- a/src/DefaultBtContext.h +++ b/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 DefaultBtContextHandle; diff --git a/src/DefaultBtProgressInfoFile.cc b/src/DefaultBtProgressInfoFile.cc index 7c0c9a77..955d11bb 100644 --- a/src/DefaultBtProgressInfoFile.cc +++ b/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 #include -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() {} -void DefaultBtProgressInfoFile::save() { - logger->info(MSG_SAVING_SEGMENT_FILE, filename.c_str()); - string filenameTemp = filename+"__temp"; - FILE* file = openFile(filenameTemp, "wb"); - try { - if(fwrite(btContext->getInfoHash(), - btContext->getInfoHashLength(), 1, file) < 1) { - throw string("writeError:info hash"); - } - if(fwrite(pieceStorage->getBitfield(), - pieceStorage->getBitfieldLength(), 1, file) < 1) { - throw string("writeError:bitfield"); - } - TransferStat stat = peerStorage->calculateStat(); - int64_t allTimeDownloadLength = pieceStorage->getCompletedLength(); - if(fwrite(&allTimeDownloadLength, - sizeof(allTimeDownloadLength), 1, file) < 1) { - throw string("writeError:download length"); - } - int64_t allTimeUploadLength = - btRuntime->getUploadLengthAtStartup()+ - stat.getSessionUploadLength(); - if(fwrite(&allTimeUploadLength, - sizeof(allTimeUploadLength), 1, file) < 1) { - throw string("writeError:upload length"); - } - fclose(file); - logger->info(MSG_SAVED_SEGMENT_FILE); - } catch(string ex) { - fclose(file); - throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, - filename.c_str(), strerror(errno)); - } +bool DefaultBtProgressInfoFile::isTorrentDownload() +{ + return !BtContextHandle(_dctx).isNull(); +} - if(rename(filenameTemp.c_str(), filename.c_str()) == -1) { +void DefaultBtProgressInfoFile::save() { + _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 { + bool torrentDownload = isTorrentDownload(); + // file version: 16 bits + // value: '0' + int16_t version = 0; + o.write(reinterpret_cast(&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; + } + o.write(reinterpret_cast(&extension), sizeof(extension)); + if(torrentDownload) { + // infoHashLength: + // length: 32 bits + BtContextHandle btContext = _dctx; + int32_t infoHashLength = btContext->getInfoHashLength(); + o.write(reinterpret_cast(&infoHashLength), sizeof(int32_t)); + // infoHash: + o.write(reinterpret_cast(btContext->getInfoHash()), + btContext->getInfoHashLength()); + } else { + // infoHashLength: + // length: 32 bits + int32_t infoHashLength = 0; + o.write(reinterpret_cast(&infoHashLength), sizeof(int32_t)); + } + // pieceLength: 32 bits + int32_t pieceLength = _dctx->getPieceLength(); + o.write(reinterpret_cast(&pieceLength), sizeof(int32_t)); + // totalLength: 64 bits + int64_t totalLength = _dctx->getTotalLength(); + o.write(reinterpret_cast(&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(); + } + o.write(reinterpret_cast(&uploadLength), sizeof(int64_t)); + // bitfieldLength: 32 bits + int32_t bitfieldLength = _pieceStorage->getBitfieldLength(); + o.write(reinterpret_cast(&bitfieldLength), sizeof(int32_t)); + // bitfield + o.write(reinterpret_cast(_pieceStorage->getBitfield()), _pieceStorage->getBitfieldLength()); + // the number of in-flight piece: 32 bits + // TODO implement this + int32_t numInFlightPiece = _pieceStorage->countInFlightPiece(); + o.write(reinterpret_cast(&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(&index), sizeof(int32_t)); + int32_t length = (*itr)->getLength(); + o.write(reinterpret_cast(&length), sizeof(int32_t)); + int32_t bitfieldLength = (*itr)->getBitfieldLength(); + o.write(reinterpret_cast(&bitfieldLength), sizeof(int32_t)); + o.write(reinterpret_cast((*itr)->getBitfield()), bitfieldLength); + } + + 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) { + throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, + _filename.c_str(), strerror(errno)); } } -void DefaultBtProgressInfoFile::load() { - logger->info(MSG_LOADING_SEGMENT_FILE, filename.c_str()); - FILE* file = openFile(filename, "r+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()); } - if(Util::toHex(savedInfoHash, btContext->getInfoHashLength()) != - btContext->getInfoHashAsString()) { - throw string("infoHashMismatch"); + 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."); } - if(fread(savedBitfield, pieceStorage->getBitfieldLength(), 1, file) < 1) { - throw string("readError"); + + int32_t infoHashLength; + in.read(reinterpret_cast(&infoHashLength), sizeof(infoHashLength)); + if(infoHashLength < 0 || infoHashLength == 0 && infoHashCheckEnabled) { + throw new DlAbortEx("Invalid info hash length: %d", infoHashLength); } - 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"); + if(infoHashLength > 0) { + savedInfoHash = new unsigned char[infoHashLength]; + in.read(reinterpret_cast(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; } - 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 pieceLength; + in.read(reinterpret_cast(&pieceLength), sizeof(pieceLength)); + if(pieceLength != _dctx->getPieceLength()) { + throw new DlAbortEx("piece length mismatch. expected: %d, actual: %d", + _dctx->getPieceLength(), pieceLength); } - btRuntime->setUploadLengthAtStartup(allTimeUploadLength); + + int64_t totalLength; + in.read(reinterpret_cast(&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()); + } + int64_t uploadLength; + in.read(reinterpret_cast(&uploadLength), sizeof(uploadLength)); + if(isTorrentDownload()) { + BT_RUNTIME(BtContextHandle(_dctx))->setUploadLengthAtStartup(uploadLength); + } + + // TODO implement the conversion mechanism between different piece length. + int32_t bitfieldLength; + in.read(reinterpret_cast(&bitfieldLength), sizeof(bitfieldLength)); + if(_pieceStorage->getBitfieldLength() != bitfieldLength) { + throw new DlAbortEx("bitfield length mismatch. expected: %d, actual: %d", + _pieceStorage->getBitfieldLength(), + bitfieldLength); + } + + // TODO implement the conversion mechanism between different piece length. + savedBitfield = new unsigned char[bitfieldLength]; + in.read(reinterpret_cast(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(&numInFlightPiece), sizeof(numInFlightPiece)); + + Pieces inFlightPieces; + while(numInFlightPiece--) { + int32_t index; + in.read(reinterpret_cast(&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(&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(&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(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; } } diff --git a/src/DefaultBtProgressInfoFile.h b/src/DefaultBtProgressInfoFile.h index 201900dd..4ca0e5e6 100644 --- a/src/DefaultBtProgressInfoFile.h +++ b/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 DownloadContextHandle; +class PieceStorage; +extern typedef SharedHandle 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 string getFilename() { return _filename; } + virtual bool exists(); virtual void save(); diff --git a/src/DefaultDiskWriter.cc b/src/DefaultDiskWriter.cc index 4ddef412..4334391e 100644 --- a/src/DefaultDiskWriter.cc +++ b/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 @@ -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; } diff --git a/src/DefaultDiskWriter.h b/src/DefaultDiskWriter.h index 5668d9a1..e5516181 100644 --- a/src/DefaultDiskWriter.h +++ b/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 DefaultDiskWriterHandle; diff --git a/src/DefaultDiskWriterFactory.h b/src/DefaultDiskWriterFactory.h new file mode 100644 index 00000000..1a8a1156 --- /dev/null +++ b/src/DefaultDiskWriterFactory.h @@ -0,0 +1,52 @@ +/* */ +#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 DefaultDiskWriterFactoryHandle; + +#endif // _D_DEFAULT_DISK_WRITER_FACTORY_H_ diff --git a/src/DefaultPeerStorage.cc b/src/DefaultPeerStorage.cc index dee82851..b0782b11 100644 --- a/src/DefaultPeerStorage.cc +++ b/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; } diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc index 5afb64e7..7435fbce 100644 --- a/src/DefaultPieceStorage.cc +++ b/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); - - ChunkChecksumValidator v(iv); - v.setFileAllocationMonitor(FileAllocationMonitorFactory::getFactory()->createNewMonitor()); - v.validate(); + // TODO implement this + abort(); +} + +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; } diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h index 97ae031e..9da473c2 100644 --- a/src/DefaultPieceStorage.h +++ b/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 DownloadContextHandle; +class BitfieldMan; +class Logger; +class Option; +extern typedef deque Pieces; +class DiskWriterFactory; +extern typedef SharedHandle DiskWriterFactoryHandle; #define END_GAME_PIECE_NUM 20 @@ -67,15 +69,15 @@ typedef deque 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 DefaultPieceStorageHandle; + #endif // _D_DEFAULT_PIECE_STORAGE_H_ diff --git a/src/DefaultSegmentManFactory.cc b/src/DefaultSegmentManFactory.cc index 0719045d..00d66e9a 100644 --- a/src/DefaultSegmentManFactory.cc +++ b/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; } diff --git a/src/DefaultSegmentManFactory.h b/src/DefaultSegmentManFactory.h index 0a8dad1d..e09d1b29 100644 --- a/src/DefaultSegmentManFactory.h +++ b/src/DefaultSegmentManFactory.h @@ -43,7 +43,8 @@ public: virtual ~DefaultSegmentManFactory() {} - virtual SegmentManHandle createNewInstance(); + virtual SegmentManHandle createNewInstance(const DownloadContextHandle& dc, + const PieceStorageHandle& ps); }; typedef SharedHandle DefaultSegmentManFactoryHandle; diff --git a/src/FileAllocationMonitor.cc b/src/Dependency.h similarity index 86% rename from src/FileAllocationMonitor.cc rename to src/Dependency.h index 7a68df7b..0851f66c 100644 --- a/src/FileAllocationMonitor.cc +++ b/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 DependencyHandle; + +#endif // _D_DEPENDENCY_H_ diff --git a/src/DirectDiskAdaptor.cc b/src/DirectDiskAdaptor.cc index 46941558..096d27dd 100644 --- a/src/DirectDiskAdaptor.cc +++ b/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(); } diff --git a/src/DirectDiskAdaptor.h b/src/DirectDiskAdaptor.h index 16b01f36..5fcb37fd 100644 --- a/src/DirectDiskAdaptor.h +++ b/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 DirectDiskAdaptorHandle; diff --git a/src/DiskAdaptor.cc b/src/DiskAdaptor.cc index 4aa59c54..0a12df6a 100644 --- a/src/DiskAdaptor.cc +++ b/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); diff --git a/src/DiskAdaptor.h b/src/DiskAdaptor.h index 5a1c6df1..b44b69db 100644 --- a/src/DiskAdaptor.h +++ b/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 DiskAdaptorHandle; diff --git a/src/DiskWriter.h b/src/DiskWriter.h index 5f0a93b5..f64808d6 100644 --- a/src/DiskWriter.h +++ b/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 diff --git a/src/GlowFileAllocator.h b/src/DiskWriterFactory.h similarity index 81% rename from src/GlowFileAllocator.h rename to src/DiskWriterFactory.h index a16af76b..07611bc0 100644 --- a/src/GlowFileAllocator.h +++ b/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 GlowFileAllocatorHandle; +typedef SharedHandle DiskWriterFactoryHandle; -#endif // _D_GLOW_FILE_ALLOCATOR_H_ +#endif // _D_DISK_WRITER_FACTORY_H_ diff --git a/src/DownloadCommand.cc b/src/DownloadCommand.cc index 2de238d6..bbc9dfcb 100644 --- a/src/DownloadCommand.cc +++ b/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 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; +} diff --git a/src/DownloadCommand.h b/src/DownloadCommand.h index c8176dcb..0e675d35 100644 --- a/src/DownloadCommand.h +++ b/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 TransferEncodingHandle; +class PeerStat; +extern typedef SharedHandle 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; diff --git a/src/DownloadContext.h b/src/DownloadContext.h new file mode 100644 index 00000000..9d70af11 --- /dev/null +++ b/src/DownloadContext.h @@ -0,0 +1,99 @@ +/* */ +#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 DownloadContextHandle; + +#endif // _D_DOWNLOAD_CONTEXT_H_ diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index 62dd7637..548b2d57 100644 --- a/src/DownloadEngine.cc +++ b/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 #include #include +#include #include -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 diff --git a/src/DownloadEngine.h b/src/DownloadEngine.h index 2ce84dcb..a1486b66 100644 --- a/src/DownloadEngine.h +++ b/src/DownloadEngine.h @@ -35,20 +35,26 @@ #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" -#ifdef ENABLE_MESSAGE_DIGEST -# include "CheckIntegrityMan.h" -#endif // ENABLE_MESSAGE_DIGEST +#include "Command.h" -typedef deque Sockets; +class SocketCore; +extern typedef SharedHandle SocketHandle; +extern typedef deque Sockets; +class Logger; +class Option; +class NameResolver; +extern typedef SharedHandle NameResolverHandle; +class RequestGroupMan; +extern typedef SharedHandle RequestGroupManHandle; +class FileAllocationMan; +extern typedef SharedHandle FileAllocationManHandle; +class StatCalc; +extern typedef SharedHandle StatCalcHandle; +#ifdef ENABLE_MESSAGE_DIGEST +class CheckIntegrityMan; +extern typedef SharedHandle CheckIntegrityManHandle; +#endif // ENABLE_MESSAGE_DIGEST class SocketEntry { public: @@ -63,15 +69,9 @@ public: public: SocketEntry(const SocketHandle& socket, Command* command, - TYPE type): - socket(socket), command(command), type(type) {} - ~SocketEntry() {} + TYPE type); - bool operator==(const SocketEntry& entry) { - return socket == entry.socket && - command == entry.command && - type == entry.type; - } + bool operator==(const SocketEntry& entry); }; typedef deque 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 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 DownloadEngineHandle; + #endif // _D_DOWNLOAD_ENGINE_H_ diff --git a/src/DownloadEngineFactory.cc b/src/DownloadEngineFactory.cc index 2c8f5b24..b3905981 100644 --- a/src/DownloadEngineFactory.cc +++ b/src/DownloadEngineFactory.cc @@ -33,46 +33,31 @@ */ /* copyright --> */ #include "DownloadEngineFactory.h" -#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 "FileAllocationDispatcherCommand.h" +#include "LogFactory.h" +#include "Option.h" +#include "RequestGroup.h" +#include "DownloadEngine.h" +#include "RequestGroupMan.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 "prefs.h" +#include "Util.h" +#include "CUIDCounter.h" +#include "FillRequestGroupCommand.h" +#include "FileAllocationDispatcherCommand.h" +#include "AutoSaveCommand.h" +#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 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 diff --git a/src/DownloadEngineFactory.h b/src/DownloadEngineFactory.h index f9d11e5d..59c41712 100644 --- a/src/DownloadEngineFactory.h +++ b/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 RequestGroupHandle; +extern typedef deque RequestGroups; +class DownloadEngine; +extern typedef SharedHandle DownloadEngineHandle; class DownloadEngineFactory { +private: + const Logger* _logger; public: - static ConsoleDownloadEngine* - newConsoleEngine(const Option* op, - const RequestGroups& requestGroups); + DownloadEngineFactory(); - static ConsoleDownloadEngine* - newConsoleEngine(const Option* option, - const Requests& requests, - const Requests& reserved); - -#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_ diff --git a/src/File.cc b/src/File.cc index 342b91ca..0796e1e0 100644 --- a/src/File.cc +++ b/src/File.cc @@ -37,6 +37,11 @@ #include "a2io.h" #include +#ifdef __MINGW32__ +# define WIN32_LEAN_AND_MEAN +# include +#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; + } +} diff --git a/src/File.h b/src/File.h index 27cd386a..36b93093 100644 --- a/src/File.h +++ b/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_ diff --git a/src/FileAllocationCommand.cc b/src/FileAllocationCommand.cc index 554086d8..01a24d65 100644 --- a/src/FileAllocationCommand.cc +++ b/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); - - commands.push_front(command); - - _e->addCommand(commands); - } + if(_e->isHaltRequested()) { return true; - } else { - _e->commands.push_back(this); - return false; + } + 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)); + + 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; } diff --git a/src/FileAllocationCommand.h b/src/FileAllocationCommand.h index 84dfe652..371c6091 100644 --- a/src/FileAllocationCommand.h +++ b/src/FileAllocationCommand.h @@ -37,16 +37,19 @@ #include "RealtimeCommand.h" #include "TimeA2.h" -#include "FileAllocationEntry.h" + +class FileAllocationEntry; +extern typedef SharedHandle 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(); diff --git a/src/FileAllocationDispatcherCommand.cc b/src/FileAllocationDispatcherCommand.cc index 8f328bbf..146d33fc 100644 --- a/src/FileAllocationDispatcherCommand.cc +++ b/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); diff --git a/src/FileAllocationDispatcherCommand.h b/src/FileAllocationDispatcherCommand.h index e52681d6..892daed2 100644 --- a/src/FileAllocationDispatcherCommand.h +++ b/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(); }; diff --git a/src/FileAllocationEntry.cc b/src/FileAllocationEntry.cc index 77690475..af9c67c1 100644 --- a/src/FileAllocationEntry.cc +++ b/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()) +{} + +FileAllocationEntry:: ~FileAllocationEntry() {} + +int64_t FileAllocationEntry::getCurrentLength() +{ + return _fileAllocationIterator->getCurrentLength(); +} + +int64_t FileAllocationEntry::getTotalLength() +{ + return _fileAllocationIterator->getTotalLength(); +} + +bool FileAllocationEntry::finished() +{ + return _fileAllocationIterator->finished(); +} void FileAllocationEntry::allocateChunk() { - int32_t bufSize = BUFSIZE; - char buf[BUFSIZE]; - memset(buf, 0, bufSize); - - _requestGroup->getSegmentMan()->diskWriter->writeData(buf, bufSize, _offset); - _offset += bufSize; - - int64_t totalLength = _requestGroup->getSegmentMan()->totalSize; - if(totalLength < _offset) { - _requestGroup->getSegmentMan()->diskWriter->truncate(totalLength); - _offset = totalLength; - } + _fileAllocationIterator->allocateChunk(); } - diff --git a/src/FileAllocationEntry.h b/src/FileAllocationEntry.h index 6108f41a..02843c03 100644 --- a/src/FileAllocationEntry.h +++ b/src/FileAllocationEntry.h @@ -37,32 +37,29 @@ #include "RequestGroupEntry.h" -class FileAllocationEntry : public RequestGroupEntry { +class FileAllocationIterator; +extern typedef SharedHandle FileAllocationIteratorHandle; +class Command; +extern typedef deque 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); - virtual ~FileAllocationEntry() {} + ~FileAllocationEntry(); - virtual int64_t getCurrentLength() const - { - return _offset; - } + virtual int64_t getCurrentLength(); - virtual bool finished() const - { - return _requestGroup->getTotalLength() <= _offset; - } + virtual int64_t getTotalLength(); + + virtual bool finished(); void allocateChunk(); + + virtual Commands prepareForNextAction(DownloadEngine* e) = 0; }; typedef SharedHandle FileAllocationEntryHandle; diff --git a/src/FileAllocationIterator.h b/src/FileAllocationIterator.h new file mode 100644 index 00000000..10685e76 --- /dev/null +++ b/src/FileAllocationIterator.h @@ -0,0 +1,56 @@ +/* */ +#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 FileAllocationIteratorHandle; + +#endif // _D_FILE_ALLOCATION_ITERATOR_H_ diff --git a/src/TorrentConsoleDownloadEngine.cc b/src/FileAllocationMan.cc similarity index 58% rename from src/TorrentConsoleDownloadEngine.cc rename to src/FileAllocationMan.cc index ad036147..205012ff 100644 --- a/src/TorrentConsoleDownloadEngine.cc +++ b/src/FileAllocationMan.cc @@ -32,40 +32,50 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#include "TorrentConsoleDownloadEngine.h" -#include "Util.h" -#include +#include "FileAllocationMan.h" +#include "FileAllocationEntry.h" -volatile sig_atomic_t btHaltRequested = 0; +FileAllocationMan::FileAllocationMan():_currentFileAllocationEntry(0) {} -TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {} +FileAllocationMan::~FileAllocationMan() {} -TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {} - -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); +bool FileAllocationMan::isFileAllocationBeingExecuted() const +{ + return _currentFileAllocationEntry.get() != 0; } -void TorrentConsoleDownloadEngine::afterEachIteration() { - if(btHaltRequested) { - btRuntime->setHalt(true); - } - TorrentDownloadEngine::afterEachIteration(); +FileAllocationEntryHandle FileAllocationMan::getCurrentFileAllocationEntry() +{ + return _currentFileAllocationEntry; +} + +void FileAllocationMan::markCurrentFileAllocationEntryDone() +{ + _currentFileAllocationEntry = 0; +} + +bool FileAllocationMan::nextFileAllocationEntryExists() const +{ + return !_fileAllocationEntries.empty(); +} + +FileAllocationEntryHandle FileAllocationMan::popNextFileAllocationEntry() +{ + if(!nextFileAllocationEntryExists()) { + return 0; + } + 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(); } diff --git a/src/FileAllocationMan.h b/src/FileAllocationMan.h index a4b2413e..17557d9b 100644 --- a/src/FileAllocationMan.h +++ b/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 FileAllocationEntryHandle; +extern typedef deque FileAllocationEntries; class FileAllocationMan { private: FileAllocationEntries _fileAllocationEntries; FileAllocationEntryHandle _currentFileAllocationEntry; public: - FileAllocationMan():_currentFileAllocationEntry(0) {} + FileAllocationMan(); - bool isFileAllocationBeingExecuted() const - { - return _currentFileAllocationEntry.get() != 0; - } + ~FileAllocationMan(); - FileAllocationEntryHandle getCurrentFileAllocationEntry() - { - return _currentFileAllocationEntry; - } + bool isFileAllocationBeingExecuted() const; - void markCurrentFileAllocationEntryDone() - { - _currentFileAllocationEntry = 0; - } + FileAllocationEntryHandle getCurrentFileAllocationEntry(); - bool nextFileAllocationEntryExists() const - { - return !_fileAllocationEntries.empty(); - } + void markCurrentFileAllocationEntryDone(); - FileAllocationEntryHandle popNextFileAllocationEntry() - { - if(!nextFileAllocationEntryExists()) { - return 0; - } - FileAllocationEntryHandle entry = _fileAllocationEntries.front(); - _fileAllocationEntries.pop_front(); - _currentFileAllocationEntry = entry; - return entry; - } + bool nextFileAllocationEntryExists() const; - void pushFileAllocationEntry(const FileAllocationEntryHandle& entry) - { - _fileAllocationEntries.push_back(entry); - } + FileAllocationEntryHandle popNextFileAllocationEntry(); - int32_t countFileAllocationEntryInQueue() const - { - return _fileAllocationEntries.size(); - } + void pushFileAllocationEntry(const FileAllocationEntryHandle& entry); + + int32_t countFileAllocationEntryInQueue() const; }; typedef SharedHandle FileAllocationManHandle; diff --git a/src/FileEntry.cc b/src/FileEntry.cc index d0c72de0..548f1123 100644 --- a/src/FileEntry.cc +++ b/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; +} diff --git a/src/FileEntry.h b/src/FileEntry.h index b395ce84..af475ab9 100644 --- a/src/FileEntry.h +++ b/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(); diff --git a/src/FillRequestGroupCommand.cc b/src/FillRequestGroupCommand.cc index 5c4b6399..85786af8 100644 --- a/src/FillRequestGroupCommand.cc +++ b/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); diff --git a/src/FillRequestGroupCommand.h b/src/FillRequestGroupCommand.h index 68ffa9d2..bc2ff3b0 100644 --- a/src/FillRequestGroupCommand.h +++ b/src/FillRequestGroupCommand.h @@ -37,8 +37,11 @@ #include "Command.h" #include "TimeA2.h" -#include "RequestGroup.h" -#include "DownloadEngine.h" + +class RequestGroup; +extern typedef SharedHandle RequestGroupHandle; +extern typedef deque 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(); diff --git a/src/FtpConnection.cc b/src/FtpConnection.cc index 39d8ef82..f87d37b7 100644 --- a/src/FtpConnection.cc +++ b/src/FtpConnection.cc @@ -34,8 +34,6 @@ /* copyright --> */ #include "FtpConnection.h" #include "Util.h" -#include "DlAbortEx.h" -#include "DlRetryEx.h" #include "message.h" #include "prefs.h" #include "LogFactory.h" @@ -48,19 +46,25 @@ FtpConnection::FtpConnection(int32_t cuid, const SocketHandle& socket, FtpConnection::~FtpConnection() {} -void FtpConnection::sendUser() const { +void FtpConnection::sendUser() const + throw(DlRetryEx*) +{ string request = "USER "+req->resolveFtpAuthConfig()->getUser()+"\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, request.c_str()); socket->writeData(request); } -void FtpConnection::sendPass() const { +void FtpConnection::sendPass() const + throw(DlRetryEx*) +{ string request = "PASS "+req->resolveFtpAuthConfig()->getPassword()+"\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, "PASS ********"); socket->writeData(request); } -void FtpConnection::sendType() const { +void FtpConnection::sendType() const + throw(DlRetryEx*) +{ string type; if(option->get(PREF_FTP_TYPE) == V_ASCII) { type = "A"; @@ -72,25 +76,33 @@ void FtpConnection::sendType() const { socket->writeData(request); } -void FtpConnection::sendCwd() const { - string request = "CWD "+req->getDir()+"\r\n"; +void FtpConnection::sendCwd() const + throw(DlRetryEx*) +{ + string request = "CWD "+Util::urldecode(req->getDir())+"\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, request.c_str()); socket->writeData(request); } -void FtpConnection::sendSize() const { - string request = "SIZE "+req->getFile()+"\r\n"; +void FtpConnection::sendSize() const + throw(DlRetryEx*) +{ + string request = "SIZE "+Util::urldecode(req->getFile())+"\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, request.c_str()); socket->writeData(request); } -void FtpConnection::sendPasv() const { +void FtpConnection::sendPasv() const + throw(DlRetryEx*) +{ string request = "PASV\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, request.c_str()); socket->writeData(request); } -SocketHandle FtpConnection::sendPort() const { +SocketHandle FtpConnection::sendPort() const + throw(DlAbortEx*, DlRetryEx*) +{ SocketHandle serverSocket; serverSocket->beginListen(); @@ -109,19 +121,24 @@ SocketHandle FtpConnection::sendPort() const { return serverSocket; } -void FtpConnection::sendRest(const SegmentHandle& segment) const { +void FtpConnection::sendRest(const SegmentHandle& segment) const + throw(DlRetryEx*) +{ string request = "REST "+Util::llitos(segment->getPositionToWrite())+"\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, request.c_str()); socket->writeData(request); } -void FtpConnection::sendRetr() const { - string request = "RETR "+req->getFile()+"\r\n"; +void FtpConnection::sendRetr() const + throw(DlRetryEx*) +{ + string request = "RETR "+Util::urldecode(req->getFile())+"\r\n"; logger->info(MSG_SENDING_REQUEST, cuid, request.c_str()); socket->writeData(request); } -int32_t FtpConnection::getStatus(const string& response) const { +int32_t FtpConnection::getStatus(const string& response) const +{ int32_t status; // When the response is not like "%d %*s", // we return 0. @@ -136,7 +153,8 @@ int32_t FtpConnection::getStatus(const string& response) const { } } -bool FtpConnection::isEndOfResponse(int32_t status, const string& response) const { +bool FtpConnection::isEndOfResponse(int32_t status, const string& response) const +{ if(response.size() <= 4) { return false; } @@ -156,7 +174,9 @@ bool FtpConnection::isEndOfResponse(int32_t status, const string& response) cons } } -bool FtpConnection::bulkReceiveResponse(pair& response) { +bool FtpConnection::bulkReceiveResponse(pair& response) + throw(DlRetryEx*) +{ char buf[1024]; while(socket->isReadable(0)) { int32_t size = sizeof(buf)-1; @@ -188,7 +208,9 @@ bool FtpConnection::bulkReceiveResponse(pair& response) { } } -int32_t FtpConnection::receiveResponse() { +int32_t FtpConnection::receiveResponse() + throw(DlRetryEx*) +{ pair response; if(bulkReceiveResponse(response)) { return response.first; @@ -197,7 +219,9 @@ int32_t FtpConnection::receiveResponse() { } } -int32_t FtpConnection::receiveSizeResponse(int64_t& size) { +int32_t FtpConnection::receiveSizeResponse(int64_t& size) + throw(DlRetryEx*) +{ pair response; if(bulkReceiveResponse(response)) { if(response.first == 213) { @@ -209,7 +233,9 @@ int32_t FtpConnection::receiveSizeResponse(int64_t& size) { } } -int32_t FtpConnection::receivePasvResponse(pair& dest) { +int32_t FtpConnection::receivePasvResponse(pair& dest) + throw(DlRetryEx*) +{ pair response; if(bulkReceiveResponse(response)) { if(response.first == 227) { diff --git a/src/FtpConnection.h b/src/FtpConnection.h index 766d3720..6d3a17dc 100644 --- a/src/FtpConnection.h +++ b/src/FtpConnection.h @@ -35,16 +35,16 @@ #ifndef _D_FTP_CONNECTION_H_ #define _D_FTP_CONNECTION_H_ +#include "common.h" #include "Socket.h" #include "Option.h" #include "Logger.h" #include "Segment.h" #include "Request.h" -#include "common.h" +#include "DlAbortEx.h" +#include "DlRetryEx.h" #include -using namespace std; - class FtpConnection { private: int32_t cuid; @@ -57,24 +57,24 @@ private: int32_t getStatus(const string& response) const; bool isEndOfResponse(int32_t status, const string& response) const; - bool bulkReceiveResponse(pair& response); + bool bulkReceiveResponse(pair& response) throw(DlRetryEx*); public: FtpConnection(int32_t cuid, const SocketHandle& socket, const RequestHandle req, const Option* op); ~FtpConnection(); - void sendUser() const; - void sendPass() const; - void sendType() const; - void sendCwd() const; - void sendSize() const; - void sendPasv() const; - SocketHandle sendPort() const; - void sendRest(const SegmentHandle& segment) const; - void sendRetr() const; + void sendUser() const throw(DlRetryEx*); + void sendPass() const throw(DlRetryEx*); + void sendType() const throw(DlRetryEx*); + void sendCwd() const throw(DlRetryEx*); + void sendSize() const throw(DlRetryEx*); + void sendPasv() const throw(DlRetryEx*); + SocketHandle sendPort() const throw(DlAbortEx*, DlRetryEx*); + void sendRest(const SegmentHandle& segment) const throw(DlRetryEx*); + void sendRetr() const throw(DlRetryEx*); - int32_t receiveResponse(); - int32_t receiveSizeResponse(int64_t& size); - int32_t receivePasvResponse(pair& dest); + int32_t receiveResponse() throw(DlRetryEx*); + int32_t receiveSizeResponse(int64_t& size) throw(DlRetryEx*); + int32_t receivePasvResponse(pair& dest) throw(DlRetryEx*); }; #endif // _D_FTP_CONNECTION_H_ diff --git a/src/FtpDownloadCommand.cc b/src/FtpDownloadCommand.cc index e1c6ef8e..c2bb39a5 100644 --- a/src/FtpDownloadCommand.cc +++ b/src/FtpDownloadCommand.cc @@ -33,6 +33,7 @@ */ /* copyright --> */ #include "FtpDownloadCommand.h" +#include "Request.h" FtpDownloadCommand::FtpDownloadCommand(int cuid, const RequestHandle req, diff --git a/src/FtpInitiateConnectionCommand.cc b/src/FtpInitiateConnectionCommand.cc index 4837769e..466bff9b 100644 --- a/src/FtpInitiateConnectionCommand.cc +++ b/src/FtpInitiateConnectionCommand.cc @@ -33,6 +33,11 @@ */ /* copyright --> */ #include "FtpInitiateConnectionCommand.h" +#include "NameResolver.h" +#include "DownloadEngine.h" +#include "RequestGroup.h" +#include "Option.h" +#include "Request.h" #include "FtpNegotiationCommand.h" #include "HttpRequestCommand.h" #include "FtpTunnelRequestCommand.h" @@ -111,3 +116,10 @@ bool FtpInitiateConnectionCommand::useHttpProxyGet() const { bool FtpInitiateConnectionCommand::useHttpProxyConnect() const { return useHttpProxy() && e->option->get(PREF_FTP_VIA_HTTP_PROXY) == V_TUNNEL; } + +#ifdef ENABLE_ASYNC_DNS +bool FtpInitiateConnectionCommand::nameResolveFinished() const { + return nameResolver->getStatus() == NameResolver::STATUS_SUCCESS || + nameResolver->getStatus() == NameResolver::STATUS_ERROR; +} +#endif // ENABLE_ASYNC_DNS diff --git a/src/FtpInitiateConnectionCommand.h b/src/FtpInitiateConnectionCommand.h index acda5af0..9bcdd55a 100644 --- a/src/FtpInitiateConnectionCommand.h +++ b/src/FtpInitiateConnectionCommand.h @@ -44,10 +44,7 @@ private: bool useHttpProxyGet() const; bool useHttpProxyConnect() const; #ifdef ENABLE_ASYNC_DNS - virtual bool nameResolveFinished() const { - return nameResolver->getStatus() == NameResolver::STATUS_SUCCESS || - nameResolver->getStatus() == NameResolver::STATUS_ERROR; - } + virtual bool nameResolveFinished() const; #endif // ENABLE_ASYNC_DNS protected: virtual bool executeInternal(); diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc index 4b5c3008..fed6658a 100644 --- a/src/FtpNegotiationCommand.cc +++ b/src/FtpNegotiationCommand.cc @@ -33,13 +33,17 @@ */ /* copyright --> */ #include "FtpNegotiationCommand.h" +#include "DownloadEngine.h" +#include "FtpConnection.h" +#include "RequestGroup.h" +#include "PieceStorage.h" #include "FtpDownloadCommand.h" #include "DlAbortEx.h" #include "DlRetryEx.h" #include "message.h" #include "prefs.h" #include "Util.h" -#include "FatalException.h" +#include "SingleFileDownloadContext.h" FtpNegotiationCommand::FtpNegotiationCommand(int32_t cuid, const RequestHandle& req, @@ -189,28 +193,29 @@ bool FtpNegotiationCommand::recvSize() { if(size == INT64_MAX || size < 0) { throw new DlAbortEx(EX_TOO_LARGE_FILE, Util::llitos(size, true).c_str()); } - if(!_requestGroup->getSegmentMan()->downloadStarted) { - _requestGroup->getSegmentMan()->downloadStarted = true; - _requestGroup->getSegmentMan()->totalSize = size; - _requestGroup->getSegmentMan()->filename = Util::urldecode(req->getFile()); + if(_requestGroup->getPieceStorage().isNull()) { + SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setTotalLength(size); + SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setFilename(Util::urldecode(req->getFile())); + + initPieceStorage(); // TODO validate filename and totalsize against hintFilename and hintTotalSize if these are provided. _requestGroup->validateTotalLengthByHint(size); if(req->getMethod() == Request::METHOD_HEAD) { - _requestGroup->getSegmentMan()->isSplittable = false; // TODO because we don't want segment file to be saved. + //_requestGroup->getSegmentMan()->isSplittable = false; // TODO because we don't want segment file to be saved. sequence = SEQ_HEAD_OK; return false; } if(e->option->get(PREF_CHECK_INTEGRITY) != V_TRUE) { - if(_requestGroup->downloadFinishedByFileLength()) { + if(downloadFinishedByFileLength()) { logger->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, cuid, _requestGroup->getFilePath().c_str()); sequence = SEQ_DOWNLOAD_ALREADY_COMPLETED; return false; } } - _requestGroup->loadAndOpenFile(); - _requestGroup->prepareForNextAction(cuid, req, e); + loadAndOpenFile(); + prepareForNextAction(); sequence = SEQ_FILE_PREPARATION; e->noWait = true; diff --git a/src/FtpNegotiationCommand.h b/src/FtpNegotiationCommand.h index 6b9fc8c6..3f158983 100644 --- a/src/FtpNegotiationCommand.h +++ b/src/FtpNegotiationCommand.h @@ -36,7 +36,8 @@ #define _D_FTP_NEGOTIATION_COMMAND_H_ #include "AbstractCommand.h" -#include "FtpConnection.h" + +class FtpConnection; class FtpNegotiationCommand : public AbstractCommand { private: diff --git a/src/GrowSegment.cc b/src/GrowSegment.cc new file mode 100644 index 00000000..b772fe80 --- /dev/null +++ b/src/GrowSegment.cc @@ -0,0 +1,54 @@ +/* */ +#include "GrowSegment.h" +#include "Piece.h" + +GrowSegment::GrowSegment(const PieceHandle& piece): + _piece(piece), _writtenLength(0) {} + +GrowSegment::~GrowSegment() {} + +void GrowSegment::updateWrittenLength(int32_t bytes) +{ + _writtenLength += bytes; + _piece->reconfigure(_writtenLength); + _piece->setAllBlock(); +} + +PieceHandle GrowSegment::getPiece() const +{ + return _piece; +} + diff --git a/src/GrowSegment.h b/src/GrowSegment.h new file mode 100644 index 00000000..85f567ec --- /dev/null +++ b/src/GrowSegment.h @@ -0,0 +1,97 @@ +/* */ +#ifndef _D_GROW_SEGMENT_H_ +#define _D_GROW_SEGMENT_H_ + +#include "Segment.h" + +class GrowSegment:public Segment { +private: + PieceHandle _piece; + int32_t _writtenLength; +public: + GrowSegment(const PieceHandle& piece); + + virtual ~GrowSegment(); + + virtual bool complete() const + { + return false; + } + + virtual int32_t getIndex() const + { + return 0; + } + + virtual int64_t getPosition() const + { + return 0; + } + + virtual int64_t getPositionToWrite() const + { + return _writtenLength; + } + + virtual int32_t getLength() const + { + return 0; + } + + virtual int32_t getSegmentLength() const + { + return 0; + } + + virtual int32_t getWrittenLength() const + { + return _writtenLength; + } + + virtual int32_t getOverflowLength() const + { + return 0; + } + + virtual void updateWrittenLength(int32_t bytes); + + virtual PieceHandle getPiece() const; +}; + +typedef SharedHandle GrowSegmentHandle; + +#endif // _D_GROW_SEGMENT_H_ + diff --git a/src/HaveEraseCommand.cc b/src/HaveEraseCommand.cc index ecb209c9..c901829f 100644 --- a/src/HaveEraseCommand.cc +++ b/src/HaveEraseCommand.cc @@ -33,23 +33,29 @@ */ /* copyright --> */ #include "HaveEraseCommand.h" +#include "DownloadEngine.h" +#include "RequestGroupMan.h" +#include "PieceStorage.h" +#include "RequestGroup.h" -HaveEraseCommand::HaveEraseCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext, - int32_t interval) - :BtContextAwareCommand(cuid, btContext), - e(e), - interval(interval) {} +HaveEraseCommand::HaveEraseCommand(int32_t cuid, DownloadEngine* e, int32_t interval) + :TimeBasedCommand(cuid, e, interval) {} -bool HaveEraseCommand::execute() { - if(btRuntime->isHalt()) { - return true; +HaveEraseCommand::~HaveEraseCommand() {} + +void HaveEraseCommand::preProcess() +{ + if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) { + _exit = true; + } +} + +void HaveEraseCommand::process() +{ + for(int32_t i = 0; i < _e->_requestGroupMan->countRequestGroup(); ++i) { + PieceStorageHandle ps = _e->_requestGroupMan->getRequestGroup(i)->getPieceStorage(); + if(!ps.isNull()) { + ps->removeAdvertisedPiece(5); + } } - if(cp.elapsed(interval)) { - cp.reset(); - pieceStorage->removeAdvertisedPiece(5); - } - e->commands.push_back(this); - return false; } diff --git a/src/HaveEraseCommand.h b/src/HaveEraseCommand.h index 4875df23..ff713583 100644 --- a/src/HaveEraseCommand.h +++ b/src/HaveEraseCommand.h @@ -35,23 +35,18 @@ #ifndef _D_HAVE_ERASE_COMMAND_H_ #define _D_HAVE_ERASE_COMMAND_H_ -#include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" +#include "TimeBasedCommand.h" -class HaveEraseCommand : public BtContextAwareCommand { -private: - TorrentDownloadEngine* e; - Time cp; - int32_t interval; +class HaveEraseCommand : public TimeBasedCommand +{ public: - HaveEraseCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext, - int32_t interval); + HaveEraseCommand(int32_t cuid, DownloadEngine* e, int32_t interval); - virtual ~HaveEraseCommand() {} + virtual ~HaveEraseCommand(); - virtual bool execute(); + virtual void preProcess(); + + virtual void process(); }; #endif // _D_HAVE_ERASE_COMMAND_H_ diff --git a/src/HttpConnection.cc b/src/HttpConnection.cc index 6f0e2c67..74362823 100644 --- a/src/HttpConnection.cc +++ b/src/HttpConnection.cc @@ -33,10 +33,7 @@ */ /* copyright --> */ #include "HttpConnection.h" -#include "DlRetryEx.h" -#include "DlAbortEx.h" #include "Util.h" -#include "Base64.h" #include "message.h" #include "prefs.h" #include "LogFactory.h" @@ -66,6 +63,7 @@ string HttpConnection::eraseConfidentialInfo(const string& request) } void HttpConnection::sendRequest(const HttpRequestHandle& httpRequest) + throw(DlRetryEx*) { string request = httpRequest->createRequest(); logger->info(MSG_SENDING_REQUEST, cuid, eraseConfidentialInfo(request).c_str()); @@ -75,6 +73,7 @@ void HttpConnection::sendRequest(const HttpRequestHandle& httpRequest) } void HttpConnection::sendProxyRequest(const HttpRequestHandle& httpRequest) + throw(DlRetryEx*) { string request = httpRequest->createProxyRequest(); logger->info(MSG_SENDING_REQUEST, cuid, eraseConfidentialInfo(request).c_str()); @@ -83,7 +82,9 @@ void HttpConnection::sendProxyRequest(const HttpRequestHandle& httpRequest) new HttpHeaderProcessor())); } -HttpResponseHandle HttpConnection::receiveResponse() { +HttpResponseHandle HttpConnection::receiveResponse() + throw(DlAbortEx*, DlRetryEx*) +{ if(outstandingHttpRequests.size() == 0) { throw new DlAbortEx(EX_NO_HTTP_REQUEST_ENTRY_FOUND); } diff --git a/src/HttpConnection.h b/src/HttpConnection.h index f007ccc9..de723838 100644 --- a/src/HttpConnection.h +++ b/src/HttpConnection.h @@ -44,6 +44,8 @@ #include "Logger.h" #include "HttpResponse.h" #include "HttpHeaderProcessor.h" +#include "DlRetryEx.h" +#include "DlAbortEx.h" class HttpRequestEntry { private: @@ -93,12 +95,12 @@ public: * HTTP proxy(GET method). * @param segment indicates starting postion of the file for downloading */ - void sendRequest(const HttpRequestHandle& httpRequest); + void sendRequest(const HttpRequestHandle& httpRequest) throw(DlRetryEx*); /** * Sends Http proxy request using CONNECT method. */ - void sendProxyRequest(const HttpRequestHandle& httpRequest); + void sendProxyRequest(const HttpRequestHandle& httpRequest) throw(DlRetryEx*); /** * Receives HTTP response from the server and returns HttpResponseHandle @@ -111,7 +113,7 @@ public: * * @return HttpResponse or 0 if whole response header is not received */ - HttpResponseHandle receiveResponse(); + HttpResponseHandle receiveResponse() throw(DlAbortEx*, DlRetryEx*); HttpRequestHandle getFirstHttpRequest() const { diff --git a/src/HttpDownloadCommand.cc b/src/HttpDownloadCommand.cc index de4d6f27..0993b94c 100644 --- a/src/HttpDownloadCommand.cc +++ b/src/HttpDownloadCommand.cc @@ -33,6 +33,9 @@ */ /* copyright --> */ #include "HttpDownloadCommand.h" +#include "RequestGroup.h" +#include "DownloadEngine.h" +#include "Request.h" #include "HttpRequestCommand.h" #include "Util.h" #include "message.h" @@ -47,7 +50,7 @@ HttpDownloadCommand::HttpDownloadCommand(int cuid, HttpDownloadCommand::~HttpDownloadCommand() {} bool HttpDownloadCommand::prepareForNextSegment() { - if(!_requestGroup->getSegmentMan()->finished()) { + if(!_requestGroup->downloadFinished()) { if(req->isKeepAlive()) { Command* command = new HttpRequestCommand(cuid, req, _requestGroup, e, socket); e->commands.push_back(command); diff --git a/src/HttpHeaderProcessor.cc b/src/HttpHeaderProcessor.cc index 23e97411..51b83fad 100644 --- a/src/HttpHeaderProcessor.cc +++ b/src/HttpHeaderProcessor.cc @@ -34,23 +34,24 @@ /* copyright --> */ #include "HttpHeaderProcessor.h" #include "message.h" -#include "DlRetryEx.h" -#include "DlAbortEx.h" #include "Util.h" void HttpHeaderProcessor::update(const char* data, int32_t length) + throw(DlAbortEx*) { checkHeaderLimit(length); strm.write(data, length); } void HttpHeaderProcessor::update(const string& data) + throw(DlAbortEx*) { checkHeaderLimit(data.size()); strm << data; } void HttpHeaderProcessor::checkHeaderLimit(int32_t incomingLength) + throw(DlAbortEx*) { strm.seekg(0, ios::end); if((int32_t)strm.tellg()+incomingLength > _limit) { @@ -87,6 +88,7 @@ void HttpHeaderProcessor::clear() } pair HttpHeaderProcessor::getHttpStatusHeader() + throw(DlRetryEx*) { strm.seekg(0, ios::beg); string line; diff --git a/src/HttpHeaderProcessor.h b/src/HttpHeaderProcessor.h index 51491602..59ffa4d8 100644 --- a/src/HttpHeaderProcessor.h +++ b/src/HttpHeaderProcessor.h @@ -37,6 +37,8 @@ #include "common.h" #include "HttpHeader.h" +#include "DlRetryEx.h" +#include "DlAbortEx.h" #include #include @@ -45,16 +47,16 @@ private: stringstream strm; int32_t _limit; - void checkHeaderLimit(int32_t incomingLength); + void checkHeaderLimit(int32_t incomingLength) throw(DlAbortEx*); public: HttpHeaderProcessor():_limit(4096) {} ~HttpHeaderProcessor() {} - void update(const char* data, int32_t length); + void update(const char* data, int32_t length) throw(DlAbortEx*); - void update(const string& data); + void update(const string& data) throw(DlAbortEx*); /** * Returns true if end of header is reached. @@ -66,7 +68,7 @@ public: */ int32_t getPutBackDataLength() const; - pair getHttpStatusHeader(); + pair getHttpStatusHeader() throw(DlRetryEx*); string getHeaderString() const; diff --git a/src/HttpInitiateConnectionCommand.cc b/src/HttpInitiateConnectionCommand.cc index 707ff73e..a3680eb2 100644 --- a/src/HttpInitiateConnectionCommand.cc +++ b/src/HttpInitiateConnectionCommand.cc @@ -33,6 +33,10 @@ */ /* copyright --> */ #include "HttpInitiateConnectionCommand.h" +#include "NameResolver.h" +#include "DownloadEngine.h" +#include "Option.h" +#include "Request.h" #include "HttpRequestCommand.h" #include "HttpProxyRequestCommand.h" #include "Util.h" @@ -110,3 +114,10 @@ bool HttpInitiateConnectionCommand::useProxyGet() { bool HttpInitiateConnectionCommand::useProxyTunnel() { return e->option->get(PREF_HTTP_PROXY_METHOD) == V_TUNNEL; } + +#ifdef ENABLE_ASYNC_DNS +bool HttpInitiateConnectionCommand::nameResolveFinished() const { + return nameResolver->getStatus() == NameResolver::STATUS_SUCCESS || + nameResolver->getStatus() == NameResolver::STATUS_ERROR; +} +#endif // ENABLE_ASYNC_DNS diff --git a/src/HttpInitiateConnectionCommand.h b/src/HttpInitiateConnectionCommand.h index b77ede4e..fa0fa596 100644 --- a/src/HttpInitiateConnectionCommand.h +++ b/src/HttpInitiateConnectionCommand.h @@ -54,10 +54,7 @@ protected: */ virtual bool executeInternal(); #ifdef ENABLE_ASYNC_DNS - virtual bool nameResolveFinished() const { - return nameResolver->getStatus() == NameResolver::STATUS_SUCCESS || - nameResolver->getStatus() == NameResolver::STATUS_ERROR; - } + virtual bool nameResolveFinished() const; #endif // ENABLE_ASYNC_DNS public: HttpInitiateConnectionCommand(int cuid, const RequestHandle& req, RequestGroup* requestGroup, DownloadEngine* e); diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 603523d8..942f6947 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -40,7 +40,7 @@ RangeHandle HttpRequest::getRange() const { // content-length is always 0 - if(segment->isNull()) { + if(segment.isNull()) { return new Range(0, 0, 0); } else { return new Range(getStartByte(), getEndByte(), entityLength); @@ -49,7 +49,7 @@ RangeHandle HttpRequest::getRange() const bool HttpRequest::isRangeSatisfied(const RangeHandle& range) const { - if(segment->isNull()) { + if(segment.isNull()) { return true; } if(getStartByte() == range->getStartByte() && @@ -83,7 +83,7 @@ string HttpRequest::createRequest() const } requestLine += string(" HTTP/1.1\r\n")+ - "User-Agent: "+Util::urlencode(userAgent)+"\r\n"+ + "User-Agent: "+userAgent+"\r\n"+ "Accept: */*\r\n"+ /* */ "Host: "+getHostText(getHost(), getPort())+"\r\n"+ "Pragma: no-cache\r\n"+ @@ -91,7 +91,8 @@ string HttpRequest::createRequest() const if(!request->isKeepAlive()) { requestLine += "Connection: close\r\n"; } - if(segment->length > 0) { + if(!segment.isNull() && segment->getLength() > 0 && + (request->isKeepAlive() || getStartByte() > 0)) { requestLine += "Range: bytes="+Util::llitos(getStartByte()); requestLine += "-"; if(request->isKeepAlive()) { @@ -112,7 +113,6 @@ string HttpRequest::createRequest() const if(getPreviousURI().size()) { requestLine += "Referer: "+getPreviousURI()+"\r\n"; } - string cookiesValue; Cookies cookies = request->cookieBox->criteriaFind(getHost(), getDir(), diff --git a/src/HttpRequest.h b/src/HttpRequest.h index b943d2ea..488bacd3 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -168,7 +168,7 @@ public: return 0; } else { if(request->isKeepAlive()) { - return segment->getPosition()+segment->length-1; + return segment->getPosition()+segment->getLength()-1; } else { return 0; } diff --git a/src/HttpRequestCommand.cc b/src/HttpRequestCommand.cc index b708dfd0..b5559715 100644 --- a/src/HttpRequestCommand.cc +++ b/src/HttpRequestCommand.cc @@ -33,6 +33,8 @@ */ /* copyright --> */ #include "HttpRequestCommand.h" +#include "DownloadEngine.h" +#include "RequestGroup.h" #include "HttpResponseCommand.h" #include "HttpConnection.h" #include "prefs.h" @@ -61,7 +63,7 @@ bool HttpRequestCommand::executeInternal() { httpRequest->setUserAgent(e->option->get(PREF_USER_AGENT)); httpRequest->setRequest(req); httpRequest->setSegment(segment); - httpRequest->setEntityLength(_requestGroup->getSegmentMan()->totalSize); + httpRequest->setEntityLength(_requestGroup->getTotalLength()); httpRequest->configure(e->option); HttpConnectionHandle httpConnection = new HttpConnection(cuid, socket, e->option); diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc index 3a75da50..6badc86e 100644 --- a/src/HttpResponse.cc +++ b/src/HttpResponse.cc @@ -33,13 +33,12 @@ */ /* copyright --> */ #include "HttpResponse.h" -#include "DlAbortEx.h" -#include "DlRetryEx.h" #include "ChunkedEncoding.h" #include "Util.h" #include "message.h" void HttpResponse::validateResponse() const + throw(DlAbortEx*, DlRetryEx*) { if(status == 401) { throw new DlAbortEx(EX_AUTH_FAILED); diff --git a/src/HttpResponse.h b/src/HttpResponse.h index ac7afc9f..09a38b09 100644 --- a/src/HttpResponse.h +++ b/src/HttpResponse.h @@ -40,6 +40,8 @@ #include "HttpHeader.h" #include "TransferEncoding.h" #include "LogFactory.h" +#include "DlAbortEx.h" +#include "DlRetryEx.h" class HttpResponse { private: @@ -58,7 +60,7 @@ public: ~HttpResponse() {} - void validateResponse() const; + void validateResponse() const throw(DlAbortEx*, DlRetryEx*); /** * Returns filename. diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 8a29619a..95dae918 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -33,6 +33,10 @@ */ /* copyright --> */ #include "HttpResponseCommand.h" +#include "DownloadEngine.h" +#include "HttpResponse.h" +#include "HttpConnection.h" +#include "SegmentMan.h" #include "DlAbortEx.h" #include "DlRetryEx.h" #include "HttpDownloadCommand.h" @@ -41,7 +45,9 @@ #include "prefs.h" #include "File.h" #include "InitiateConnectionCommandFactory.h" -#include "FatalException.h" +#include "SingleFileDownloadContext.h" +#include "DiskAdaptor.h" +#include "PieceStorage.h" #include #include @@ -59,10 +65,6 @@ HttpResponseCommand::~HttpResponseCommand() {} bool HttpResponseCommand::executeInternal() { HttpRequestHandle httpRequest = httpConnection->getFirstHttpRequest(); - if(!(httpRequest->getSegment() == segment)) { - logger->info(MSG_SEGMENT_CHANGED, cuid); - return prepareForRetry(0); - } HttpResponseHandle httpResponse = httpConnection->receiveResponse(); if(httpResponse.isNull()) { // The server has not responded to our request yet. @@ -87,7 +89,7 @@ bool HttpResponseCommand::executeInternal() e->noWait = true; return prepareForRetry(0); } - if(_requestGroup->getSegmentMan()->downloadStarted) { + if(!_requestGroup->getPieceStorage().isNull()) { // validate totalsize _requestGroup->validateFilename(httpResponse->determinFilename()); _requestGroup->validateTotalLength(httpResponse->getEntityLength()); @@ -99,7 +101,7 @@ bool HttpResponseCommand::executeInternal() _requestGroup->validateFilenameByHint(httpResponse->determinFilename()); _requestGroup->validateTotalLengthByHint(httpResponse->getEntityLength()); - _requestGroup->getSegmentMan()->filename = httpResponse->determinFilename(); + SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setFilename(httpResponse->determinFilename()); if(httpResponse->isTransferEncodingSpecified()) { return handleOtherEncoding(httpResponse); } else { @@ -111,27 +113,26 @@ bool HttpResponseCommand::executeInternal() bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpResponse) { HttpRequestHandle httpRequest = httpResponse->getHttpRequest(); - // TODO quick and dirty way - if(_requestGroup->isTorrent) { - return doTorrentStuff(httpResponse); - } int64_t size = httpResponse->getEntityLength(); if(size == INT64_MAX || size < 0) { throw new DlAbortEx(EX_TOO_LARGE_FILE, Util::llitos(size, true).c_str()); } - _requestGroup->getSegmentMan()->isSplittable = !(size == 0); - _requestGroup->getSegmentMan()->downloadStarted = true; - _requestGroup->getSegmentMan()->totalSize = size; - + //_requestGroup->getSegmentMan()->isSplittable = !(size == 0); + //_requestGroup->getSegmentMan()->totalSize = size; + //_requestGroup->getSegmentMan()->initDownloadContext(size); + + SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setTotalLength(size); + initPieceStorage(); + // quick hack for method 'head' if(httpRequest->getMethod() == Request::METHOD_HEAD) { // TODO because we don't want segment file to be saved. - _requestGroup->getSegmentMan()->isSplittable = false; + //_requestGroup->getSegmentMan()->isSplittable = false; return true; } if(e->option->get(PREF_CHECK_INTEGRITY) != V_TRUE) { - if(_requestGroup->downloadFinishedByFileLength()) { + if(downloadFinishedByFileLength()) { logger->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, cuid, _requestGroup->getFilePath().c_str()); return true; } @@ -143,8 +144,8 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpRe if(_requestGroup->getRemainingUris().empty() && !file.exists()) { command = createHttpDownloadCommand(httpResponse); } - _requestGroup->loadAndOpenFile(); - _requestGroup->prepareForNextAction(cuid, req, e, command); + loadAndOpenFile(); + prepareForNextAction(command); e->noWait = true; } catch(Exception* e) { delete command; @@ -156,18 +157,22 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpRe bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResponse) { HttpRequestHandle httpRequest = httpResponse->getHttpRequest(); // we ignore content-length when transfer-encoding is set - _requestGroup->getSegmentMan()->downloadStarted = true; - _requestGroup->getSegmentMan()->isSplittable = false; - _requestGroup->getSegmentMan()->totalSize = 0; + //_requestGroup->getSegmentMan()->isSplittable = false; + //_requestGroup->getSegmentMan()->totalSize = 0; // quick hack for method 'head' if(httpRequest->getMethod() == Request::METHOD_HEAD) { return true; } // disable keep-alive req->setKeepAlive(false); - segment = _requestGroup->getSegmentMan()->getSegment(cuid); - _requestGroup->shouldCancelDownloadForSafety(); - _requestGroup->getSegmentMan()->diskWriter->initAndOpenFile(_requestGroup->getSegmentMan()->getFilePath()); + + initPieceStorage(); + + //segment = _requestGroup->getSegmentMan()->getSegment(cuid); + + shouldCancelDownloadForSafety(); + // TODO handle file-size unknown case + _requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();//_requestGroup->getFilePath()); e->commands.push_back(createHttpDownloadCommand(httpResponse)); return true; } @@ -192,20 +197,3 @@ HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand(const HttpRe return command; } - -bool HttpResponseCommand::doTorrentStuff(const HttpResponseHandle& httpResponse) -{ - int64_t size = httpResponse->getEntityLength(); - _requestGroup->getSegmentMan()->totalSize = size; - if(size > 0) { - _requestGroup->getSegmentMan()->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE), - _requestGroup->getSegmentMan()->totalSize); - } - // disable keep-alive - httpResponse->getHttpRequest()->getRequest()->setKeepAlive(false); - _requestGroup->getSegmentMan()->isSplittable = false; - _requestGroup->getSegmentMan()->downloadStarted = true; - _requestGroup->getSegmentMan()->diskWriter->initAndOpenFile("/tmp/aria2"+Util::itos((int32_t)getpid())); - e->commands.push_back(createHttpDownloadCommand(httpResponse)); - return true; -} diff --git a/src/HttpResponseCommand.h b/src/HttpResponseCommand.h index f2c77061..18c3102e 100644 --- a/src/HttpResponseCommand.h +++ b/src/HttpResponseCommand.h @@ -36,8 +36,12 @@ #define _D_HTTP_RESPONSE_COMMAND_H_ #include "AbstractCommand.h" -#include "HttpConnection.h" -#include "HttpDownloadCommand.h" + +class HttpConnection; +extern typedef SharedHandle HttpConnectionHandle; +class HttpDownloadCommand; +class HttpResponse; +extern typedef SharedHandle HttpResponseHandle; class HttpResponseCommand : public AbstractCommand { private: @@ -46,7 +50,6 @@ private: bool handleDefaultEncoding(const HttpResponseHandle& httpResponse); bool handleOtherEncoding(const HttpResponseHandle& httpResponse); HttpDownloadCommand* createHttpDownloadCommand(const HttpResponseHandle& httpResponse); - bool doTorrentStuff(const HttpResponseHandle& httpResponse); protected: bool executeInternal(); public: diff --git a/src/IteratableChecksumValidator.cc b/src/IteratableChecksumValidator.cc index 545d4328..d99acb16 100644 --- a/src/IteratableChecksumValidator.cc +++ b/src/IteratableChecksumValidator.cc @@ -42,7 +42,7 @@ void IteratableChecksumValidator::validateChunk() { if(!finished()) { - char data[BUFSIZE]; + unsigned char data[BUFSIZE]; int32_t size = _diskWriter->readData(data, sizeof(data), _currentOffset); diff --git a/src/IteratableChunkChecksumValidator.cc b/src/IteratableChunkChecksumValidator.cc index 0e43acc3..02d3a4ce 100644 --- a/src/IteratableChunkChecksumValidator.cc +++ b/src/IteratableChunkChecksumValidator.cc @@ -36,47 +36,57 @@ #include "Util.h" #include "message.h" #include "MessageDigestHelper.h" +#include "DiskAdaptor.h" void IteratableChunkChecksumValidator::validateChunk() { if(!finished()) { - string actualChecksum = calculateActualChecksum(); - - - if(!_chunkChecksum->validateChunk(actualChecksum, _currentIndex)) { - int64_t offset = ((int64_t)_currentIndex)*_chunkChecksum->getChecksumLength(); - // wrong checksum - logger->info(EX_INVALID_CHUNK_CHECKSUM, - _currentIndex, - Util::llitos(offset, true).c_str(), - _chunkChecksum->getChecksum(_currentIndex).c_str(), - actualChecksum.c_str()); - int32_t startIndex; - int32_t endIndex; - Util::indexRange(startIndex, endIndex, offset, - _chunkChecksum->getChecksumLength(), - _bitfield->getBlockLength()); - _bitfield->unsetBitRange(startIndex, endIndex); + string actualChecksum; + try { + actualChecksum = calculateActualChecksum(); + } catch(DlAbortEx* ex) { + _logger->debug("Caught exception while validating piece index=%d. Some part of file may be missing. Continue operation.", ex, _currentIndex); + delete ex; + _bitfield->unsetBit(_currentIndex); + _currentIndex++; + return; } - _currentIndex++; + if(actualChecksum == _dctx->getPieceHashes()[_currentIndex]) { + _bitfield->setBit(_currentIndex); + } else { + _logger->info(EX_INVALID_CHUNK_CHECKSUM, + _currentIndex, + Util::llitos(getCurrentOffset(), true).c_str(), + _dctx->getPieceHashes()[_currentIndex].c_str(), + actualChecksum.c_str()); + _bitfield->unsetBit(_currentIndex); + } + _currentIndex++; } } string IteratableChunkChecksumValidator::calculateActualChecksum() { - int64_t offset = ((int64_t)_currentIndex)*_chunkChecksum->getChecksumLength(); - int32_t length = _diskWriter->size() < offset+_chunkChecksum->getChecksumLength() ? _diskWriter->size()-offset : _chunkChecksum->getChecksumLength(); - return MessageDigestHelper::digest(_chunkChecksum->getAlgo(), _diskWriter, offset, length); -} - -bool IteratableChunkChecksumValidator::canValidate() const -{ - // We assume file is already opened using DiskWriter::open or openExistingFile. - return _chunkChecksum->getEstimatedDataLength() >= _diskWriter->size(); + int64_t offset = getCurrentOffset(); + int32_t length; + // When validating last piece + if(_currentIndex+1 == (uint32_t)_dctx->getNumPieces()) { + length = _dctx->getTotalLength()-offset; + } else { + length = _dctx->getPieceLength(); + } + return MessageDigestHelper::digest(_dctx->getPieceHashAlgo(), + _pieceStorage->getDiskAdaptor(), + offset, length); } void IteratableChunkChecksumValidator::init() { - _bitfield->setAllBit(); + _bitfield->clearAllBit(); _currentIndex = 0; } + +void IteratableChunkChecksumValidator::updatePieceStorage() +{ + _pieceStorage->setBitfield(_bitfield->getBitfield(), _bitfield->getBitfieldLength()); +} diff --git a/src/IteratableChunkChecksumValidator.h b/src/IteratableChunkChecksumValidator.h index 6e4bb4bc..75c2b2e1 100644 --- a/src/IteratableChunkChecksumValidator.h +++ b/src/IteratableChunkChecksumValidator.h @@ -36,25 +36,29 @@ #define _D_ITERATABLE_CHUNK_CHECKSUM_VALIDATOR_H_ #include "common.h" +#include "DownloadContext.h" +#include "PieceStorage.h" #include "BitfieldMan.h" -#include "ChunkChecksum.h" -#include "DiskWriter.h" #include "LogFactory.h" class IteratableChunkChecksumValidator { private: - DiskWriterHandle _diskWriter; + DownloadContextHandle _dctx; + PieceStorageHandle _pieceStorage; BitfieldMan* _bitfield; - int32_t _currentIndex; - ChunkChecksumHandle _chunkChecksum; - const Logger* logger; + uint32_t _currentIndex; + const Logger* _logger; string calculateActualChecksum(); public: - IteratableChunkChecksumValidator():_diskWriter(0), _bitfield(0), _currentIndex(0), _chunkChecksum(0), logger(LogFactory::getInstance()) {} - - bool canValidate() const; + IteratableChunkChecksumValidator(const DownloadContextHandle& dctx, + const PieceStorageHandle& pieceStorage): + _dctx(dctx), + _pieceStorage(pieceStorage), + _bitfield(new BitfieldMan(_dctx->getPieceLength(), _dctx->getTotalLength())), + _currentIndex(0), + _logger(LogFactory::getInstance()) {} void init(); @@ -62,38 +66,20 @@ public: bool finished() const { - return _currentIndex >= _chunkChecksum->countChecksum(); - } - - void setDiskWriter(const DiskWriterHandle& diskWriter) - { - _diskWriter = diskWriter; - } - - void setBitfield(BitfieldMan* bitfield) - { - _bitfield = bitfield; - } - - void setChunkChecksum(const ChunkChecksumHandle& chunkChecksum) - { - _chunkChecksum = chunkChecksum; + return _currentIndex >= (uint32_t)_dctx->getNumPieces(); } int64_t getCurrentOffset() const { - return ((int64_t)_currentIndex)*_chunkChecksum->getChecksumLength(); + return ((int64_t)_currentIndex)*_dctx->getPieceLength(); } int64_t getTotalLength() const { - return _bitfield->getTotalLength(); + return _dctx->getTotalLength(); } - ChunkChecksumHandle getChunkChecksum() - { - return _chunkChecksum; - } + void updatePieceStorage(); }; typedef SharedHandle IteratableChunkChecksumValidatorHandle; diff --git a/src/Makefile.am b/src/Makefile.am index 39441014..58c7446f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,7 @@ bin_PROGRAMS = aria2c -aria2c_SOURCES = main.cc +aria2c_SOURCES = main.cc\ + option_processing.cc\ + version_usage.cc SRCS = Socket.h\ SocketCore.cc SocketCore.h\ Command.cc Command.h\ @@ -22,8 +24,9 @@ SRCS = Socket.h\ FtpTunnelResponseCommand.cc FtpTunnelResponseCommand.h\ SleepCommand.cc SleepCommand.h\ DownloadEngine.cc DownloadEngine.h\ - ConsoleDownloadEngine.cc ConsoleDownloadEngine.h\ - Segment.cc Segment.h\ + Segment.h\ + GrowSegment.cc GrowSegment.h\ + PiecedSegment.cc PiecedSegment.h\ SegmentMan.cc SegmentMan.h\ Util.cc Util.h\ Request.cc Request.h\ @@ -60,8 +63,6 @@ SRCS = Socket.h\ Randomizer.h\ SimpleRandomizer.cc SimpleRandomizer.h\ FileAllocator.h\ - FileAllocationMonitor.cc FileAllocationMonitor.h\ - ConsoleFileAllocationMonitor.cc ConsoleFileAllocationMonitor.h\ HttpResponse.cc HttpResponse.h\ HttpRequest.cc HttpRequest.h\ Range.h\ @@ -74,17 +75,18 @@ SRCS = Socket.h\ DefaultAuthResolver.cc DefaultAuthResolver.h\ NetrcAuthResolver.cc NetrcAuthResolver.h\ RequestFactory.cc RequestFactory.h\ - DefaultFileAllocator.cc DefaultFileAllocator.h\ - GlowFileAllocator.cc GlowFileAllocator.h\ OptionParser.cc OptionParser.h\ OptionHandlerFactory.cc OptionHandlerFactory.h\ NameResolver.cc NameResolver.h\ RequestGroup.cc RequestGroup.h\ + RequestGroupAware.cc RequestGroupAware.h\ RequestGroupMan.cc RequestGroupMan.h\ + FileAllocationMan.cc FileAllocationMan.h\ FileAllocationCommand.cc FileAllocationCommand.h\ FillRequestGroupCommand.cc FillRequestGroupCommand.h\ FileAllocationDispatcherCommand.cc FileAllocationDispatcherCommand.h\ FileAllocationEntry.cc FileAllocationEntry.h\ + StreamFileAllocationEntry.cc StreamFileAllocationEntry.h\ MultiUrlRequestInfo.cc MultiUrlRequestInfo.h\ UriListParser.cc UriListParser.h\ SegmentManFactory.h\ @@ -110,17 +112,30 @@ SRCS = Socket.h\ NumberDecorator.h\ AlphaNumberDecorator.h\ TimeBasedCommand.cc TimeBasedCommand.h\ - AutoSaveCommand.cc AutoSaveCommand.h + AutoSaveCommand.cc AutoSaveCommand.h\ + UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h\ + StatCalc.h\ + ConsoleStatCalc.cc ConsoleStatCalc.h\ + TransferStat.cc TransferStat.h\ + Dependency.h\ + BtProgressInfoFile.h\ + DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ + NullProgressInfoFile.h\ + FileAllocationIterator.h\ + SingleFileAllocationIterator.cc SingleFileAllocationIterator.h\ + PostDownloadHandler.cc PostDownloadHandler.h\ + HaveEraseCommand.cc HaveEraseCommand.h\ + Piece.cc Piece.h # debug_new.cpp if ENABLE_MESSAGE_DIGEST -SRCS += ChunkChecksumValidator.cc ChunkChecksumValidator.h\ - IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\ +SRCS += IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\ IteratableChecksumValidator.cc IteratableChecksumValidator.h\ ChecksumCommand.cc ChecksumCommand.h\ CheckIntegrityCommand.cc CheckIntegrityCommand.h\ CheckIntegrityEntry.cc CheckIntegrityEntry.h\ - CheckIntegrityMan.h\ + StreamCheckIntegrityEntry.cc StreamCheckIntegrityEntry.h\ + CheckIntegrityMan.cc CheckIntegrityMan.h\ messageDigest.cc messageDigest.h\ MessageDigestHelper.cc MessageDigestHelper.h endif # ENABLE_MESSAGE_DIGEST @@ -139,12 +154,8 @@ SRCS += MetaEntry.h\ PeerInitiateConnectionCommand.cc PeerInitiateConnectionCommand.h\ PeerInteractionCommand.cc PeerInteractionCommand.h\ Peer.cc Peer.h\ - TorrentDownloadEngine.cc TorrentDownloadEngine.h\ - TorrentConsoleDownloadEngine.cc TorrentConsoleDownloadEngine.h\ PeerListenCommand.cc PeerListenCommand.h\ - Piece.cc Piece.h\ RequestSlot.cc RequestSlot.h\ - TorrentAutoSaveCommand.cc TorrentAutoSaveCommand.h\ Directory.cc Directory.h\ TrackerWatcherCommand.cc TrackerWatcherCommand.h\ DiskAdaptor.cc DiskAdaptor.h\ @@ -152,11 +163,8 @@ SRCS += MetaEntry.h\ CopyDiskAdaptor.cc CopyDiskAdaptor.h\ DirectDiskAdaptor.cc DirectDiskAdaptor.h\ MultiDiskAdaptor.cc MultiDiskAdaptor.h\ - TrackerUpdateCommand.cc TrackerUpdateCommand.h\ ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\ PeerChokeCommand.cc PeerChokeCommand.h\ - HaveEraseCommand.cc HaveEraseCommand.h\ - TorrentRequestInfo.cc TorrentRequestInfo.h\ SeedCriteria.h\ TimeSeedCriteria.h\ ShareRatioSeedCriteria.h\ @@ -177,8 +185,6 @@ SRCS += MetaEntry.h\ DefaultBtAnnounce.cc DefaultBtAnnounce.h\ BtRegistry.cc BtRegistry.h\ BtRuntime.h\ - BtProgressInfoFile.h\ - DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ BtContextAwareCommand.cc BtContextAwareCommand.h\ BtMessage.h\ AbstractBtMessage.h\ @@ -228,7 +234,13 @@ SRCS += MetaEntry.h\ DefaultBtInteractive.cc DefaultBtInteractive.h\ PeerObject.h\ ActivePeerConnectionCommand.cc ActivePeerConnectionCommand.h\ - TrackerSegmentManFactory.cc TrackerSegmentManFactory.h + BtDependency.cc BtDependency.h\ + PeerReceiveHandshakeCommand.cc PeerReceiveHandshakeCommand.h\ + BtSetup.cc BtSetup.h\ + BtFileAllocationEntry.cc BtFileAllocationEntry.h\ + BtPostDownloadHandler.cc BtPostDownloadHandler.h\ + MultiFileAllocationIterator.cc MultiFileAllocationIterator.h\ + BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h endif # ENABLE_BITTORRENT if ENABLE_METALINK @@ -237,7 +249,8 @@ SRCS += Metalinker.cc Metalinker.h\ MetalinkResource.cc MetalinkResource.h\ MetalinkProcessor.h\ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h\ - MetalinkRequestInfo.cc MetalinkRequestInfo.h + Metalink2RequestGroup.cc Metalink2RequestGroup.h\ + MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h endif # ENABLE_METALINK if !HAVE_BASENAME @@ -280,10 +293,10 @@ noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@ @LIBARES_LIBS@\ - @LIBCARES_LIBS@ @WINSOCK_LIBS@ # -lprofiler -#aria2c_LDFLAGS = #-pg + @LIBCARES_LIBS@ @WINSOCK_LIBS@ #-lprofiler +#aria2c_LDFLAGS = -pg AM_CPPFLAGS = -Wall\ -I../lib -I../intl -I$(top_srcdir)/intl\ @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\ @LIBARES_CPPFLAGS@ @LIBCARES_CPPFLAGS@\ - -D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@ # -pg \ No newline at end of file + -D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@ #-pg \ No newline at end of file diff --git a/src/Makefile.in b/src/Makefile.in index 92fbf514..30ecdfa9 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -40,13 +40,13 @@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = aria2c$(EXEEXT) # debug_new.cpp -@ENABLE_MESSAGE_DIGEST_TRUE@am__append_1 = ChunkChecksumValidator.cc ChunkChecksumValidator.h\ -@ENABLE_MESSAGE_DIGEST_TRUE@ IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\ +@ENABLE_MESSAGE_DIGEST_TRUE@am__append_1 = IteratableChunkChecksumValidator.cc IteratableChunkChecksumValidator.h\ @ENABLE_MESSAGE_DIGEST_TRUE@ IteratableChecksumValidator.cc IteratableChecksumValidator.h\ @ENABLE_MESSAGE_DIGEST_TRUE@ ChecksumCommand.cc ChecksumCommand.h\ @ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityCommand.cc CheckIntegrityCommand.h\ @ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityEntry.cc CheckIntegrityEntry.h\ -@ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityMan.h\ +@ENABLE_MESSAGE_DIGEST_TRUE@ StreamCheckIntegrityEntry.cc StreamCheckIntegrityEntry.h\ +@ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityMan.cc CheckIntegrityMan.h\ @ENABLE_MESSAGE_DIGEST_TRUE@ messageDigest.cc messageDigest.h\ @ENABLE_MESSAGE_DIGEST_TRUE@ MessageDigestHelper.cc MessageDigestHelper.h @@ -63,12 +63,8 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ PeerInitiateConnectionCommand.cc PeerInitiateConnectionCommand.h\ @ENABLE_BITTORRENT_TRUE@ PeerInteractionCommand.cc PeerInteractionCommand.h\ @ENABLE_BITTORRENT_TRUE@ Peer.cc Peer.h\ -@ENABLE_BITTORRENT_TRUE@ TorrentDownloadEngine.cc TorrentDownloadEngine.h\ -@ENABLE_BITTORRENT_TRUE@ TorrentConsoleDownloadEngine.cc TorrentConsoleDownloadEngine.h\ @ENABLE_BITTORRENT_TRUE@ PeerListenCommand.cc PeerListenCommand.h\ -@ENABLE_BITTORRENT_TRUE@ Piece.cc Piece.h\ @ENABLE_BITTORRENT_TRUE@ RequestSlot.cc RequestSlot.h\ -@ENABLE_BITTORRENT_TRUE@ TorrentAutoSaveCommand.cc TorrentAutoSaveCommand.h\ @ENABLE_BITTORRENT_TRUE@ Directory.cc Directory.h\ @ENABLE_BITTORRENT_TRUE@ TrackerWatcherCommand.cc TrackerWatcherCommand.h\ @ENABLE_BITTORRENT_TRUE@ DiskAdaptor.cc DiskAdaptor.h\ @@ -76,11 +72,8 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ CopyDiskAdaptor.cc CopyDiskAdaptor.h\ @ENABLE_BITTORRENT_TRUE@ DirectDiskAdaptor.cc DirectDiskAdaptor.h\ @ENABLE_BITTORRENT_TRUE@ MultiDiskAdaptor.cc MultiDiskAdaptor.h\ -@ENABLE_BITTORRENT_TRUE@ TrackerUpdateCommand.cc TrackerUpdateCommand.h\ @ENABLE_BITTORRENT_TRUE@ ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\ @ENABLE_BITTORRENT_TRUE@ PeerChokeCommand.cc PeerChokeCommand.h\ -@ENABLE_BITTORRENT_TRUE@ HaveEraseCommand.cc HaveEraseCommand.h\ -@ENABLE_BITTORRENT_TRUE@ TorrentRequestInfo.cc TorrentRequestInfo.h\ @ENABLE_BITTORRENT_TRUE@ SeedCriteria.h\ @ENABLE_BITTORRENT_TRUE@ TimeSeedCriteria.h\ @ENABLE_BITTORRENT_TRUE@ ShareRatioSeedCriteria.h\ @@ -101,8 +94,6 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ DefaultBtAnnounce.cc DefaultBtAnnounce.h\ @ENABLE_BITTORRENT_TRUE@ BtRegistry.cc BtRegistry.h\ @ENABLE_BITTORRENT_TRUE@ BtRuntime.h\ -@ENABLE_BITTORRENT_TRUE@ BtProgressInfoFile.h\ -@ENABLE_BITTORRENT_TRUE@ DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ @ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.cc BtContextAwareCommand.h\ @ENABLE_BITTORRENT_TRUE@ BtMessage.h\ @ENABLE_BITTORRENT_TRUE@ AbstractBtMessage.h\ @@ -152,14 +143,21 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ DefaultBtInteractive.cc DefaultBtInteractive.h\ @ENABLE_BITTORRENT_TRUE@ PeerObject.h\ @ENABLE_BITTORRENT_TRUE@ ActivePeerConnectionCommand.cc ActivePeerConnectionCommand.h\ -@ENABLE_BITTORRENT_TRUE@ TrackerSegmentManFactory.cc TrackerSegmentManFactory.h +@ENABLE_BITTORRENT_TRUE@ BtDependency.cc BtDependency.h\ +@ENABLE_BITTORRENT_TRUE@ PeerReceiveHandshakeCommand.cc PeerReceiveHandshakeCommand.h\ +@ENABLE_BITTORRENT_TRUE@ BtSetup.cc BtSetup.h\ +@ENABLE_BITTORRENT_TRUE@ BtFileAllocationEntry.cc BtFileAllocationEntry.h\ +@ENABLE_BITTORRENT_TRUE@ BtPostDownloadHandler.cc BtPostDownloadHandler.h\ +@ENABLE_BITTORRENT_TRUE@ MultiFileAllocationIterator.cc MultiFileAllocationIterator.h\ +@ENABLE_BITTORRENT_TRUE@ BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h @ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @ENABLE_METALINK_TRUE@ MetalinkResource.cc MetalinkResource.h\ @ENABLE_METALINK_TRUE@ MetalinkProcessor.h\ @ENABLE_METALINK_TRUE@ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h\ -@ENABLE_METALINK_TRUE@ MetalinkRequestInfo.cc MetalinkRequestInfo.h +@ENABLE_METALINK_TRUE@ Metalink2RequestGroup.cc Metalink2RequestGroup.h\ +@ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h @HAVE_BASENAME_FALSE@am__append_4 = libgen.c libgen.h @HAVE_GETADDRINFO_FALSE@am__append_5 = getaddrinfo.c getaddrinfo.h @@ -213,8 +211,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ FtpDownloadCommand.h FtpTunnelRequestCommand.cc \ FtpTunnelRequestCommand.h FtpTunnelResponseCommand.cc \ FtpTunnelResponseCommand.h SleepCommand.cc SleepCommand.h \ - DownloadEngine.cc DownloadEngine.h ConsoleDownloadEngine.cc \ - ConsoleDownloadEngine.h Segment.cc Segment.h SegmentMan.cc \ + DownloadEngine.cc DownloadEngine.h Segment.h GrowSegment.cc \ + GrowSegment.h PiecedSegment.cc PiecedSegment.h SegmentMan.cc \ SegmentMan.h Util.cc Util.h Request.cc Request.h common.h \ message.h Exception.h FatalException.h RecoverableException.h \ DlAbortEx.h DlRetryEx.h Logger.h SimpleLogger.cc \ @@ -229,25 +227,24 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ SpeedCalc.cc SpeedCalc.h PeerStat.h BitfieldMan.cc \ BitfieldMan.h BitfieldManFactory.cc BitfieldManFactory.h \ Randomizer.h SimpleRandomizer.cc SimpleRandomizer.h \ - FileAllocator.h FileAllocationMonitor.cc \ - FileAllocationMonitor.h ConsoleFileAllocationMonitor.cc \ - ConsoleFileAllocationMonitor.h HttpResponse.cc HttpResponse.h \ - HttpRequest.cc HttpRequest.h Range.h \ - AbstractProxyRequestCommand.cc AbstractProxyRequestCommand.h \ - AbstractProxyResponseCommand.cc AbstractProxyResponseCommand.h \ - Netrc.cc Netrc.h AuthConfig.cc AuthConfig.h AuthResolver.h \ - AbstractAuthResolver.h DefaultAuthResolver.cc \ - DefaultAuthResolver.h NetrcAuthResolver.cc NetrcAuthResolver.h \ - RequestFactory.cc RequestFactory.h DefaultFileAllocator.cc \ - DefaultFileAllocator.h GlowFileAllocator.cc \ - GlowFileAllocator.h OptionParser.cc OptionParser.h \ + FileAllocator.h HttpResponse.cc HttpResponse.h HttpRequest.cc \ + HttpRequest.h Range.h AbstractProxyRequestCommand.cc \ + AbstractProxyRequestCommand.h AbstractProxyResponseCommand.cc \ + AbstractProxyResponseCommand.h Netrc.cc Netrc.h AuthConfig.cc \ + AuthConfig.h AuthResolver.h AbstractAuthResolver.h \ + DefaultAuthResolver.cc DefaultAuthResolver.h \ + NetrcAuthResolver.cc NetrcAuthResolver.h RequestFactory.cc \ + RequestFactory.h OptionParser.cc OptionParser.h \ OptionHandlerFactory.cc OptionHandlerFactory.h NameResolver.cc \ NameResolver.h RequestGroup.cc RequestGroup.h \ - RequestGroupMan.cc RequestGroupMan.h FileAllocationCommand.cc \ - FileAllocationCommand.h FillRequestGroupCommand.cc \ - FillRequestGroupCommand.h FileAllocationDispatcherCommand.cc \ + RequestGroupAware.cc RequestGroupAware.h RequestGroupMan.cc \ + RequestGroupMan.h FileAllocationMan.cc FileAllocationMan.h \ + FileAllocationCommand.cc FileAllocationCommand.h \ + FillRequestGroupCommand.cc FillRequestGroupCommand.h \ + FileAllocationDispatcherCommand.cc \ FileAllocationDispatcherCommand.h FileAllocationEntry.cc \ - FileAllocationEntry.h MultiUrlRequestInfo.cc \ + FileAllocationEntry.h StreamFileAllocationEntry.cc \ + StreamFileAllocationEntry.h MultiUrlRequestInfo.cc \ MultiUrlRequestInfo.h UriListParser.cc UriListParser.h \ SegmentManFactory.h AbstractSegmentManFactory.h \ DefaultSegmentManFactory.cc DefaultSegmentManFactory.h \ @@ -262,47 +259,49 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ ParameterizedStringParser.cc ParameterizedStringParser.h \ FixedWidthNumberDecorator.h NumberDecorator.h \ AlphaNumberDecorator.h TimeBasedCommand.cc TimeBasedCommand.h \ - AutoSaveCommand.cc AutoSaveCommand.h ChunkChecksumValidator.cc \ - ChunkChecksumValidator.h IteratableChunkChecksumValidator.cc \ + AutoSaveCommand.cc AutoSaveCommand.h \ + UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h \ + StatCalc.h ConsoleStatCalc.cc ConsoleStatCalc.h \ + TransferStat.cc TransferStat.h Dependency.h \ + BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \ + DefaultBtProgressInfoFile.h NullProgressInfoFile.h \ + FileAllocationIterator.h SingleFileAllocationIterator.cc \ + SingleFileAllocationIterator.h PostDownloadHandler.cc \ + PostDownloadHandler.h HaveEraseCommand.cc HaveEraseCommand.h \ + Piece.cc Piece.h IteratableChunkChecksumValidator.cc \ IteratableChunkChecksumValidator.h \ IteratableChecksumValidator.cc IteratableChecksumValidator.h \ ChecksumCommand.cc ChecksumCommand.h CheckIntegrityCommand.cc \ CheckIntegrityCommand.h CheckIntegrityEntry.cc \ - CheckIntegrityEntry.h CheckIntegrityMan.h messageDigest.cc \ - messageDigest.h MessageDigestHelper.cc MessageDigestHelper.h \ - MetaEntry.h Data.cc Data.h Dictionary.cc Dictionary.h List.cc \ - List.h MetaFileUtil.cc MetaFileUtil.h MetaEntryVisitor.h \ + CheckIntegrityEntry.h StreamCheckIntegrityEntry.cc \ + StreamCheckIntegrityEntry.h CheckIntegrityMan.cc \ + CheckIntegrityMan.h messageDigest.cc messageDigest.h \ + MessageDigestHelper.cc MessageDigestHelper.h MetaEntry.h \ + Data.cc Data.h Dictionary.cc Dictionary.h List.cc List.h \ + MetaFileUtil.cc MetaFileUtil.h MetaEntryVisitor.h \ ShaVisitor.cc ShaVisitor.h PeerConnection.cc PeerConnection.h \ PeerMessageUtil.cc PeerMessageUtil.h PeerAbstractCommand.cc \ PeerAbstractCommand.h PeerInitiateConnectionCommand.cc \ PeerInitiateConnectionCommand.h PeerInteractionCommand.cc \ - PeerInteractionCommand.h Peer.cc Peer.h \ - TorrentDownloadEngine.cc TorrentDownloadEngine.h \ - TorrentConsoleDownloadEngine.cc TorrentConsoleDownloadEngine.h \ - PeerListenCommand.cc PeerListenCommand.h Piece.cc Piece.h \ - RequestSlot.cc RequestSlot.h TorrentAutoSaveCommand.cc \ - TorrentAutoSaveCommand.h Directory.cc Directory.h \ - TrackerWatcherCommand.cc TrackerWatcherCommand.h \ + PeerInteractionCommand.h Peer.cc Peer.h PeerListenCommand.cc \ + PeerListenCommand.h RequestSlot.cc RequestSlot.h Directory.cc \ + Directory.h TrackerWatcherCommand.cc TrackerWatcherCommand.h \ DiskAdaptor.cc DiskAdaptor.h AbstractSingleDiskAdaptor.cc \ AbstractSingleDiskAdaptor.h CopyDiskAdaptor.cc \ CopyDiskAdaptor.h DirectDiskAdaptor.cc DirectDiskAdaptor.h \ - MultiDiskAdaptor.cc MultiDiskAdaptor.h TrackerUpdateCommand.cc \ - TrackerUpdateCommand.h ByteArrayDiskWriter.cc \ + MultiDiskAdaptor.cc MultiDiskAdaptor.h ByteArrayDiskWriter.cc \ ByteArrayDiskWriter.h PeerChokeCommand.cc PeerChokeCommand.h \ - HaveEraseCommand.cc HaveEraseCommand.h TorrentRequestInfo.cc \ - TorrentRequestInfo.h SeedCriteria.h TimeSeedCriteria.h \ - ShareRatioSeedCriteria.h UnionSeedCriteria.h \ - SeedCheckCommand.cc SeedCheckCommand.h PeerListProcessor.h \ - DefaultPeerListProcessor.cc DefaultPeerListProcessor.h \ - CompactPeerListProcessor.cc CompactPeerListProcessor.h \ - DelegatingPeerListProcessor.cc DelegatingPeerListProcessor.h \ - AnnounceTier.h AnnounceList.h AnnounceList.cc BtContext.h \ - DefaultBtContext.cc DefaultBtContext.h PieceStorage.h \ - DefaultPieceStorage.cc DefaultPieceStorage.h \ - DefaultPeerStorage.cc DefaultPeerStorage.h BtAnnounce.h \ - DefaultBtAnnounce.cc DefaultBtAnnounce.h BtRegistry.cc \ - BtRegistry.h BtRuntime.h BtProgressInfoFile.h \ - DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h \ + SeedCriteria.h TimeSeedCriteria.h ShareRatioSeedCriteria.h \ + UnionSeedCriteria.h SeedCheckCommand.cc SeedCheckCommand.h \ + PeerListProcessor.h DefaultPeerListProcessor.cc \ + DefaultPeerListProcessor.h CompactPeerListProcessor.cc \ + CompactPeerListProcessor.h DelegatingPeerListProcessor.cc \ + DelegatingPeerListProcessor.h AnnounceTier.h AnnounceList.h \ + AnnounceList.cc BtContext.h DefaultBtContext.cc \ + DefaultBtContext.h PieceStorage.h DefaultPieceStorage.cc \ + DefaultPieceStorage.h DefaultPeerStorage.cc \ + DefaultPeerStorage.h BtAnnounce.h DefaultBtAnnounce.cc \ + DefaultBtAnnounce.h BtRegistry.cc BtRegistry.h BtRuntime.h \ BtContextAwareCommand.cc BtContextAwareCommand.h BtMessage.h \ AbstractBtMessage.h SimpleBtMessage.cc SimpleBtMessage.h \ BtAllowedFastMessage.cc BtAllowedFastMessage.h \ @@ -334,22 +333,28 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ BtChokedEvent.h BtChokingEvent.h BtInteractive.h \ DefaultBtInteractive.cc DefaultBtInteractive.h PeerObject.h \ ActivePeerConnectionCommand.cc ActivePeerConnectionCommand.h \ - TrackerSegmentManFactory.cc TrackerSegmentManFactory.h \ - Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ + BtDependency.cc BtDependency.h PeerReceiveHandshakeCommand.cc \ + PeerReceiveHandshakeCommand.h BtSetup.cc BtSetup.h \ + BtFileAllocationEntry.cc BtFileAllocationEntry.h \ + BtPostDownloadHandler.cc BtPostDownloadHandler.h \ + MultiFileAllocationIterator.cc MultiFileAllocationIterator.h \ + BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h Metalinker.cc \ + Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h \ - MetalinkRequestInfo.cc MetalinkRequestInfo.h libgen.c libgen.h \ - getaddrinfo.c getaddrinfo.h gai_strerror.c gai_strerror.h \ - gettimeofday.c gettimeofday.h inet_aton.c inet_aton.h \ - localtime_r.c localtime_r.h strptime.c strptime.h timegm.c \ - timegm.h -@ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 = \ -@ENABLE_MESSAGE_DIGEST_TRUE@ ChunkChecksumValidator.$(OBJEXT) \ -@ENABLE_MESSAGE_DIGEST_TRUE@ IteratableChunkChecksumValidator.$(OBJEXT) \ + Metalink2RequestGroup.cc Metalink2RequestGroup.h \ + MetalinkPostDownloadHandler.cc MetalinkPostDownloadHandler.h \ + libgen.c libgen.h getaddrinfo.c getaddrinfo.h gai_strerror.c \ + gai_strerror.h gettimeofday.c gettimeofday.h inet_aton.c \ + inet_aton.h localtime_r.c localtime_r.h strptime.c strptime.h \ + timegm.c timegm.h +@ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 = IteratableChunkChecksumValidator.$(OBJEXT) \ @ENABLE_MESSAGE_DIGEST_TRUE@ IteratableChecksumValidator.$(OBJEXT) \ @ENABLE_MESSAGE_DIGEST_TRUE@ ChecksumCommand.$(OBJEXT) \ @ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityCommand.$(OBJEXT) \ @ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityEntry.$(OBJEXT) \ +@ENABLE_MESSAGE_DIGEST_TRUE@ StreamCheckIntegrityEntry.$(OBJEXT) \ +@ENABLE_MESSAGE_DIGEST_TRUE@ CheckIntegrityMan.$(OBJEXT) \ @ENABLE_MESSAGE_DIGEST_TRUE@ messageDigest.$(OBJEXT) \ @ENABLE_MESSAGE_DIGEST_TRUE@ MessageDigestHelper.$(OBJEXT) @ENABLE_BITTORRENT_TRUE@am__objects_2 = Data.$(OBJEXT) \ @@ -362,11 +367,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ PeerInitiateConnectionCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerInteractionCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ Peer.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TorrentDownloadEngine.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TorrentConsoleDownloadEngine.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerListenCommand.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ Piece.$(OBJEXT) RequestSlot.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TorrentAutoSaveCommand.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ RequestSlot.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ Directory.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ TrackerWatcherCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DiskAdaptor.$(OBJEXT) \ @@ -374,11 +376,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ CopyDiskAdaptor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DirectDiskAdaptor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ MultiDiskAdaptor.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TrackerUpdateCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ ByteArrayDiskWriter.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerChokeCommand.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ HaveEraseCommand.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TorrentRequestInfo.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ SeedCheckCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DefaultPeerListProcessor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ CompactPeerListProcessor.$(OBJEXT) \ @@ -389,7 +388,6 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ DefaultPeerStorage.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DefaultBtAnnounce.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtRegistry.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ DefaultBtProgressInfoFile.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ SimpleBtMessage.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtAllowedFastMessage.$(OBJEXT) \ @@ -415,12 +413,19 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ DefaultBtRequestFactory.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DefaultBtInteractive.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ ActivePeerConnectionCommand.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TrackerSegmentManFactory.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ BtDependency.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ PeerReceiveHandshakeCommand.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtSetup.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtFileAllocationEntry.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtPostDownloadHandler.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ MultiFileAllocationIterator.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtCheckIntegrityEntry.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ Xml2MetalinkProcessor.$(OBJEXT) \ -@ENABLE_METALINK_TRUE@ MetalinkRequestInfo.$(OBJEXT) +@ENABLE_METALINK_TRUE@ Metalink2RequestGroup.$(OBJEXT) \ +@ENABLE_METALINK_TRUE@ MetalinkPostDownloadHandler.$(OBJEXT) @HAVE_BASENAME_FALSE@am__objects_4 = libgen.$(OBJEXT) @HAVE_GETADDRINFO_FALSE@am__objects_5 = getaddrinfo.$(OBJEXT) @HAVE_GAI_STRERROR_FALSE@am__objects_6 = gai_strerror.$(OBJEXT) @@ -444,8 +449,8 @@ am__objects_12 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ FtpNegotiationCommand.$(OBJEXT) FtpDownloadCommand.$(OBJEXT) \ FtpTunnelRequestCommand.$(OBJEXT) \ FtpTunnelResponseCommand.$(OBJEXT) SleepCommand.$(OBJEXT) \ - DownloadEngine.$(OBJEXT) ConsoleDownloadEngine.$(OBJEXT) \ - Segment.$(OBJEXT) SegmentMan.$(OBJEXT) Util.$(OBJEXT) \ + DownloadEngine.$(OBJEXT) GrowSegment.$(OBJEXT) \ + PiecedSegment.$(OBJEXT) SegmentMan.$(OBJEXT) Util.$(OBJEXT) \ Request.$(OBJEXT) SimpleLogger.$(OBJEXT) \ ChunkedEncoding.$(OBJEXT) AbstractDiskWriter.$(OBJEXT) \ DefaultDiskWriter.$(OBJEXT) File.$(OBJEXT) Option.$(OBJEXT) \ @@ -453,27 +458,33 @@ am__objects_12 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ TimeA2.$(OBJEXT) FeatureConfig.$(OBJEXT) \ DownloadEngineFactory.$(OBJEXT) SpeedCalc.$(OBJEXT) \ BitfieldMan.$(OBJEXT) BitfieldManFactory.$(OBJEXT) \ - SimpleRandomizer.$(OBJEXT) FileAllocationMonitor.$(OBJEXT) \ - ConsoleFileAllocationMonitor.$(OBJEXT) HttpResponse.$(OBJEXT) \ + SimpleRandomizer.$(OBJEXT) HttpResponse.$(OBJEXT) \ HttpRequest.$(OBJEXT) AbstractProxyRequestCommand.$(OBJEXT) \ AbstractProxyResponseCommand.$(OBJEXT) Netrc.$(OBJEXT) \ AuthConfig.$(OBJEXT) DefaultAuthResolver.$(OBJEXT) \ NetrcAuthResolver.$(OBJEXT) RequestFactory.$(OBJEXT) \ - DefaultFileAllocator.$(OBJEXT) GlowFileAllocator.$(OBJEXT) \ OptionParser.$(OBJEXT) OptionHandlerFactory.$(OBJEXT) \ NameResolver.$(OBJEXT) RequestGroup.$(OBJEXT) \ - RequestGroupMan.$(OBJEXT) FileAllocationCommand.$(OBJEXT) \ + RequestGroupAware.$(OBJEXT) RequestGroupMan.$(OBJEXT) \ + FileAllocationMan.$(OBJEXT) FileAllocationCommand.$(OBJEXT) \ FillRequestGroupCommand.$(OBJEXT) \ FileAllocationDispatcherCommand.$(OBJEXT) \ - FileAllocationEntry.$(OBJEXT) MultiUrlRequestInfo.$(OBJEXT) \ - UriListParser.$(OBJEXT) DefaultSegmentManFactory.$(OBJEXT) \ - RealtimeCommand.$(OBJEXT) RequestGroupEntry.$(OBJEXT) \ - Cookie.$(OBJEXT) CookieParser.$(OBJEXT) \ - CookieBoxFactory.$(OBJEXT) HttpHeaderProcessor.$(OBJEXT) \ - FileEntry.$(OBJEXT) Platform.$(OBJEXT) \ - PStringSegment.$(OBJEXT) PStringBuildVisitor.$(OBJEXT) \ + FileAllocationEntry.$(OBJEXT) \ + StreamFileAllocationEntry.$(OBJEXT) \ + MultiUrlRequestInfo.$(OBJEXT) UriListParser.$(OBJEXT) \ + DefaultSegmentManFactory.$(OBJEXT) RealtimeCommand.$(OBJEXT) \ + RequestGroupEntry.$(OBJEXT) Cookie.$(OBJEXT) \ + CookieParser.$(OBJEXT) CookieBoxFactory.$(OBJEXT) \ + HttpHeaderProcessor.$(OBJEXT) FileEntry.$(OBJEXT) \ + Platform.$(OBJEXT) PStringSegment.$(OBJEXT) \ + PStringBuildVisitor.$(OBJEXT) \ ParameterizedStringParser.$(OBJEXT) TimeBasedCommand.$(OBJEXT) \ - AutoSaveCommand.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + AutoSaveCommand.$(OBJEXT) UnknownLengthPieceStorage.$(OBJEXT) \ + ConsoleStatCalc.$(OBJEXT) TransferStat.$(OBJEXT) \ + DefaultBtProgressInfoFile.$(OBJEXT) \ + SingleFileAllocationIterator.$(OBJEXT) \ + PostDownloadHandler.$(OBJEXT) HaveEraseCommand.$(OBJEXT) \ + Piece.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) $(am__objects_7) $(am__objects_8) \ $(am__objects_9) $(am__objects_10) $(am__objects_11) @@ -482,7 +493,8 @@ libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_aria2c_OBJECTS = main.$(OBJEXT) +am_aria2c_OBJECTS = main.$(OBJEXT) option_processing.$(OBJEXT) \ + version_usage.$(OBJEXT) aria2c_OBJECTS = $(am_aria2c_OBJECTS) aria2c_DEPENDENCIES = libaria2c.a @ALLOCA@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) @@ -667,7 +679,10 @@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ -aria2c_SOURCES = main.cc +aria2c_SOURCES = main.cc\ + option_processing.cc\ + version_usage.cc + SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ AbstractCommand.cc AbstractCommand.h \ InitiateConnectionCommandFactory.cc \ @@ -686,8 +701,8 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ FtpDownloadCommand.h FtpTunnelRequestCommand.cc \ FtpTunnelRequestCommand.h FtpTunnelResponseCommand.cc \ FtpTunnelResponseCommand.h SleepCommand.cc SleepCommand.h \ - DownloadEngine.cc DownloadEngine.h ConsoleDownloadEngine.cc \ - ConsoleDownloadEngine.h Segment.cc Segment.h SegmentMan.cc \ + DownloadEngine.cc DownloadEngine.h Segment.h GrowSegment.cc \ + GrowSegment.h PiecedSegment.cc PiecedSegment.h SegmentMan.cc \ SegmentMan.h Util.cc Util.h Request.cc Request.h common.h \ message.h Exception.h FatalException.h RecoverableException.h \ DlAbortEx.h DlRetryEx.h Logger.h SimpleLogger.cc \ @@ -702,25 +717,24 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ SpeedCalc.cc SpeedCalc.h PeerStat.h BitfieldMan.cc \ BitfieldMan.h BitfieldManFactory.cc BitfieldManFactory.h \ Randomizer.h SimpleRandomizer.cc SimpleRandomizer.h \ - FileAllocator.h FileAllocationMonitor.cc \ - FileAllocationMonitor.h ConsoleFileAllocationMonitor.cc \ - ConsoleFileAllocationMonitor.h HttpResponse.cc HttpResponse.h \ - HttpRequest.cc HttpRequest.h Range.h \ - AbstractProxyRequestCommand.cc AbstractProxyRequestCommand.h \ - AbstractProxyResponseCommand.cc AbstractProxyResponseCommand.h \ - Netrc.cc Netrc.h AuthConfig.cc AuthConfig.h AuthResolver.h \ - AbstractAuthResolver.h DefaultAuthResolver.cc \ - DefaultAuthResolver.h NetrcAuthResolver.cc NetrcAuthResolver.h \ - RequestFactory.cc RequestFactory.h DefaultFileAllocator.cc \ - DefaultFileAllocator.h GlowFileAllocator.cc \ - GlowFileAllocator.h OptionParser.cc OptionParser.h \ + FileAllocator.h HttpResponse.cc HttpResponse.h HttpRequest.cc \ + HttpRequest.h Range.h AbstractProxyRequestCommand.cc \ + AbstractProxyRequestCommand.h AbstractProxyResponseCommand.cc \ + AbstractProxyResponseCommand.h Netrc.cc Netrc.h AuthConfig.cc \ + AuthConfig.h AuthResolver.h AbstractAuthResolver.h \ + DefaultAuthResolver.cc DefaultAuthResolver.h \ + NetrcAuthResolver.cc NetrcAuthResolver.h RequestFactory.cc \ + RequestFactory.h OptionParser.cc OptionParser.h \ OptionHandlerFactory.cc OptionHandlerFactory.h NameResolver.cc \ NameResolver.h RequestGroup.cc RequestGroup.h \ - RequestGroupMan.cc RequestGroupMan.h FileAllocationCommand.cc \ - FileAllocationCommand.h FillRequestGroupCommand.cc \ - FillRequestGroupCommand.h FileAllocationDispatcherCommand.cc \ + RequestGroupAware.cc RequestGroupAware.h RequestGroupMan.cc \ + RequestGroupMan.h FileAllocationMan.cc FileAllocationMan.h \ + FileAllocationCommand.cc FileAllocationCommand.h \ + FillRequestGroupCommand.cc FillRequestGroupCommand.h \ + FileAllocationDispatcherCommand.cc \ FileAllocationDispatcherCommand.h FileAllocationEntry.cc \ - FileAllocationEntry.h MultiUrlRequestInfo.cc \ + FileAllocationEntry.h StreamFileAllocationEntry.cc \ + StreamFileAllocationEntry.h MultiUrlRequestInfo.cc \ MultiUrlRequestInfo.h UriListParser.cc UriListParser.h \ SegmentManFactory.h AbstractSegmentManFactory.h \ DefaultSegmentManFactory.cc DefaultSegmentManFactory.h \ @@ -735,23 +749,31 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ ParameterizedStringParser.cc ParameterizedStringParser.h \ FixedWidthNumberDecorator.h NumberDecorator.h \ AlphaNumberDecorator.h TimeBasedCommand.cc TimeBasedCommand.h \ - AutoSaveCommand.cc AutoSaveCommand.h $(am__append_1) \ - $(am__append_2) $(am__append_3) $(am__append_4) \ - $(am__append_5) $(am__append_6) $(am__append_7) \ - $(am__append_8) $(am__append_9) $(am__append_10) \ - $(am__append_11) + AutoSaveCommand.cc AutoSaveCommand.h \ + UnknownLengthPieceStorage.cc UnknownLengthPieceStorage.h \ + StatCalc.h ConsoleStatCalc.cc ConsoleStatCalc.h \ + TransferStat.cc TransferStat.h Dependency.h \ + BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \ + DefaultBtProgressInfoFile.h NullProgressInfoFile.h \ + FileAllocationIterator.h SingleFileAllocationIterator.cc \ + SingleFileAllocationIterator.h PostDownloadHandler.cc \ + PostDownloadHandler.h HaveEraseCommand.cc HaveEraseCommand.h \ + Piece.cc Piece.h $(am__append_1) $(am__append_2) \ + $(am__append_3) $(am__append_4) $(am__append_5) \ + $(am__append_6) $(am__append_7) $(am__append_8) \ + $(am__append_9) $(am__append_10) $(am__append_11) noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@ @LIBARES_LIBS@\ - @LIBCARES_LIBS@ @WINSOCK_LIBS@ # -lprofiler + @LIBCARES_LIBS@ @WINSOCK_LIBS@ #-lprofiler -#aria2c_LDFLAGS = #-pg +#aria2c_LDFLAGS = -pg AM_CPPFLAGS = -Wall\ -I../lib -I../intl -I$(top_srcdir)/intl\ @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\ @LIBARES_CPPFLAGS@ @LIBCARES_CPPFLAGS@\ - -D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@ # -pg + -D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@ #-pg all: all-am @@ -842,8 +864,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtAllowedFastMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtBitfieldMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtCancelMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtCheckIntegrityEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtChokeMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtContextAwareCommand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtDependency.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtFileAllocationEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHandshakeMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveAllMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveMessage.Po@am__quote@ @@ -853,21 +878,22 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtNotInterestedMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPieceMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPortMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPostDownloadHandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRejectMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRequestMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSetup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSuggestPieceMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityEntry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChecksumCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkChecksumValidator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncoding.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Command.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompactPeerListProcessor.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleDownloadEngine.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleFileAllocationMonitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleStatCalc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cookie.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxFactory.Po@am__quote@ @@ -884,7 +910,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtProgressInfoFile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtRequestFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriter.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultFileAllocator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerStorage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorage.Po@am__quote@ @@ -902,7 +927,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationDispatcherCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationEntry.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationMonitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAllocationMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FillRequestGroupCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpConnection.Po@am__quote@ @@ -911,7 +936,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpNegotiationCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelRequestCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelResponseCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GlowFileAllocator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveEraseCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpConnection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpDownloadCommand.Po@am__quote@ @@ -931,11 +956,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LogFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtil.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalink2RequestGroup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntry.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkRequestInfo.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkPostDownloadHandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkResource.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalinker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskAdaptor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiFileAllocationIterator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiUrlRequestInfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NameResolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Netrc.Po@am__quote@ @@ -954,34 +981,36 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerInteractionCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerListenCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtil.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerReceiveHandshakeCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Piece.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PiecedSegment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Platform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PostDownloadHandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RealtimeCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Request.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupAware.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestSlot.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SeedCheckCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Segment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleBtMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleLogger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleRandomizer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SingleFileAllocationIterator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SleepCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketCore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StreamCheckIntegrityEntry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StreamFileAllocationEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeA2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeBasedCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentAutoSaveCommand.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentConsoleDownloadEngine.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentDownloadEngine.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentRequestInfo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerSegmentManFactory.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerUpdateCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransferStat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessor.Po@am__quote@ @@ -993,8 +1022,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localtime_r.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messageDigest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/option_processing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strptime.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timegm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version_usage.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ diff --git a/src/MessageDigestHelper.cc b/src/MessageDigestHelper.cc index 8819dcdc..edda3c6c 100644 --- a/src/MessageDigestHelper.cc +++ b/src/MessageDigestHelper.cc @@ -40,18 +40,21 @@ #include "Util.h" #include -string MessageDigestHelper::digest(const string& algo, DiskWriterHandle diskWriter, int64_t offset, int64_t length) +string MessageDigestHelper::digest(const string& algo, + const BinaryStreamHandle& bs, + int64_t offset, + int64_t length) { MessageDigestContext ctx; ctx.trySetAlgo(algo); ctx.digestInit(); int32_t BUFSIZE = 4096; - char BUF[BUFSIZE]; + unsigned char BUF[BUFSIZE]; int64_t iteration = length/BUFSIZE; int32_t tail = length%BUFSIZE; for(int64_t i = 0; i < iteration; ++i) { - int32_t readLength = diskWriter->readData(BUF, BUFSIZE, offset); + int32_t readLength = bs->readData(BUF, BUFSIZE, offset); if(readLength != BUFSIZE) { throw new DlAbortEx(EX_FILE_READ, "n/a", strerror(errno)); } @@ -59,7 +62,7 @@ string MessageDigestHelper::digest(const string& algo, DiskWriterHandle diskWrit offset += readLength; } if(tail) { - int32_t readLength = diskWriter->readData(BUF, tail, offset); + int32_t readLength = bs->readData(BUF, tail, offset); if(readLength != tail) { throw new DlAbortEx(EX_FILE_READ, "n/a", strerror(errno)); } @@ -73,7 +76,7 @@ string MessageDigestHelper::digest(const string& algo, const string& filename) { DiskWriterHandle writer = new DefaultDiskWriter(); writer->openExistingFile(filename); - return digest(algo, writer); + return digest(algo, writer, 0, writer->size()); } string MessageDigestHelper::digest(const string& algo, const void* data, int32_t length) diff --git a/src/MessageDigestHelper.h b/src/MessageDigestHelper.h index 21e4a215..04a7c155 100644 --- a/src/MessageDigestHelper.h +++ b/src/MessageDigestHelper.h @@ -36,7 +36,7 @@ #define _D_MESSAGE_DIGEST_HELPER_H_ #include "common.h" -#include "DiskWriter.h" +#include "BinaryStream.h" class MessageDigestHelper { public: @@ -44,15 +44,7 @@ public: * Returns message digest in hexadecimal notation. * Digest algorithm is specified by algo. */ - static string digest(const string& algo, DiskWriterHandle diskWriter, int64_t offset, int64_t length); - - /** - * Calculates message digest of file opened by diskWriter. - */ - static string digest(const string& algo, DiskWriterHandle diskWriter) - { - return digest(algo, diskWriter, 0, diskWriter->size()); - } + static string digest(const string& algo, const BinaryStreamHandle& bs, int64_t offset, int64_t length); /** * Calculates message digest of file denoted by filename. diff --git a/src/MetalinkRequestInfo.cc b/src/Metalink2RequestGroup.cc similarity index 54% rename from src/MetalinkRequestInfo.cc rename to src/Metalink2RequestGroup.cc index 7e2311ef..7985af99 100644 --- a/src/MetalinkRequestInfo.cc +++ b/src/Metalink2RequestGroup.cc @@ -32,13 +32,21 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#include "MetalinkRequestInfo.h" -#include "Xml2MetalinkProcessor.h" +#include "Metalink2RequestGroup.h" +#include "RequestGroup.h" +#include "Option.h" +#include "LogFactory.h" #include "prefs.h" -#include "DlAbortEx.h" -#include "MultiUrlRequestInfo.h" +#include "Xml2MetalinkProcessor.h" #include "Util.h" #include "message.h" +#include "RecoverableException.h" +#include "BtDependency.h" +#include "SingleFileDownloadContext.h" + +Metalink2RequestGroup::Metalink2RequestGroup(const Option* option):_option(option), _logger(LogFactory::getInstance()) {} + +Metalink2RequestGroup::~Metalink2RequestGroup() {} class AccumulateNonP2PUrl { private: @@ -83,26 +91,21 @@ public: } }; -RequestInfos MetalinkRequestInfo::execute() { +RequestGroups Metalink2RequestGroup::generate(const string& metalinkFile) +{ Xml2MetalinkProcessor proc; - RequestInfos nextReqInfos; try { MetalinkerHandle metalinker = proc.parseFile(metalinkFile); MetalinkEntries entries = - metalinker->queryEntry(op->get(PREF_METALINK_VERSION), - op->get(PREF_METALINK_LANGUAGE), - op->get(PREF_METALINK_OS)); + metalinker->queryEntry(_option->get(PREF_METALINK_VERSION), + _option->get(PREF_METALINK_LANGUAGE), + _option->get(PREF_METALINK_OS)); if(entries.size() == 0) { - cout << EX_NO_RESULT_WITH_YOUR_PREFS << endl; - throw new DlAbortEx(EX_NO_RESULT_WITH_YOUR_PREFS); - } - if(op->get(PREF_SHOW_FILES) == V_TRUE) { - Util::toStream(cout, MetalinkEntry::toFileEntry(entries)); - return RequestInfos(); + return RequestGroups(); } bool useIndex; Integers selectIndexes; - Util::unfoldRange(op->get(PREF_SELECT_FILE), selectIndexes); + Util::unfoldRange(_option->get(PREF_SELECT_FILE), selectIndexes); if(selectIndexes.size()) { useIndex = true; } else { @@ -113,74 +116,80 @@ RequestInfos MetalinkRequestInfo::execute() { for(MetalinkEntries::iterator itr = entries.begin(); itr != entries.end(); itr++, ++count) { MetalinkEntryHandle& entry = *itr; - if(op->defined(PREF_METALINK_LOCATION)) { - entry->setLocationPreference(op->get(PREF_METALINK_LOCATION), 100); + if(_option->defined(PREF_METALINK_LOCATION)) { + entry->setLocationPreference(_option->get(PREF_METALINK_LOCATION), 100); } if(useIndex) { if(find(selectIndexes.begin(), selectIndexes.end(), count+1) == selectIndexes.end()) { continue; } - } else if(!targetFiles.empty()) { - if(find(targetFiles.begin(), targetFiles.end(), entry->getPath()) == targetFiles.end()) { - continue; - } } - entry->dropUnsupportedResource(); if(entry->resources.size() == 0) { continue; } - logger->info(MSG_METALINK_QUEUEING, - entry->getPath().c_str()); - MetalinkResources::iterator itr = - find_if(entry->resources.begin(), - entry->resources.end(), - FindBitTorrentUrl()); - Strings urls; -#ifdef ENABLE_MESSAGE_DIGEST - ChecksumHandle checksum = 0; -#endif // ENABLE_MESSAGE_DIGEST - if(itr == entry->resources.end()) { - entry->reorderResourcesByPreference(); - - for_each(entry->resources.begin(), entry->resources.end(), - AccumulateNonP2PUrl(&urls, op->getAsInt(PREF_SPLIT))); -#ifdef ENABLE_MESSAGE_DIGEST - // TODO - // set checksum - checksum = entry->checksum; -#endif // ENABLE_MESSAGE_DIGEST - } else { - // BitTorrent downloading - urls.push_back((*itr)->url); + _logger->info(MSG_METALINK_QUEUEING, entry->getPath().c_str()); + MetalinkResources::iterator itr = find_if(entry->resources.begin(), + entry->resources.end(), + FindBitTorrentUrl()); + RequestGroupHandle torrentRg = 0; + // there is torrent entry + if(itr != entry->resources.end()) { + Strings uris; + uris.push_back((*itr)->url); + torrentRg = new RequestGroup(_option, uris); + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(_option->getAsInt(PREF_SEGMENT_SIZE), + 0, + ""); + dctx->setDir(_option->get(PREF_DIR)); + torrentRg->setDownloadContext(dctx); + torrentRg->clearPostDowloadHandler(); + groups.push_back(torrentRg); } - RequestGroupHandle rg = new RequestGroup(urls, op); - if(itr == entry->resources.end()) { - rg->setHintFilename(entry->file->getBasename()); - rg->setHintTotalLength(entry->getLength()); - } - rg->setTopDir(entry->file->getDirname()); - rg->setNumConcurrentCommand(entry->maxConnections < 0 ? - op->getAsInt(PREF_METALINK_SERVERS) : - min(op->getAsInt(PREF_METALINK_SERVERS), entry->maxConnections)); - -#ifdef ENABLE_MESSAGE_DIGEST + entry->reorderResourcesByPreference(); + Strings uris; + for_each(entry->resources.begin(), entry->resources.end(), + AccumulateNonP2PUrl(&uris, _option->getAsInt(PREF_SPLIT))); + RequestGroupHandle rg = new RequestGroup(_option, uris); + // If piece hash is specified in the metalink, + // make segment size equal to piece hash size. + int32_t pieceLength; if(entry->chunkChecksum.isNull()) { - rg->setChecksum(checksum); + pieceLength = _option->getAsInt(PREF_SEGMENT_SIZE); } else { - rg->setChunkChecksum(entry->chunkChecksum); + pieceLength = entry->chunkChecksum->getChecksumLength(); } -#endif // ENABLE_MESSAGE_DIGEST - groups.push_front(rg); + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(pieceLength, + 0, + ""); + dctx->setDir(_option->get(PREF_DIR)); + if(!entry->chunkChecksum.isNull()) { + dctx->setPieceHashes(entry->chunkChecksum->getChecksums()); + dctx->setPieceHashAlgo(entry->chunkChecksum->getAlgo()); + } + // TODO set checksum here to DownloadContext + // * hash and hash algorithm + + rg->setDownloadContext(dctx); + rg->setHintFilename(entry->file->getBasename()); + rg->setHintTotalLength(entry->getLength()); + rg->setNumConcurrentCommand(entry->maxConnections < 0 ? + _option->getAsInt(PREF_METALINK_SERVERS) : + min(_option->getAsInt(PREF_METALINK_SERVERS), entry->maxConnections)); + + // Inject depenency between rg and torrentRg here if torrentRg.isNull() == false + if(!torrentRg.isNull()) { + rg->dependsOn(new BtDependency(rg, torrentRg, _option)); + } + + groups.push_back(rg); } - // clear PREF_OUT, because PREF_OUT is a filename for metalink file itself. - op->put(PREF_OUT, ""); - MultiUrlRequestInfoHandle reqInfo = new MultiUrlRequestInfo(groups, op); - nextReqInfos.push_back(reqInfo); + return groups; } catch(RecoverableException* ex) { - logger->error(EX_EXCEPTION_CAUGHT, ex); + _logger->error(EX_EXCEPTION_CAUGHT, ex); delete ex; - fail = true; + return RequestGroups(); } - return nextReqInfos; } diff --git a/src/MetalinkRequestInfo.h b/src/Metalink2RequestGroup.h similarity index 75% rename from src/MetalinkRequestInfo.h rename to src/Metalink2RequestGroup.h index c89c3787..1c72fee8 100644 --- a/src/MetalinkRequestInfo.h +++ b/src/Metalink2RequestGroup.h @@ -32,26 +32,28 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_METALINK_REQUEST_INFO_H_ -#define _D_METALINK_REQUEST_INFO_H_ +#ifndef _D_METALINK_2_REQUEST_GROUP_H_ +#define _D_METALINK_2_REQUEST_GROUP_H_ -#include "RequestInfo.h" +#include "common.h" -class MetalinkRequestInfo : public RequestInfo { +class Option; +class Logger; +class RequestGroup; +extern typedef SharedHandle RequestGroupHandle; +extern typedef deque RequestGroups; + +class Metalink2RequestGroup { private: - string metalinkFile; - Strings targetFiles; + const Option* _option; + + const Logger* _logger; public: - MetalinkRequestInfo(const string& metalinkFile, Option* op): - RequestInfo(op), - metalinkFile(metalinkFile) {} - virtual ~MetalinkRequestInfo() {} + Metalink2RequestGroup(const Option* option); - virtual RequestInfos execute(); + ~Metalink2RequestGroup(); - void setTargetFiles(const Strings& targetFiles) { - this->targetFiles = targetFiles; - } + RequestGroups generate(const string& metalinkFile); }; -#endif // _D_METALINK_REQUEST_INFO_H_ +#endif // _D_METALINK_2_REQUEST_GROUP_H_ diff --git a/src/MetalinkPostDownloadHandler.cc b/src/MetalinkPostDownloadHandler.cc new file mode 100644 index 00000000..de6e9695 --- /dev/null +++ b/src/MetalinkPostDownloadHandler.cc @@ -0,0 +1,48 @@ +/* */ +#include "MetalinkPostDownloadHandler.h" +#include "RequestGroup.h" +#include "Metalink2RequestGroup.h" + +MetalinkPostDownloadHandler::MetalinkPostDownloadHandler(const Option* option): + PostDownloadHandler(".metalink", option) +{} + +MetalinkPostDownloadHandler::~MetalinkPostDownloadHandler() {} + +RequestGroups MetalinkPostDownloadHandler::getNextRequestGroups(const string& path) +{ + return Metalink2RequestGroup(_option).generate(path); +} diff --git a/src/MetalinkPostDownloadHandler.h b/src/MetalinkPostDownloadHandler.h new file mode 100644 index 00000000..068f44c2 --- /dev/null +++ b/src/MetalinkPostDownloadHandler.h @@ -0,0 +1,51 @@ +/* */ +#ifndef _D_METALINK_POST_DOWNLOAD_HANDLER_H_ +#define _D_METALINK_POST_DOWNLOAD_HANDLER_H_ + +#include "PostDownloadHandler.h" + +class MetalinkPostDownloadHandler:public PostDownloadHandler +{ +public: + MetalinkPostDownloadHandler(const Option* option); + + virtual ~MetalinkPostDownloadHandler(); + + virtual RequestGroups getNextRequestGroups(const string& path); +}; + +typedef SharedHandle MetalinkPostDownloadHandlerHandle; +#endif // _D_METALINK_POST_DOWNLOAD_HANDLER_H_ diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc index b866d68e..a57ea5dc 100644 --- a/src/MultiDiskAdaptor.cc +++ b/src/MultiDiskAdaptor.cc @@ -34,17 +34,19 @@ /* copyright --> */ #include "MultiDiskAdaptor.h" #include "DefaultDiskWriter.h" -#include "DlAbortEx.h" #include "message.h" #include "Util.h" +#include "MultiFileAllocationIterator.h" +#include "DefaultDiskWriterFactory.h" -void MultiDiskAdaptor::resetDiskWriterEntries() { +void MultiDiskAdaptor::resetDiskWriterEntries() +{ diskWriterEntries.clear(); for(FileEntries::const_iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { DiskWriterEntryHandle entry = new DiskWriterEntry(*itr); if((*itr)->isRequested()) { - entry->setDiskWriter(DefaultDiskWriter::createNewDiskWriter(option)); + entry->setDiskWriter(DefaultDiskWriterFactory().newDiskWriter()); } else { entry->setDiskWriter(new DefaultDiskWriter()); } @@ -52,18 +54,23 @@ void MultiDiskAdaptor::resetDiskWriterEntries() { } } -string MultiDiskAdaptor::getTopDirPath() const { +string MultiDiskAdaptor::getTopDirPath() const +{ return storeDir+"/"+topDir; } -void MultiDiskAdaptor::mkdir() const { +void MultiDiskAdaptor::mkdir() const + throw(DlAbortEx*) +{ for(FileEntries::const_iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { (*itr)->setupDir(getTopDirPath()); } } -void MultiDiskAdaptor::openFile() { +void MultiDiskAdaptor::openFile() + throw(DlAbortEx*) +{ mkdir(); resetDiskWriterEntries(); for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); @@ -72,7 +79,9 @@ void MultiDiskAdaptor::openFile() { } } -void MultiDiskAdaptor::initAndOpenFile() { +void MultiDiskAdaptor::initAndOpenFile() + throw(DlAbortEx*) +{ mkdir(); resetDiskWriterEntries(); for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); @@ -81,7 +90,9 @@ void MultiDiskAdaptor::initAndOpenFile() { } } -void MultiDiskAdaptor::openExistingFile() { +void MultiDiskAdaptor::openExistingFile() + throw(DlAbortEx*) +{ resetDiskWriterEntries(); for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); itr != diskWriterEntries.end(); itr++) { @@ -89,20 +100,24 @@ void MultiDiskAdaptor::openExistingFile() { } } -void MultiDiskAdaptor::closeFile() { +void MultiDiskAdaptor::closeFile() +{ for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); itr != diskWriterEntries.end(); itr++) { (*itr)->closeFile(); } } -void MultiDiskAdaptor::onDownloadComplete() { +void MultiDiskAdaptor::onDownloadComplete() + throw(DlAbortEx*) +{ closeFile(); openFile(); } void MultiDiskAdaptor::writeData(const unsigned char* data, int32_t len, int64_t offset) + throw(DlAbortEx*) { int64_t fileOffset = offset; bool writing = false; @@ -145,6 +160,7 @@ int32_t MultiDiskAdaptor::calculateLength(const DiskWriterEntryHandle entry, } int32_t MultiDiskAdaptor::readData(unsigned char* data, int32_t len, int64_t offset) + throw(DlAbortEx*) { int64_t fileOffset = offset; bool reading = false; @@ -184,6 +200,7 @@ bool MultiDiskAdaptor::fileExists() // TODO call DiskWriter::openFile() before calling this function. int64_t MultiDiskAdaptor::size() const + throw(DlAbortEx*) { int64_t size = 0; for(DiskWriterEntries::const_iterator itr = diskWriterEntries.begin(); @@ -192,3 +209,8 @@ int64_t MultiDiskAdaptor::size() const } return size; } + +FileAllocationIteratorHandle MultiDiskAdaptor::fileAllocationIterator() +{ + return new MultiFileAllocationIterator(this); +} diff --git a/src/MultiDiskAdaptor.h b/src/MultiDiskAdaptor.h index 1d01d937..8e1b8424 100644 --- a/src/MultiDiskAdaptor.h +++ b/src/MultiDiskAdaptor.h @@ -39,6 +39,7 @@ #include "Option.h" #include "DiskWriter.h" #include "File.h" +#include "DlAbortEx.h" class DiskWriterEntry { private: @@ -57,16 +58,19 @@ public: } void initAndOpenFile(const string& topDir) + throw(DlAbortEx*) { diskWriter->initAndOpenFile(getFilePath(topDir), fileEntry->getLength()); } void openFile(const string& topDir) + throw(DlAbortEx*) { diskWriter->openFile(getFilePath(topDir), fileEntry->getLength()); } void openExistingFile(const string& topDir) + throw(DlAbortEx*) { diskWriter->openExistingFile(getFilePath(topDir), fileEntry->getLength()); } @@ -82,6 +86,7 @@ public: } int64_t size() const + throw(DlAbortEx*) { return diskWriter->size(); } @@ -112,7 +117,7 @@ private: void resetDiskWriterEntries(); - void mkdir() const; + void mkdir() const throw(DlAbortEx*); bool isInRange(const DiskWriterEntryHandle entry, int64_t offset) const; @@ -128,28 +133,31 @@ public: virtual ~MultiDiskAdaptor() {} - virtual void initAndOpenFile(); + virtual void initAndOpenFile() throw(DlAbortEx*); - virtual void openFile(); + virtual void openFile() throw(DlAbortEx*); - virtual void openExistingFile(); + virtual void openExistingFile() throw(DlAbortEx*); virtual void closeFile(); - virtual void onDownloadComplete(); + virtual void onDownloadComplete() 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 string getFilePath() { + virtual string getFilePath() + { return getTopDirPath(); } - virtual int64_t size() const; + virtual int64_t size() const throw(DlAbortEx*); + + virtual FileAllocationIteratorHandle fileAllocationIterator(); void setTopDir(const string& topDir) { this->topDir = topDir; diff --git a/src/MultiDiskWriter.cc b/src/MultiDiskWriter.cc deleted file mode 100644 index 89ae72bf..00000000 --- a/src/MultiDiskWriter.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* */ -#include "MultiDiskWriter.h" -#include "DlAbortEx.h" -#include "Util.h" -#include "message.h" -#include - -MultiDiskWriter::MultiDiskWriter(int pieceLength): - pieceLength(pieceLength), - ctx(DIGEST_ALGO_SHA1), - fileAllocator(0) { - ctx.digestInit(); -} - -MultiDiskWriter::~MultiDiskWriter() { - clearEntries(); -} - -void MultiDiskWriter::clearEntries() { - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end(); itr++) { - delete *itr; - } - diskWriterEntries.clear(); -} - -void MultiDiskWriter::setFileEntries(const FileEntries& fileEntries) { - clearEntries(); - for(FileEntries::const_iterator itr = fileEntries.begin(); - itr != fileEntries.end(); itr++) { - diskWriterEntries.push_back(new DiskWriterEntry(*itr)); - } -} - -void MultiDiskWriter::configureFileAllocator(DiskWriterEntry* entry) { - if(entry->fileEntry->isRequested()) { - entry->diskWriter->setFileAllocator(fileAllocator); - } else { - entry->diskWriter->setFileAllocator(0); - } -} - -void MultiDiskWriter::openFile(const string& filename) { - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end(); itr++) { - configureFileAllocator(*itr); - (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry->getPath()); - } -} - -// filename is a directory which is specified by the user in the option. -void MultiDiskWriter::initAndOpenFile(const string& filename) { - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end(); itr++) { - configureFileAllocator(*itr); - (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry->getPath()); - } -} - -void MultiDiskWriter::closeFile() { - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end(); itr++) { - (*itr)->diskWriter->closeFile(); - } -} - -void MultiDiskWriter::openExistingFile(const string& filename) { - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end(); itr++) { - (*itr)->diskWriter->setFileAllocator(0); - (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry->getPath()); - } -} - -void MultiDiskWriter::writeData(const char* data, int len, long long int offset) { - long long int fileOffset = offset; - bool writing = false; - int rem = len; - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end() && rem != 0; itr++) { - if(isInRange(*itr, offset) || writing) { - int writeLength = calculateLength(*itr, fileOffset, rem); - (*itr)->diskWriter->writeData(data+(len-rem), writeLength, fileOffset); - rem -= writeLength; - writing = true; - fileOffset = 0; - } else { - fileOffset -= (*itr)->fileEntry->getLength(); - } - } - if(!writing) { - throw new DlAbortEx(EX_FILE_OFFSET_OUT_OF_RANGE, offset); - } -} - -bool MultiDiskWriter::isInRange(const DiskWriterEntry* entry, long long int offset) const { - return entry->fileEntry->getOffset() <= offset && - offset < entry->fileEntry->getOffset()+entry->fileEntry->getLength(); -} - -int MultiDiskWriter::calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const { - int length; - if(entry->fileEntry->getLength() < fileOffset+rem) { - length = entry->fileEntry->getLength()-fileOffset; - } else { - length = rem; - } - return length; -} - -int MultiDiskWriter::readData(char* data, int len, long long int offset) { - long long int fileOffset = offset; - bool reading = false; - int rem = len; - int totalReadLength = 0; - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end() && rem != 0; itr++) { - if(isInRange(*itr, offset) || reading) { - int readLength = calculateLength((*itr), fileOffset, rem); - totalReadLength += (*itr)->diskWriter->readData(data+(len-rem), readLength, fileOffset); - rem -= readLength; - reading = true; - fileOffset = 0; - } else { - fileOffset -= (*itr)->fileEntry->getLength(); - } - } - if(!reading) { - throw new DlAbortEx(EX_FILE_OFFSET_OUT_OF_RANGE, offset); - } - return totalReadLength; -} - -void MultiDiskWriter::hashUpdate(DiskWriterEntry* entry, long long int offset, long long int length) { - int BUFSIZE = 16*1024; - char buf[BUFSIZE]; - for(int i = 0; i < length/BUFSIZE; i++) { - if(BUFSIZE != entry->diskWriter->readData(buf, BUFSIZE, offset)) { - throw string("error"); - } - ctx.digestUpdate(buf, BUFSIZE); - offset += BUFSIZE; - } - int r = length%BUFSIZE; - if(r > 0) { - if(r != entry->diskWriter->readData(buf, r, offset)) { - throw string("error"); - } - ctx.digestUpdate(buf, r); - } -} - -string MultiDiskWriter::sha1Sum(long long int offset, long long int length) { - long long int fileOffset = offset; - bool reading = false; - int rem = length; - ctx.digestReset(); - try { - for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); - itr != diskWriterEntries.end() && rem != 0; itr++) { - if(isInRange(*itr, offset) || reading) { - int readLength = calculateLength((*itr), fileOffset, rem); - hashUpdate(*itr, fileOffset, readLength); - rem -= readLength; - reading = true; - fileOffset = 0; - } else { - fileOffset -= (*itr)->fileEntry->getLength(); - } - } - if(!reading) { - throw new DlAbortEx(EX_FILE_OFFSET_OUT_OF_RANGE, offset); - } - unsigned char hashValue[20]; - ctx.digestFinal(hashValue); - return Util::toHex(hashValue, 20); - } catch(string ex) { - throw new DlAbortEx(EX_FILE_SHA1SUM, "", strerror(errno)); - } -} - diff --git a/src/MultiDiskWriter.h b/src/MultiDiskWriter.h deleted file mode 100644 index 6fa229a2..00000000 --- a/src/MultiDiskWriter.h +++ /dev/null @@ -1,89 +0,0 @@ -/* */ -#ifndef _D_MULTI_DISK_WRITER_H_ -#define _D_MULTI_DISK_WRITER_H_ - -#include "DefaultDiskWriter.h" -#include "messageDigest.h" -#include "FileEntry.h" -#include "FileAllocator.h" - -class DiskWriterEntry { -public: - FileEntryHandle fileEntry; - DefaultDiskWriter* diskWriter; -public: - DiskWriterEntry(const FileEntryHandle& fileEntry):fileEntry(fileEntry) { - diskWriter = new DefaultDiskWriter(this->fileEntry->getLength()); - } - ~DiskWriterEntry() { - delete diskWriter; - } -}; - -typedef deque DiskWriterEntries; - -class MultiDiskWriter : public DiskWriter { -private: - DiskWriterEntries diskWriterEntries; - int pieceLength; - MessageDigestContext ctx; - FileAllocatorHandle fileAllocator; - - bool isInRange(const DiskWriterEntry* entry, long long int offset) const; - int calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const; - void clearEntries(); - void hashUpdate(DiskWriterEntry* entry, long long int offset, long long int length); - void configureFileAllocator(DiskWriterEntry* entry); -public: - MultiDiskWriter(int pieceLength); - virtual ~MultiDiskWriter(); - - void setFileEntries(const FileEntries& fileEntries); - - virtual void openFile(const string& filename); - virtual void initAndOpenFile(const string& filename); - virtual void closeFile(); - virtual void openExistingFile(const string& filename); - virtual void writeData(const char* data, int len, long long int position = 0); - virtual int readData(char* data, int len, long long int position); - virtual string sha1Sum(long long int offset, long long int length); - - void setFileAllocator(const FileAllocatorHandle& fileAllocator) { - this->fileAllocator = fileAllocator; - } -}; - -#endif // _D_MULTI_DISK_WRITER_H_ diff --git a/src/GlowFileAllocator.cc b/src/MultiFileAllocationIterator.cc similarity index 51% rename from src/GlowFileAllocator.cc rename to src/MultiFileAllocationIterator.cc index 6a6f2334..fb2f7fe4 100644 --- a/src/GlowFileAllocator.cc +++ b/src/MultiFileAllocationIterator.cc @@ -32,44 +32,70 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#include "GlowFileAllocator.h" -#include "DlAbortEx.h" -#include "TimeA2.h" -#include "a2io.h" -#include -#include -#include -#include +#include "MultiFileAllocationIterator.h" +#include "MultiDiskAdaptor.h" +#include "FileEntry.h" -void GlowFileAllocator::allocate(int fd, int64_t totalLength) +#define BUFSIZE 16*1024 + +MultiFileAllocationIterator::MultiFileAllocationIterator(MultiDiskAdaptor* diskAdaptor): + _diskAdaptor(diskAdaptor), + _entries(diskAdaptor->getFileEntries()), + _currentEntry(0), + _offset(0) +{} + +MultiFileAllocationIterator::~MultiFileAllocationIterator() {} + +void MultiFileAllocationIterator::prepareNextEntry() { - struct stat fs; - if(fstat(fd, &fs) < 0) { - throw new DlAbortEx("fstat filed: %s", strerror(errno)); - } - if(fs.st_size != lseek(fd, 0, SEEK_END)) { - throw new DlAbortEx("Seek failed: %s", strerror(errno)); - } - int32_t bufSize = 4096; - char buf[4096]; - memset(buf, 0, bufSize); - int64_t x = (totalLength-fs.st_size+bufSize-1)/bufSize; - fileAllocationMonitor->setMinValue(0); - fileAllocationMonitor->setMaxValue(totalLength); - fileAllocationMonitor->setCurrentValue(fs.st_size); - fileAllocationMonitor->showProgress(); - Time cp; - for(int64_t i = 0; i < x; ++i) { - if(write(fd, buf, bufSize) < 0) { - throw new DlAbortEx("Allocation failed: %s", strerror(errno)); - } - if(cp.elapsedInMillis(500)) { - fileAllocationMonitor->setCurrentValue(i*bufSize); - fileAllocationMonitor->showProgress(); - cp.reset(); + _currentEntry = 0; + _offset = 0; + while(!_entries.empty()) { + FileEntryHandle entry = _entries.front(); + _entries.pop_front(); + if(entry->isRequested()) { + _currentEntry = entry; + _offset = File(_diskAdaptor->getStoreDir()+"/"+ + _diskAdaptor->getTopDir()+"/"+ + _currentEntry->getPath()).size(); + break; } } - fileAllocationMonitor->setCurrentValue(totalLength); - fileAllocationMonitor->showProgress(); - ftruncate(fd, totalLength); +} + + +void MultiFileAllocationIterator::allocateChunk() +{ + while(_currentEntry.isNull() || _currentEntry->getLength() <= _offset) { + prepareNextEntry(); + if(_currentEntry.isNull()) { + break; + } + } + if(finished()) { + return; + } + int32_t bufSize = BUFSIZE; + unsigned char buf[BUFSIZE]; + memset(buf, 0, bufSize); + + int32_t wsize = _offset+bufSize > _currentEntry->getLength() ? + _currentEntry->getLength()-_offset:bufSize; + _diskAdaptor->writeData(buf, wsize, _offset+_currentEntry->getOffset()); + _offset += wsize; +} + +bool MultiFileAllocationIterator::finished() +{ + return _entries.empty() && _currentEntry.isNull(); +} + +int64_t MultiFileAllocationIterator::getTotalLength() +{ + if(_currentEntry.isNull()) { + return 0; + } else { + return _currentEntry->getLength(); + } } diff --git a/src/FileAllocationMonitor.h b/src/MultiFileAllocationIterator.h similarity index 65% rename from src/FileAllocationMonitor.h rename to src/MultiFileAllocationIterator.h index 8d9c8354..6f97723e 100644 --- a/src/FileAllocationMonitor.h +++ b/src/MultiFileAllocationIterator.h @@ -32,36 +32,42 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_FILE_ALLOCATION_MONITOR_H_ -#define _D_FILE_ALLOCATION_MONITOR_H_ +#ifndef _D_MULTI_FILE_ALLOCATION_ITERATOR_H_ +#define _D_MULTI_FILE_ALLOCATION_ITERATOR_H_ -#include "FileProgressMonitor.h" +#include "FileAllocationIterator.h" -typedef FileProgressMonitor FileAllocationMonitor; -typedef SharedHandle FileAllocationMonitorHandle; +class MultiDiskAdaptor; +class FileEntry; +extern typedef SharedHandle FileEntryHandle; +extern typedef deque FileEntries; -class FileAllocationMonitorFactory; - -typedef SharedHandle FileAllocationMonitorFactoryHandle; - -class FileAllocationMonitorFactory { +class MultiFileAllocationIterator:public FileAllocationIterator +{ private: - static FileAllocationMonitorFactoryHandle factory; - -protected: - FileAllocationMonitorFactory() {} + MultiDiskAdaptor* _diskAdaptor; + FileEntries _entries; + FileEntryHandle _currentEntry; + int64_t _offset; public: - static FileAllocationMonitorFactoryHandle getFactory() { - return factory; + MultiFileAllocationIterator(MultiDiskAdaptor* diskAdaptor); + + virtual ~MultiFileAllocationIterator(); + + void prepareNextEntry(); + + virtual void allocateChunk(); + + virtual bool finished(); + + virtual int64_t getCurrentLength() + { + return _offset; } - virtual ~FileAllocationMonitorFactory() {} - - static void setFactory(const FileAllocationMonitorFactoryHandle& factory) { - FileAllocationMonitorFactory::factory = factory; - } - - virtual FileAllocationMonitorHandle createNewMonitor() = 0; + virtual int64_t getTotalLength(); }; -#endif // _D_FILE_ALLOCATION_MONITOR_H_ +typedef SharedHandle MultiFileAllocationIteratorHandle; + +#endif // _D_MULTI_FILE_ALLOCATION_ITERATOR_H_ diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc index 99a08f17..6f7965c4 100644 --- a/src/MultiUrlRequestInfo.cc +++ b/src/MultiUrlRequestInfo.cc @@ -33,50 +33,56 @@ */ /* copyright --> */ #include "MultiUrlRequestInfo.h" +#include "RequestGroupMan.h" +#include "DownloadEngine.h" +#include "LogFactory.h" +#include "RequestGroup.h" #include "prefs.h" #include "DownloadEngineFactory.h" #include "RecoverableException.h" #include "message.h" #include "DNSCache.h" -#include "TorrentRequestInfo.h" -#include "MetalinkRequestInfo.h" #include "Util.h" +#include "ConsoleStatCalc.h" #include -extern volatile sig_atomic_t haltRequested; +#ifndef SA_RESETHAND +# define SA_RESETHAND 0x80000000 +#endif // SA_RESETHAND -RequestInfoHandle MultiUrlRequestInfo::createNextRequestInfo(const string& filename) const -{ -#ifdef ENABLE_BITTORRENT - if(op->getAsBool(PREF_FOLLOW_TORRENT) && - Util::endsWith(filename, ".torrent")) { - return new TorrentRequestInfo(filename, op); - } else -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - if(op->getAsBool(PREF_FOLLOW_METALINK) && - Util::endsWith(filename, ".metalink")) { - return new MetalinkRequestInfo(filename, op); - } else -#endif // ENABLE_METALINK - { - return 0; - } -} +extern volatile sig_atomic_t globalHaltRequested; static void handler(int signal) { - haltRequested = true; + globalHaltRequested = true; } -RequestInfos MultiUrlRequestInfo::execute() { +MultiUrlRequestInfo::MultiUrlRequestInfo(const RequestGroups& requestGroups, Option* op): + _requestGroups(requestGroups), + _option(op), + _logger(LogFactory::getInstance()) +{} + +MultiUrlRequestInfo::~MultiUrlRequestInfo() {} + +void MultiUrlRequestInfo::printDownloadAbortMessage() +{ + printf(_("\nSome downloads were not complete because of errors." + " Check the log.\n" + "aria2 will resume download if the transfer is restarted.")); + printf("\n"); +} + +void MultiUrlRequestInfo::execute() +{ { DNSCacheHandle dnsCache = new SimpleDNSCache(); DNSCacheSingletonHolder::instance(dnsCache); } - RequestInfos nextReqInfos; try { - SharedHandle e(DownloadEngineFactory::newConsoleEngine(op, _requestGroups)); + DownloadEngineHandle e = + DownloadEngineFactory().newDownloadEngine(_option, _requestGroups); + e->setStatCalc(new ConsoleStatCalc()); e->fillCommand(); @@ -87,35 +93,21 @@ RequestInfos MultiUrlRequestInfo::execute() { // This is done every 1 second. At the same time, it removes finished/error // RequestGroup from DownloadEngine. - Util::setGlobalSignalHandler(SIGINT, handler, 0); - Util::setGlobalSignalHandler(SIGTERM, handler, 0); + Util::setGlobalSignalHandler(SIGINT, handler, SA_RESETHAND); + Util::setGlobalSignalHandler(SIGTERM, handler, SA_RESETHAND); e->run(); - for(RequestGroups::iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - if((*itr)->downloadFinished()) { - RequestInfoHandle reqInfo = createNextRequestInfo((*itr)->getFilePath()); - if(!reqInfo.isNull()) { - nextReqInfos.push_back(reqInfo); - } - } - } - RequestGroupMan rgman(_requestGroups); - // TODO print summary of the download result - rgman.showDownloadResults(cout); + e->_requestGroupMan->showDownloadResults(cout); cout << flush; - // TODO Do we have to print a message when some of the downloads are failed? - if(!rgman.downloadFinished()) { + + if(!e->_requestGroupMan->downloadFinished()) { printDownloadAbortMessage(); } } catch(RecoverableException *ex) { - logger->error(EX_EXCEPTION_CAUGHT, ex); + _logger->error(EX_EXCEPTION_CAUGHT, ex); delete ex; - fail = true; } Util::setGlobalSignalHandler(SIGINT, SIG_DFL, 0); Util::setGlobalSignalHandler(SIGTERM, SIG_DFL, 0); - - return nextReqInfos; } diff --git a/src/MultiUrlRequestInfo.h b/src/MultiUrlRequestInfo.h index de065a43..c7f7916d 100644 --- a/src/MultiUrlRequestInfo.h +++ b/src/MultiUrlRequestInfo.h @@ -35,27 +35,30 @@ #ifndef _D_MULTI_URL_REQUEST_INFO_H_ #define _D_MULTI_URL_REQUEST_INFO_H_ -#include "RequestInfo.h" -#include "RequestGroup.h" +#include "common.h" -class MultiUrlRequestInfo : public RequestInfo { +class RequestGroup; +extern typedef SharedHandle RequestGroupHandle; +extern typedef deque RequestGroups; +class Option; +class Logger; + +class MultiUrlRequestInfo { private: RequestGroups _requestGroups; - RequestInfoHandle createNextRequestInfo(const string& filename) const; + Option* _option; + + const Logger* _logger; + + void printDownloadAbortMessage(); + public: - MultiUrlRequestInfo(const RequestGroups& requestGroups, Option* op): - RequestInfo(op), - _requestGroups(requestGroups) {} + MultiUrlRequestInfo(const RequestGroups& requestGroups, Option* op); + + virtual ~MultiUrlRequestInfo(); - MultiUrlRequestInfo(const Strings& uris, Option* op):RequestInfo(op) - { - _requestGroups.push_back(new RequestGroup(uris, op)); - } - - virtual ~MultiUrlRequestInfo() {} - - virtual RequestInfos execute(); + void execute(); }; typedef SharedHandle MultiUrlRequestInfoHandle; diff --git a/src/NullProgressInfoFile.h b/src/NullProgressInfoFile.h new file mode 100644 index 00000000..7fd8415c --- /dev/null +++ b/src/NullProgressInfoFile.h @@ -0,0 +1,60 @@ +/* */ +#ifndef _D_NULL_PROGRESS_INFO_FILE_H_ +#define _D_NULL_PROGRESS_INFO_FILE_H_ + +#include "BtProgressInfoFile.h" + +class NullProgressInfoFile:public BtProgressInfoFile { +public: + virtual ~NullProgressInfoFile() {} + + virtual string getFilename() + { + return ""; + } + + virtual bool exists() { return false; } + + virtual void save() {} + + virtual void load() {} + + virtual void removeFile() {} +}; + +typedef SharedHandle NullProgressInfoFileHandle; + +#endif // _D_NULL_PROGRESS_INFO_FILE_H_ diff --git a/src/Peer.cc b/src/Peer.cc index 1017c250..44ef73f6 100644 --- a/src/Peer.cc +++ b/src/Peer.cc @@ -54,6 +54,14 @@ Peer::Peer(string ipaddr, int32_t port, int32_t pieceLength, int64_t totalLength id = MessageDigestHelper::digestString("sha1", idSeed); } +void Peer::reconfigure(int32_t pieceLength, int64_t totalLength) +{ + delete bitfield; + this->pieceLength = pieceLength; + this->bitfield = BitfieldManFactory::getFactoryInstance()-> + createBitfieldMan(this->pieceLength, totalLength); +} + /* Peer::Peer():entryId(0), ipaddr(""), port(0), bitfield(0), sessionUploadLength(0), sessionDownloadLength(0), diff --git a/src/Peer.h b/src/Peer.h index 63b5f07c..2fbbdc6d 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -210,6 +210,8 @@ public: void startBadCondition(); bool isGood() const; + + void reconfigure(int32_t pieceLength, int64_t totalLength); }; typedef SharedHandle PeerHandle; diff --git a/src/PeerAbstractCommand.cc b/src/PeerAbstractCommand.cc index 86c44338..4454a519 100644 --- a/src/PeerAbstractCommand.cc +++ b/src/PeerAbstractCommand.cc @@ -33,33 +33,34 @@ */ /* copyright --> */ #include "PeerAbstractCommand.h" +#include "Peer.h" +#include "DownloadEngine.h" +#include "Option.h" #include "DlAbortEx.h" #include "DlRetryEx.h" #include "Util.h" #include "message.h" #include "prefs.h" -PeerAbstractCommand::PeerAbstractCommand(int32_t cuid, const PeerHandle& peer, - TorrentDownloadEngine* e, - const BtContextHandle& btContext, +PeerAbstractCommand::PeerAbstractCommand(int32_t cuid, + const PeerHandle& peer, + DownloadEngine* e, const SocketHandle& s) - :BtContextAwareCommand(cuid, btContext), e(e), socket(s), peer(peer), + :Command(cuid), e(e), socket(s), peer(peer), checkSocketIsReadable(false), checkSocketIsWritable(false), uploadLimitCheck(false), uploadLimit(0), noCheck(false) { setReadCheckSocket(socket); timeout = e->option->getAsInt(PREF_BT_TIMEOUT); - btRuntime->increaseConnections(); } PeerAbstractCommand::~PeerAbstractCommand() { disableReadCheckSocket(); disableWriteCheckSocket(); - btRuntime->decreaseConnections(); } bool PeerAbstractCommand::execute() { - if(btRuntime->isHalt()) { + if(exitBeforeExecute()) { peer->resetStatus(); return true; } @@ -96,10 +97,6 @@ bool PeerAbstractCommand::prepareForRetry(int32_t wait) { return true; } -void PeerAbstractCommand::onAbort(Exception* ex) { - peerStorage->returnPeer(peer); -} - void PeerAbstractCommand::disableReadCheckSocket() { if(checkSocketIsReadable) { e->deleteSocketForReadCheck(readCheckTarget, this); diff --git a/src/PeerAbstractCommand.h b/src/PeerAbstractCommand.h index e50aabde..79a4d030 100644 --- a/src/PeerAbstractCommand.h +++ b/src/PeerAbstractCommand.h @@ -35,25 +35,29 @@ #ifndef _D_PEER_ABSTRACT_COMMAND_H_ #define _D_PEER_ABSTRACT_COMMAND_H_ -#include "BtContextAwareCommand.h" -#include "Request.h" -#include "TorrentDownloadEngine.h" +#include "Command.h" #include "TimeA2.h" -#include "Exception.h" +#include "Socket.h" -class PeerAbstractCommand : public BtContextAwareCommand { +class DownloadEngine; +class Exception; +class Peer; +extern typedef SharedHandle PeerHandle; + +class PeerAbstractCommand : public Command { private: Time checkPoint; int32_t timeout; protected: - TorrentDownloadEngine* e; + DownloadEngine* e; SocketHandle socket; PeerHandle peer; void setTimeout(int32_t timeout) { this->timeout = timeout; } virtual bool prepareForNextPeer(int32_t wait); virtual bool prepareForRetry(int32_t wait); - virtual void onAbort(Exception* ex); + virtual void onAbort(Exception* ex) {}; + virtual bool exitBeforeExecute() = 0; virtual bool executeInternal() = 0; void setReadCheckSocket(const SocketHandle& socket); void setWriteCheckSocket(const SocketHandle& socket); @@ -71,12 +75,13 @@ private: int32_t uploadLimit; bool noCheck; public: - PeerAbstractCommand(int32_t cuid, const PeerHandle& peer, - TorrentDownloadEngine* e, - const BtContextHandle& btContext, + PeerAbstractCommand(int32_t cuid, + const PeerHandle& peer, + DownloadEngine* e, const SocketHandle& s = SocketHandle()); virtual ~PeerAbstractCommand(); - bool execute(); + + virtual bool execute(); }; #endif // _D_PEER_ABSTRACT_COMMAND_H_ diff --git a/src/PeerChokeCommand.cc b/src/PeerChokeCommand.cc index de06502b..7c2eec0e 100644 --- a/src/PeerChokeCommand.cc +++ b/src/PeerChokeCommand.cc @@ -36,13 +36,17 @@ #include "Util.h" PeerChokeCommand::PeerChokeCommand(int32_t cuid, - TorrentDownloadEngine* e, + RequestGroup* requestGroup, + DownloadEngine* e, const BtContextHandle& btContext, int32_t interval): - BtContextAwareCommand(cuid, btContext), + Command(cuid), + BtContextAwareCommand(btContext), + RequestGroupAware(requestGroup), interval(interval), e(e), - rotate(0) {} + rotate(0) +{} PeerChokeCommand::~PeerChokeCommand() {} diff --git a/src/PeerChokeCommand.h b/src/PeerChokeCommand.h index 687f405c..0a2b2f67 100644 --- a/src/PeerChokeCommand.h +++ b/src/PeerChokeCommand.h @@ -35,14 +35,19 @@ #ifndef _D_PEER_CHOKE_COMMAND_H_ #define _D_PEER_CHOKE_COMMAND_H_ +#include "Command.h" #include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" +#include "DownloadEngine.h" #include "TimeA2.h" +#include "RequestGroupAware.h" -class PeerChokeCommand : public BtContextAwareCommand { +class PeerChokeCommand : public Command, + public BtContextAwareCommand, + public RequestGroupAware +{ private: int32_t interval; - TorrentDownloadEngine* e; + DownloadEngine* e; int32_t rotate; Time checkPoint; @@ -52,13 +57,14 @@ private: public: PeerChokeCommand(int32_t cuid, - TorrentDownloadEngine* e, + RequestGroup* requestGroup, + DownloadEngine* e, const BtContextHandle& btContext, int32_t interval); virtual ~PeerChokeCommand(); - bool execute(); + virtual bool execute(); }; #endif // _D_PEER_CHOKE_COMMAND_H_ diff --git a/src/PeerConnection.cc b/src/PeerConnection.cc index fd231997..e62e1e25 100644 --- a/src/PeerConnection.cc +++ b/src/PeerConnection.cc @@ -122,17 +122,20 @@ bool PeerConnection::receiveMessage(unsigned char* data, int32_t& dataLength) { return true; } -bool PeerConnection::receiveHandshake(unsigned char* data, int32_t& dataLength) { - if(!socket->isReadable(0)) { +bool PeerConnection::receiveHandshake(unsigned char* data, int32_t& dataLength, + bool peek) { + int32_t remain = BtHandshakeMessage::MESSAGE_LENGTH-resbufLength; + if(remain != 0 && !socket->isReadable(0)) { dataLength = 0; return false; } - int32_t remain = BtHandshakeMessage::MESSAGE_LENGTH-resbufLength; int32_t temp = remain; - socket->readData((char*)resbuf+resbufLength, temp); - if(temp == 0) { - // we got EOF - throw new DlAbortEx(EX_EOF_FROM_PEER); + if(remain != 0) { + socket->readData((char*)resbuf+resbufLength, temp); + if(temp == 0) { + // we got EOF + throw new DlAbortEx(EX_EOF_FROM_PEER); + } } bool retval; if(remain != temp) { @@ -141,11 +144,11 @@ bool PeerConnection::receiveHandshake(unsigned char* data, int32_t& dataLength) retval = true; } resbufLength += temp; - // we got whole handshake payload + int32_t writeLength = resbufLength > dataLength ? dataLength : resbufLength; memcpy(data, resbuf, writeLength); dataLength = writeLength; - if(retval) { + if(retval && !peek) { resbufLength = 0; } return retval; diff --git a/src/PeerConnection.h b/src/PeerConnection.h index 3e941ae5..6cf5dbf2 100644 --- a/src/PeerConnection.h +++ b/src/PeerConnection.h @@ -72,7 +72,7 @@ public: * In both cases, 'msg' is filled with received bytes and the filled length * is assigned to 'length'. */ - bool receiveHandshake(unsigned char* data, int32_t& dataLength); + bool receiveHandshake(unsigned char* data, int32_t& dataLength, bool peek = false); }; typedef SharedHandle PeerConnectionHandle; diff --git a/src/PeerInitiateConnectionCommand.cc b/src/PeerInitiateConnectionCommand.cc index 8ada7e3f..8139f1fe 100644 --- a/src/PeerInitiateConnectionCommand.cc +++ b/src/PeerInitiateConnectionCommand.cc @@ -33,6 +33,7 @@ */ /* copyright --> */ #include "PeerInitiateConnectionCommand.h" +#include "DownloadEngine.h" #include "PeerInteractionCommand.h" #include "Util.h" #include "DlAbortEx.h" @@ -41,12 +42,21 @@ #include "CUIDCounter.h" PeerInitiateConnectionCommand::PeerInitiateConnectionCommand(int cuid, + RequestGroup* requestGroup, const PeerHandle& peer, - TorrentDownloadEngine* e, + DownloadEngine* e, const BtContextHandle& btContext) - :PeerAbstractCommand(cuid, peer, e, btContext) {} + :PeerAbstractCommand(cuid, peer, e), + BtContextAwareCommand(btContext), + RequestGroupAware(requestGroup) +{ + btRuntime->increaseConnections(); +} -PeerInitiateConnectionCommand::~PeerInitiateConnectionCommand() {} +PeerInitiateConnectionCommand::~PeerInitiateConnectionCommand() +{ + btRuntime->decreaseConnections(); +} bool PeerInitiateConnectionCommand::executeInternal() { Command* command; @@ -55,6 +65,7 @@ bool PeerInitiateConnectionCommand::executeInternal() { socket->establishConnection(peer->ipaddr, peer->port); command = new PeerInteractionCommand(cuid, + _requestGroup, peer, e, btContext, @@ -72,6 +83,7 @@ bool PeerInitiateConnectionCommand::prepareForNextPeer(int wait) { peer->cuid = CUIDCounterSingletonHolder::instance()->newID(); PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(peer->cuid, + _requestGroup, peer, e, btContext); @@ -83,9 +95,19 @@ bool PeerInitiateConnectionCommand::prepareForNextPeer(int wait) { bool PeerInitiateConnectionCommand::prepareForRetry(int wait) { PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(cuid, + _requestGroup, peer, e, btContext); e->commands.push_back(command); return true; } + +void PeerInitiateConnectionCommand::onAbort(Exception* ex) { + peerStorage->returnPeer(peer); +} + +bool PeerInitiateConnectionCommand::exitBeforeExecute() +{ + return btRuntime->isHalt(); +} diff --git a/src/PeerInitiateConnectionCommand.h b/src/PeerInitiateConnectionCommand.h index 7a86f097..ee366ce6 100644 --- a/src/PeerInitiateConnectionCommand.h +++ b/src/PeerInitiateConnectionCommand.h @@ -36,19 +36,28 @@ #define _D_PEER_INITIATE_CONNECTION_H_ #include "PeerAbstractCommand.h" +#include "RequestGroupAware.h" +#include "BtContextAwareCommand.h" -class PeerInitiateConnectionCommand : public PeerAbstractCommand { +class PeerInitiateConnectionCommand : public PeerAbstractCommand, + public BtContextAwareCommand, + public RequestGroupAware +{ protected: - bool executeInternal(); - bool prepareForRetry(int wait); - bool prepareForNextPeer(int wait); + virtual bool executeInternal(); + virtual bool prepareForRetry(int wait); + virtual bool prepareForNextPeer(int wait); + virtual void onAbort(Exception* ex); + virtual bool exitBeforeExecute(); + public: PeerInitiateConnectionCommand(int cuid, + RequestGroup* requestGroup, const PeerHandle& peer, - TorrentDownloadEngine* e, + DownloadEngine* e, const BtContextHandle& btContext); - ~PeerInitiateConnectionCommand(); + virtual ~PeerInitiateConnectionCommand(); }; #endif // _D_PEER_INITIATE_CONNECTION_H_ diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 522b02ab..7d9794ac 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -33,6 +33,7 @@ */ /* copyright --> */ #include "PeerInteractionCommand.h" +#include "DownloadEngine.h" #include "PeerInitiateConnectionCommand.h" #include "PeerMessageUtil.h" #include "DefaultBtInteractive.h" @@ -45,17 +46,20 @@ #include "DefaultBtRequestFactory.h" #include "DefaultBtMessageFactory.h" #include "DefaultBtInteractive.h" -#include "PeerConnection.h" #include "CUIDCounter.h" #include PeerInteractionCommand::PeerInteractionCommand(int32_t cuid, + RequestGroup* requestGroup, const PeerHandle& p, - TorrentDownloadEngine* e, + DownloadEngine* e, const BtContextHandle& btContext, const SocketHandle& s, - Seq sequence) - :PeerAbstractCommand(cuid, p, e, btContext, s), + Seq sequence, + const PeerConnectionHandle& passedPeerConnection) + :PeerAbstractCommand(cuid, p, e, s), + BtContextAwareCommand(btContext), + RequestGroupAware(requestGroup), sequence(sequence), btInteractive(0), maxDownloadSpeedLimit(0) @@ -71,8 +75,8 @@ PeerInteractionCommand::PeerInteractionCommand(int32_t cuid, factory->setBtContext(btContext); factory->setPeer(peer); - PeerConnectionHandle peerConnection = - new PeerConnection(cuid, socket, e->option); + PeerConnectionHandle peerConnection = passedPeerConnection.isNull() ? + new PeerConnection(cuid, socket, e->option) : passedPeerConnection; DefaultBtMessageDispatcherHandle dispatcher = new DefaultBtMessageDispatcher(); dispatcher->setCuid(cuid); @@ -128,12 +132,15 @@ PeerInteractionCommand::PeerInteractionCommand(int32_t cuid, peer->activate(); maxDownloadSpeedLimit = e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT); + + btRuntime->increaseConnections(); } PeerInteractionCommand::~PeerInteractionCommand() { peer->deactivate(); PEER_OBJECT_CLUSTER(btContext)->unregisterHandle(peer->getId()); - + + btRuntime->decreaseConnections(); //logger->debug("CUID#%d - unregistered message factory using ID:%s", //cuid, peer->getId().c_str()); } @@ -205,6 +212,7 @@ bool PeerInteractionCommand::prepareForNextPeer(int32_t wait) { peer->cuid = CUIDCounterSingletonHolder::instance()->newID(); PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(peer->cuid, + _requestGroup, peer, e, btContext); @@ -220,5 +228,12 @@ bool PeerInteractionCommand::prepareForRetry(int32_t wait) { void PeerInteractionCommand::onAbort(Exception* ex) { btInteractive->cancelAllPiece(); - PeerAbstractCommand::onAbort(ex); + peerStorage->returnPeer(peer); + //PeerAbstractCommand::onAbort(ex); } + +bool PeerInteractionCommand::exitBeforeExecute() +{ + return btRuntime->isHalt(); +} + diff --git a/src/PeerInteractionCommand.h b/src/PeerInteractionCommand.h index 0f999611..046504cc 100644 --- a/src/PeerInteractionCommand.h +++ b/src/PeerInteractionCommand.h @@ -36,9 +36,15 @@ #define _D_PEER_INTERACTION_COMMAND_H_ #include "PeerAbstractCommand.h" +#include "RequestGroupAware.h" +#include "BtContextAwareCommand.h" #include "BtInteractive.h" +#include "PeerConnection.h" -class PeerInteractionCommand : public PeerAbstractCommand { +class PeerInteractionCommand : public PeerAbstractCommand, + public BtContextAwareCommand, + public RequestGroupAware +{ public: enum Seq { INITIATOR_SEND_HANDSHAKE, @@ -55,13 +61,16 @@ protected: virtual bool prepareForRetry(int32_t wait); virtual bool prepareForNextPeer(int32_t wait); virtual void onAbort(Exception* ex); + virtual bool exitBeforeExecute(); public: PeerInteractionCommand(int32_t cuid, + RequestGroup* requestGroup, const PeerHandle& peer, - TorrentDownloadEngine* e, + DownloadEngine* e, const BtContextHandle& btContext, const SocketHandle& s, - Seq sequence); + Seq sequence, + const PeerConnectionHandle& peerConnection = 0); virtual ~PeerInteractionCommand(); diff --git a/src/PeerListenCommand.cc b/src/PeerListenCommand.cc index e9e7b11c..f8162c40 100644 --- a/src/PeerListenCommand.cc +++ b/src/PeerListenCommand.cc @@ -33,17 +33,18 @@ */ /* copyright --> */ #include "PeerListenCommand.h" -#include "PeerInteractionCommand.h" +#include "DownloadEngine.h" +#include "Peer.h" +#include "RequestGroupMan.h" #include "RecoverableException.h" #include "CUIDCounter.h" #include "message.h" +#include "PeerReceiveHandshakeCommand.h" -PeerListenCommand::PeerListenCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext) - :BtContextAwareCommand(cuid, btContext), - e(e), - _lowestSpeedLimit(20*1024) {} +PeerListenCommand::PeerListenCommand(int32_t cuid, DownloadEngine* e): + Command(cuid), + e(e), + _lowestSpeedLimit(20*1024) {} PeerListenCommand::~PeerListenCommand() {} @@ -68,7 +69,7 @@ int32_t PeerListenCommand::bindPort(int32_t portRangeStart, int32_t portRangeEnd } bool PeerListenCommand::execute() { - if(btRuntime->isHalt()) { + if(e->isHaltRequested() || e->_requestGroupMan->countRequestGroup() == 0) { return true; } for(int32_t i = 0; i < 3 && socket->isReadable(0); i++) { @@ -80,24 +81,20 @@ bool PeerListenCommand::execute() { pair localInfo; peerSocket->getAddrInfo(localInfo); - TransferStat tstat = peerStorage->calculateStat(); - if(peerInfo.first != localInfo.first && - (!pieceStorage->downloadFinished() && tstat.getDownloadSpeed() < _lowestSpeedLimit || - btRuntime->getConnections() < MAX_PEERS)) { - PeerHandle peer = PeerHandle(new Peer(peerInfo.first, peerInfo.second, - btContext->getPieceLength(), - btContext->getTotalLength())); - if(peerStorage->addIncomingPeer(peer)) { - peer->cuid = CUIDCounterSingletonHolder::instance()->newID(); - PeerInteractionCommand* command = - new PeerInteractionCommand(peer->cuid, peer, e, - btContext, - peerSocket, - PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE); - e->commands.push_back(command); - logger->debug(MSG_INCOMING_PEER_CONNECTION, cuid, peer->cuid); - } + if(peerInfo.first == localInfo.first) { + continue; } + PeerHandle peer = new Peer(peerInfo.first, peerInfo.second, 0, 0); + PeerReceiveHandshakeCommand* command = + new PeerReceiveHandshakeCommand(CUIDCounterSingletonHolder::instance()->newID(), + peer, e, peerSocket); + e->commands.push_back(command); + logger->debug("Accepted the connection from %s:%d.", + peer->ipaddr.c_str(), + peer->port); + logger->debug("Added CUID#%d to receive Bt handshake.", + command->getCuid()); + } catch(RecoverableException* ex) { logger->debug(MSG_ACCEPT_FAILURE, ex, cuid); delete ex; diff --git a/src/PeerListenCommand.h b/src/PeerListenCommand.h index e385da2d..5997dfee 100644 --- a/src/PeerListenCommand.h +++ b/src/PeerListenCommand.h @@ -35,22 +35,22 @@ #ifndef _D_PEER_LISTEN_COMMAND_H_ #define _D_PEER_LISTEN_COMMAND_H_ -#include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" +#include "Command.h" +#include "Socket.h" -class PeerListenCommand : public BtContextAwareCommand { +class DownloadEngine; + +class PeerListenCommand : public Command { private: - TorrentDownloadEngine* e; + DownloadEngine* e; SocketHandle socket; int32_t _lowestSpeedLimit; public: - PeerListenCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext); + PeerListenCommand(int32_t cuid, DownloadEngine* e); virtual ~PeerListenCommand(); - bool execute(); + virtual bool execute(); int32_t bindPort(int32_t portRangeStart, int32_t portRangeEnd); diff --git a/src/PeerReceiveHandshakeCommand.cc b/src/PeerReceiveHandshakeCommand.cc new file mode 100644 index 00000000..81d9fb72 --- /dev/null +++ b/src/PeerReceiveHandshakeCommand.cc @@ -0,0 +1,101 @@ +/* */ +#include "PeerReceiveHandshakeCommand.h" +#include "PeerConnection.h" +#include "DownloadEngine.h" +#include "BtHandshakeMessage.h" +#include "Util.h" +#include "BtContext.h" +#include "DlAbortEx.h" +#include "PeerInteractionCommand.h" +#include "message.h" + +PeerReceiveHandshakeCommand::PeerReceiveHandshakeCommand(int32_t cuid, + const PeerHandle& peer, + DownloadEngine* e, + const SocketHandle& s): + PeerAbstractCommand(cuid, peer, e, s), + _peerConnection(new PeerConnection(cuid, s, e->option)), + _lowestSpeedLimit(20*1024) +{} + +PeerReceiveHandshakeCommand::~PeerReceiveHandshakeCommand() {} + +bool PeerReceiveHandshakeCommand::exitBeforeExecute() +{ + return e->isHaltRequested(); +} + +bool PeerReceiveHandshakeCommand::executeInternal() +{ + unsigned char data[BtHandshakeMessage::MESSAGE_LENGTH]; + int32_t dataLength = BtHandshakeMessage::MESSAGE_LENGTH; + // ignore return value. The received data is kept in PeerConnection object + // because of peek = true. + _peerConnection->receiveHandshake(data, dataLength, true); + // To handle tracker's NAT-checking feature + if(dataLength >= 48) { + // check info_hash + string infoHash = Util::toHex(&data[28], INFO_HASH_LENGTH); + BtContextHandle btContext = BtRegistry::getBtContext(infoHash); + if(btContext.isNull() || !BT_RUNTIME(btContext)->ready()) { + throw new DlAbortEx("Unknown info hash %s", infoHash.c_str()); + } + TransferStat tstat = PEER_STORAGE(btContext)->calculateStat(); + if(!PIECE_STORAGE(btContext)->downloadFinished() && tstat.getDownloadSpeed() < _lowestSpeedLimit || + BT_RUNTIME(btContext)->getConnections() < MAX_PEERS) { + peer->reconfigure(btContext->getPieceLength(), btContext->getTotalLength()); + PEER_STORAGE(btContext)->addIncomingPeer(peer); + + peer->cuid = cuid; + + PeerInteractionCommand* command = + new PeerInteractionCommand(cuid, + btContext->getOwnerRequestGroup(), + peer, + e, + btContext, + socket, + PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE, + _peerConnection); + e->commands.push_back(command); + logger->debug(MSG_INCOMING_PEER_CONNECTION, cuid, peer->cuid); + } + return true; + } else { + e->commands.push_back(this); + return false; + } +} diff --git a/src/PeerReceiveHandshakeCommand.h b/src/PeerReceiveHandshakeCommand.h new file mode 100644 index 00000000..26b907ad --- /dev/null +++ b/src/PeerReceiveHandshakeCommand.h @@ -0,0 +1,68 @@ +/* */ +#ifndef _D_PEER_RECEIVE_HANDSHAKE_COMMAND_H_ +#define _D_PEER_RECEIVE_HANDSHAKE_COMMAND_H_ + +#include "PeerAbstractCommand.h" + +class PeerConnection; +extern typedef SharedHandle PeerConnectionHandle; + +class PeerReceiveHandshakeCommand:public PeerAbstractCommand +{ +private: + PeerConnectionHandle _peerConnection; + + int32_t _lowestSpeedLimit; + +protected: + virtual bool executeInternal(); + /* + virtual bool prepareForRetry(int32_t wait); + virtual bool prepareForNextPeer(int32_t wait); + */ + virtual bool exitBeforeExecute(); +public: + PeerReceiveHandshakeCommand(int32_t cuid, + const PeerHandle& peer, + DownloadEngine* e, + const SocketHandle& s); + + virtual ~PeerReceiveHandshakeCommand(); + + +}; + +#endif // _D_PEER_RECEIVE_HANDSHAKE_COMMAND_H_ diff --git a/src/PeerStorage.h b/src/PeerStorage.h index 1b463936..a7e4accd 100644 --- a/src/PeerStorage.h +++ b/src/PeerStorage.h @@ -37,70 +37,7 @@ #include "common.h" #include "Peer.h" - -class TransferStat { -public: - int32_t downloadSpeed; - int32_t uploadSpeed; - int64_t sessionDownloadLength; - int64_t sessionUploadLength; - - void copy(const TransferStat& stat) - { - downloadSpeed = stat.downloadSpeed; - uploadSpeed = stat.uploadSpeed; - sessionDownloadLength = stat.sessionDownloadLength; - sessionUploadLength = stat.sessionUploadLength; - } -public: - TransferStat():downloadSpeed(0), uploadSpeed(0), - sessionDownloadLength(0), sessionUploadLength(0) {} - - TransferStat(const TransferStat& stat) - { - copy(stat); - } - - TransferStat& operator=(const TransferStat& stat) - { - if(this != &stat) { - copy(stat); - } - return *this; - } - - int32_t getDownloadSpeed() const { - return downloadSpeed; - } - - void setDownloadSpeed(int32_t s) { downloadSpeed = s; } - - int32_t getUploadSpeed() const { - return uploadSpeed; - } - - void setUploadSpeed(int32_t s) { uploadSpeed = s; } - - /** - * Returns the number of bytes downloaded since the program started. - * This is not the total number of bytes downloaded. - */ - int64_t getSessionDownloadLength() const { - return sessionDownloadLength; - } - - void setSessionDownloadLength(int64_t s) { sessionDownloadLength = s; } - - /** - * Returns the number of bytes uploaded since the program started. - * This is not the total number of bytes uploaded. - */ - int64_t getSessionUploadLength() const { - return sessionUploadLength; - } - - void setSessionUploadLength(int64_t s) { sessionUploadLength = s; } -}; +#include "TransferStat.h" class PeerStorage { public: diff --git a/src/Piece.cc b/src/Piece.cc index e227bbaa..6aec598e 100644 --- a/src/Piece.cc +++ b/src/Piece.cc @@ -101,3 +101,16 @@ BlockIndexes Piece::getAllMissingBlockIndexes() const { string Piece::toString() const { return "piece: index="+Util::itos(index)+", length="+Util::itos(length); } + +void Piece::reconfigure(int32_t length) +{ + this->length = length; + bitfield = + BitfieldManFactory::getFactoryInstance()->createBitfieldMan(BLOCK_LENGTH, length); +} + +void Piece::setBitfield(const unsigned char* bitfield, int32_t len) +{ + this->bitfield->setBitfield(bitfield, len); +} + diff --git a/src/Piece.h b/src/Piece.h index 8b779560..f9f04788 100644 --- a/src/Piece.h +++ b/src/Piece.h @@ -117,6 +117,11 @@ public: bool isBlockUsed(int32_t index) const { return bitfield->isUseBitSet(index); } + + /** + * Loses current bitfield state. + */ + void reconfigure(int32_t length); }; typedef SharedHandle PieceHandle; diff --git a/src/PieceStorage.h b/src/PieceStorage.h index e41aeea6..64e6d523 100644 --- a/src/PieceStorage.h +++ b/src/PieceStorage.h @@ -36,9 +36,15 @@ #define _D_PIECE_STORAGE_H_ #include "common.h" -#include "Peer.h" -#include "Piece.h" -#include "DiskAdaptor.h" +#include "TimeA2.h" + +class Piece; +extern typedef SharedHandle PieceHandle; +extern typedef deque Pieces; +class Peer; +extern typedef SharedHandle PeerHandle; +class DiskAdaptor; +extern typedef SharedHandle DiskAdaptorHandle; class PieceStorage { public: @@ -66,12 +72,30 @@ public: */ virtual PieceHandle getMissingFastPiece(const PeerHandle& peer) = 0; + /** + * Returns a missing piece if available. Otherwise returns 0; + */ + virtual PieceHandle getMissingPiece() = 0; + + /** + * Returns a missing piece whose index is index. + * If a piece whose index is index is already acquired or currently used, + * then returns 0. + * Also returns 0 if any of missing piece is not available. + */ + virtual PieceHandle getMissingPiece(int32_t index) = 0; + /** * Returns the piece denoted by index. * No status of the piece is changed in this method. */ virtual PieceHandle getPiece(int32_t index) = 0; + /** + * Marks the piece whose index is index as missing. + */ + virtual void markPieceMissing(int32_t index) = 0; + /** * Tells that the download of the specfied piece completes. */ @@ -88,6 +112,8 @@ public: */ virtual bool hasPiece(int32_t index) = 0; + virtual bool isPieceUsed(int32_t index) = 0; + virtual int64_t getTotalLength() = 0; virtual int64_t getFilteredTotalLength() = 0; @@ -163,9 +189,15 @@ public: virtual void markAllPiecesDone() = 0; /** - * Validates file integrity by comparing checksums. + * Sets all bits in bitfield(0 to length) to 1. */ - virtual void checkIntegrity() = 0; + virtual void markPiecesDone(int64_t length) = 0; + + virtual void addInFlightPiece(const Pieces& pieces) = 0; + + virtual int32_t countInFlightPiece() = 0; + + virtual Pieces getInFlightPieces() = 0; }; typedef SharedHandle PieceStorageHandle; diff --git a/src/ConsoleFileAllocationMonitor.h b/src/PiecedSegment.cc similarity index 51% rename from src/ConsoleFileAllocationMonitor.h rename to src/PiecedSegment.cc index f1c89eee..3588bfe1 100644 --- a/src/ConsoleFileAllocationMonitor.h +++ b/src/PiecedSegment.cc @@ -32,74 +32,69 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_CONSOLE_FILE_ALLOCATION_MONITOR_H_ -#define _D_CONSOLE_FILE_ALLOCATION_MONITOR_H_ +#include "PiecedSegment.h" +#include "Piece.h" -#include "FileAllocationMonitor.h" +PiecedSegment::PiecedSegment(int32_t pieceLength, const PieceHandle& piece): + _pieceLength(pieceLength), _overflowLength(0), _piece(piece) +{ + _writtenLength = _piece->getAllMissingBlockIndexes().front()*BLOCK_LENGTH; +} -class ConsoleFileAllocationMonitor : public FileAllocationMonitor { -private: - string filename; - int64_t min; - int64_t max; - int64_t current; -public: - ConsoleFileAllocationMonitor():min(0), max(0), current(0) {} +PiecedSegment::~PiecedSegment() {} - virtual ~ConsoleFileAllocationMonitor() {} +bool PiecedSegment::complete() const +{ + return _piece->pieceComplete(); +} - virtual void setFilename(const string& filename) { - this->filename = filename; +int32_t PiecedSegment::getIndex() const +{ + return _piece->getIndex(); +} + +int64_t PiecedSegment::getPosition() const +{ + return ((int64_t)_piece->getIndex())*_pieceLength; +} + +int64_t PiecedSegment::getPositionToWrite() const +{ + return getPosition()+_writtenLength; +} + +int32_t PiecedSegment::getLength() const +{ + return _piece->getLength(); +} + +void PiecedSegment::updateWrittenLength(int32_t bytes) +{ + int32_t newWrittenLength = _writtenLength+bytes; + if(newWrittenLength > _piece->getLength()) { + _overflowLength = newWrittenLength-_piece->getLength(); + newWrittenLength = _piece->getLength(); } - - virtual void setMinValue(const int64_t& min) { - if(max < min) { - this->min = max; - } else { - this->min = min; - } + for(int32_t i = _writtenLength/BLOCK_LENGTH; i < newWrittenLength/BLOCK_LENGTH; ++i) { + _piece->completeBlock(i); } - - int64_t getMinValue() const { - return min; + if(newWrittenLength == _piece->getLength()) { + _piece->completeBlock(_piece->countBlock()-1); } + _writtenLength = newWrittenLength; +} - virtual void setMaxValue(const int64_t& max) { - if(max < min) { - this->max = min; - } else { - this->max = max; - } - } +PieceHandle PiecedSegment::getPiece() const +{ + return _piece; +} - int64_t getMaxValue() const { - return max; - } +bool PiecedSegment::operator==(const PiecedSegment& segment) const +{ + return _piece == segment._piece; +} - virtual void setCurrentValue(const int64_t& current) { - if(current > max) { - this->current = max; - } else { - this->current = current; - } - } - - int64_t getCurrentValue() const { - return current; - } - - virtual void showProgress(); -}; - -class ConsoleFileAllocationMonitorFactory : public FileAllocationMonitorFactory { -public: - ConsoleFileAllocationMonitorFactory() {} - - virtual FileAllocationMonitorHandle createNewMonitor() { - return new ConsoleFileAllocationMonitor(); - } -}; - -typedef SharedHandle ConsoleFileAllocationMonitorFactoryHandle; - -#endif // _D_CONSOLE_FILE_ALLOCATION_MONITOR_H_ +bool PiecedSegment::operator!=(const PiecedSegment& segment) const +{ + return !(*this == segment); +} diff --git a/src/PiecedSegment.h b/src/PiecedSegment.h new file mode 100644 index 00000000..4c778f05 --- /dev/null +++ b/src/PiecedSegment.h @@ -0,0 +1,94 @@ +/* */ +#ifndef _D_PIECED_SEGMENT_H_ +#define _D_PIECED_SEGMENT_H_ + +#include "Segment.h" + +class PiecedSegment:public Segment { +private: + /** + * Piece class has length property but it is a actual length of piece. + * The last piece likely have shorter length than the other length. + */ + int32_t _pieceLength; + int32_t _writtenLength; + int32_t _overflowLength; + PieceHandle _piece; + +public: + PiecedSegment(int32_t pieceLength, const PieceHandle& piece); + + virtual ~PiecedSegment(); + + virtual bool complete() const; + + virtual int32_t getIndex() const; + + virtual int64_t getPosition() const; + + virtual int64_t getPositionToWrite() const; + + virtual int32_t getLength() const; + + virtual int32_t getSegmentLength() const + { + return _pieceLength; + } + + virtual int32_t getWrittenLength() const + { + return _writtenLength; + } + + virtual int32_t getOverflowLength() const + { + return _overflowLength; + } + + virtual void updateWrittenLength(int32_t bytes); + + virtual PieceHandle getPiece() const; + + bool operator==(const PiecedSegment& segment) const; + + bool operator!=(const PiecedSegment& segment) const; + +}; + +typedef SharedHandle PiecedSegmentHandle; + +#endif // _D_PIECED_SEGMENT_H_ + diff --git a/src/PostDownloadHandler.cc b/src/PostDownloadHandler.cc new file mode 100644 index 00000000..d7eab07e --- /dev/null +++ b/src/PostDownloadHandler.cc @@ -0,0 +1,46 @@ +/* */ +#include "PostDownloadHandler.h" +#include "Util.h" + +PostDownloadHandler::PostDownloadHandler(const string& extension, const Option* option):_extension(extension), _option(option) +{} + +PostDownloadHandler::~PostDownloadHandler() {} + +bool PostDownloadHandler::canHandle(const string& path) +{ + return Util::endsWith(path, _extension); +} diff --git a/src/TorrentAutoSaveCommand.h b/src/PostDownloadHandler.h similarity index 69% rename from src/TorrentAutoSaveCommand.h rename to src/PostDownloadHandler.h index 86d31641..70a0b5ce 100644 --- a/src/TorrentAutoSaveCommand.h +++ b/src/PostDownloadHandler.h @@ -32,28 +32,32 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_TORRENT_AUTO_SAVE_COMMAND_H_ -#define _D_TORRENT_AUTO_SAVE_COMMAND_H_ +#ifndef _D_POST_DOWNLOAD_HANDLER_H_ +#define _D_POST_DOWNLOAD_HANDLER_H_ -#include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" -#include "TimeA2.h" -#include "BtContext.h" +#include "common.h" -class TorrentAutoSaveCommand : public BtContextAwareCommand { +class Option; +class RequestGroup; +typedef SharedHandle RequestGroupHandle; +typedef deque RequestGroups; + +class PostDownloadHandler +{ private: - TorrentDownloadEngine* e; - int32_t interval; - Time checkPoint; + string _extension; +protected: + const Option* _option; public: - TorrentAutoSaveCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext, - int32_t interval); + PostDownloadHandler(const string& extension, const Option* option); - ~TorrentAutoSaveCommand(); + virtual ~PostDownloadHandler(); - bool execute(); + bool canHandle(const string& path); + + virtual RequestGroups getNextRequestGroups(const string& path) = 0; }; -#endif // _D_TORRENT_AUTO_SAVE_COMMAND_H_ +typedef SharedHandle PostDownloadHandlerHandle; +typedef deque PostDownloadHandlers; +#endif // _D_POST_DOWNLOAD_HANDLER_H_ diff --git a/src/ProgressAwareEntry.h b/src/ProgressAwareEntry.h index 5b11845e..af306ae6 100644 --- a/src/ProgressAwareEntry.h +++ b/src/ProgressAwareEntry.h @@ -41,11 +41,11 @@ class ProgressAwareEntry { public: virtual ~ProgressAwareEntry() {} - virtual int64_t getCurrentLength() const = 0; + virtual int64_t getCurrentLength() = 0; - virtual int64_t getTotalLength() const = 0; + virtual int64_t getTotalLength() = 0; - virtual bool finished() const = 0; + virtual bool finished() = 0; }; typedef SharedHandle ProgressAwareEntryHandle; diff --git a/src/RealtimeCommand.cc b/src/RealtimeCommand.cc index a613fc59..4c9eff58 100644 --- a/src/RealtimeCommand.cc +++ b/src/RealtimeCommand.cc @@ -41,7 +41,7 @@ bool RealtimeCommand::execute() try { return executeInternal(); } catch(Exception* e) { - _requestGroup->getSegmentMan()->errors++; + //_requestGroup->getSegmentMan()->errors++; bool r = handleException(e); delete e; return r; diff --git a/src/RealtimeCommand.h b/src/RealtimeCommand.h index 915aa56b..203c0eeb 100644 --- a/src/RealtimeCommand.h +++ b/src/RealtimeCommand.h @@ -39,16 +39,17 @@ #include "RequestGroup.h" #include "DownloadEngine.h" #include "Exception.h" +#include "RequestGroupAware.h" -class RealtimeCommand : public Command { +class RealtimeCommand : public Command, public RequestGroupAware { protected: - RequestGroup* _requestGroup; DownloadEngine* _e; public: RealtimeCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e): Command(cuid), - _requestGroup(requestGroup), - _e(e) {} + RequestGroupAware(requestGroup), + _e(e) + {} virtual ~RealtimeCommand() {} diff --git a/src/Request.cc b/src/Request.cc index 938c6186..bf8893f3 100644 --- a/src/Request.cc +++ b/src/Request.cc @@ -41,7 +41,7 @@ const string Request::METHOD_GET = "get"; const string Request::METHOD_HEAD = "head"; -Request::Request():port(0), tryCount(0), keepAlive(true), method(METHOD_GET), +Request::Request():port(0), tryCount(0), keepAlive(false), method(METHOD_GET), _httpAuthResolver(0), _httpProxyAuthResolver(0), _ftpAuthResolver(0), diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 01e95a40..6d75bad0 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -34,34 +34,186 @@ /* copyright --> */ #include "RequestGroup.h" #include "DownloadEngine.h" +#include "DefaultSegmentManFactory.h" +#include "NullProgressInfoFile.h" +#include "SegmentManFactory.h" +#include "Dependency.h" #include "prefs.h" -#include "DefaultDiskWriter.h" #include "RequestFactory.h" #include "InitiateConnectionCommandFactory.h" #include "CUIDCounter.h" -#include "DlAbortEx.h" #include "File.h" #include "message.h" -#include "DlAbortEx.h" #include "Util.h" -#include "FatalException.h" -#include "DownloadCommand.h" +#include "BtRegistry.h" +#include "LogFactory.h" +#include "DiskAdaptor.h" +#include "DiskWriterFactory.h" #ifdef ENABLE_MESSAGE_DIGEST -#include "CheckIntegrityCommand.h" -#include "CheckIntegrityEntry.h" +# include "CheckIntegrityCommand.h" #endif // ENABLE_MESSAGE_DIGEST +#ifdef ENABLE_BITTORRENT +# include "BtCheckIntegrityEntry.h" +# include "DefaultPieceStorage.h" +# include "DefaultBtProgressInfoFile.h" +# include "DefaultPeerStorage.h" +# include "DefaultBtAnnounce.h" +# include "BtSetup.h" +# include "BtFileAllocationEntry.h" +# include "BtPostDownloadHandler.h" +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK +# include "MetalinkPostDownloadHandler.h" +#endif // ENABLE_METALINK #include +int32_t RequestGroup::_gidCounter = 0; + +RequestGroup::RequestGroup(const Option* option, + const Strings& uris): + _gid(++_gidCounter), + _hintTotalLength(0), + _uris(uris), + _numConcurrentCommand(0), + _numStreamConnection(0), + _numCommand(0), + _segmentMan(0), + _segmentManFactory(new DefaultSegmentManFactory(option)), + _downloadContext(0), + _pieceStorage(0), + _progressInfoFile(new NullProgressInfoFile()), + _diskWriterFactory(0), + _dependency(0), + _preLocalFileCheckEnabled(true), + _haltRequested(false), + _option(option), + _logger(LogFactory::getInstance()) +{ + if(_option->get(PREF_FILE_ALLOCATION) == V_PREALLOC) { + _fileAllocationEnabled = true; + } else { + _fileAllocationEnabled = false; + } + initializePostDownloadHandler(); +} + +RequestGroup::~RequestGroup() {} + SegmentManHandle RequestGroup::initSegmentMan() { - _segmentMan = _segmentManFactory->createNewInstance(); - _segmentMan->ufilename = _ufilename; - if(!_topDir.empty() && _topDir != ".") { - _segmentMan->dir += "/"+_topDir; - } + _segmentMan = _segmentManFactory->createNewInstance(_downloadContext, + _pieceStorage); return _segmentMan; } +bool RequestGroup::downloadFinished() const +{ + if(_pieceStorage.isNull()) { + return false; + } else { + return _pieceStorage->downloadFinished(); + } +} + +void RequestGroup::closeFile() +{ + if(!_pieceStorage.isNull()) { + _pieceStorage->getDiskAdaptor()->closeFile(); + } +} + +Commands RequestGroup::createInitialCommand(DownloadEngine* e) +{ + // If this includes torrent download, then this method returns + // the command that torrent download requires, such as + // TrackerWatcherCommand and so on. + + // It is better to avoid to using BtTorrent specific classes here. +#ifdef ENABLE_BITTORRENT + { + BtContextHandle btContext = _downloadContext; + if(!btContext.isNull()) { + if(btContext->getFileEntries().size() > 1) { + // this is really multi file torrent. + // clear http/ftp uris because the current implementation does not + // allow integrating multi-file torrent and http/ftp. + _logger->debug("Clearing http/ftp URIs because the current implementation does not allow integrating multi-file torrent and http/ftp."); + _uris.clear(); + } + + _pieceStorage = new DefaultPieceStorage(btContext, _option); + _pieceStorage->initStorage(); + initSegmentMan(); + + BtProgressInfoFileHandle progressInfoFile = + new DefaultBtProgressInfoFile(_downloadContext, + _pieceStorage, + _option); + + BtRegistry::registerBtContext(btContext->getInfoHashAsString(), btContext); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + _pieceStorage); + BtRegistry::registerBtProgressInfoFile(btContext->getInfoHashAsString(), + progressInfoFile); + + + BtRuntimeHandle btRuntime = new BtRuntime(); + btRuntime->setListenPort(_option->getAsInt(PREF_LISTEN_PORT)); + BtRegistry::registerBtRuntime(btContext->getInfoHashAsString(), btRuntime); + + PeerStorageHandle peerStorage = new DefaultPeerStorage(btContext, _option); + BtRegistry::registerPeerStorage(btContext->getInfoHashAsString(), peerStorage); + + BtAnnounceHandle btAnnounce = new DefaultBtAnnounce(btContext, _option); + BtRegistry::registerBtAnnounce(btContext->getInfoHashAsString(), btAnnounce); + btAnnounce->shuffleAnnounce(); + + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + + // Call Load, Save and file allocation command here + if(progressInfoFile->exists()) { + // load .aria2 file if it exists. + progressInfoFile->load(); + _pieceStorage->getDiskAdaptor()->openFile(); + } else { + if(_pieceStorage->getDiskAdaptor()->fileExists()) { + if(_option->get(PREF_ALLOW_OVERWRITE) != V_TRUE) { + _logger->error(MSG_FILE_ALREADY_EXISTS, + getFilePath().c_str(), + progressInfoFile->getFilename().c_str()); + // TODO we need this->haltRequested = true? + return Commands(); + } else { + _pieceStorage->getDiskAdaptor()->openFile(); + } + } else { + _pieceStorage->getDiskAdaptor()->openFile(); + } + } + _progressInfoFile = progressInfoFile; + Commands commands; + CheckIntegrityEntryHandle entry = new BtCheckIntegrityEntry(this); +#ifdef ENABLE_MESSAGE_DIGEST + if(File(getFilePath()).size() > 0 && + e->option->get(PREF_CHECK_INTEGRITY) == V_TRUE && + entry->isValidationReady()) { + entry->initValidator(); + CheckIntegrityCommand* command = + new CheckIntegrityCommand(CUIDCounterSingletonHolder::instance()->newID(), this, e, entry); + commands.push_back(command); + } else +#endif // ENABLE_MESSAGE_DIGEST + { + commands = entry->prepareForNextAction(e); + } + return commands; + } + } +#endif // ENABLE_BITTORRENT + return createNextCommand(e, 1); +} + Commands RequestGroup::createNextCommandWithAdj(DownloadEngine* e, int32_t numAdj) { int32_t numCommand = _numConcurrentCommand == 0 ? _uris.size() : _numConcurrentCommand+numAdj; @@ -71,7 +223,7 @@ Commands RequestGroup::createNextCommandWithAdj(DownloadEngine* e, int32_t numAd Commands RequestGroup::createNextCommand(DownloadEngine* e, int32_t numCommand, const string& method) { Commands commands; - for(;!_uris.empty() && commands.size() < (size_t)numCommand; _uris.pop_front()) { + for(;!_uris.empty() && numCommand--; _uris.pop_front()) { string uri = _uris.front(); _spentUris.push_back(uri); RequestHandle req = RequestFactorySingletonHolder::instance()->createRequest(); @@ -80,182 +232,46 @@ Commands RequestGroup::createNextCommand(DownloadEngine* e, int32_t numCommand, if(req->setUrl(uri)) { commands.push_back(InitiateConnectionCommandFactory::createInitiateConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(), req, this, e)); } else { - logger->error(MSG_UNRECOGNIZED_URI, - req->getUrl().c_str()); + _logger->error(MSG_UNRECOGNIZED_URI, req->getUrl().c_str()); } } return commands; } -void RequestGroup::initBitfield() -{ - _segmentMan->initBitfield(_option->getAsInt(PREF_SEGMENT_SIZE), - _segmentMan->totalSize); -} - -void RequestGroup::openExistingFile() -{ - _segmentMan->diskWriter->openExistingFile(_segmentMan->getFilePath()); -} - -void RequestGroup::markAllPiecesDone() -{ - _segmentMan->markAllPiecesDone(); -} - -void RequestGroup::markExistingPiecesDone() -{ - _segmentMan->markPieceDone(File(_segmentMan->getFilePath()).size()); -} - -void RequestGroup::markPieceDone(int64_t length) -{ - _segmentMan->markPieceDone(length); -} - -void RequestGroup::shouldCancelDownloadForSafety() -{ - if(fileExists() && !segmentFileExists()) { - if(_option->get(PREF_AUTO_FILE_RENAMING) == V_TRUE) { - if(tryAutoFileRenaming()) { - logger->notice("File already exists. Renamed to %s.", - getFilePath().c_str()); - } else { - logger->notice("File renaming failed: %s", - _segmentMan->getFilePath().c_str()); - throw new FatalException(EX_DOWNLOAD_ABORTED); - } - } else if(_option->get(PREF_ALLOW_OVERWRITE) != V_TRUE) { - logger->notice(MSG_FILE_ALREADY_EXISTS, - _segmentMan->getFilePath().c_str(), - _segmentMan->getSegmentFilePath().c_str()); - throw new FatalException(EX_DOWNLOAD_ABORTED); - } - } -} - -void RequestGroup::initAndOpenFile() -{ - File d(getDir()); - if(d.isDir()) { - } else if(d.exists()) { - throw new FatalException(EX_MAKE_DIR, getDir().c_str(), MSG_NOT_DIRECTORY); - } else if(!d.mkdirs()) { - throw new FatalException(EX_MAKE_DIR, getDir().c_str(), strerror(errno)); - } - _segmentMan->diskWriter->initAndOpenFile(_segmentMan->getFilePath()); -} - -bool RequestGroup::needsFileAllocation() const -{ - return _option->get(PREF_FILE_ALLOCATION) == V_PREALLOC - && File(_segmentMan->getFilePath()).size() < _segmentMan->totalSize; -} - -bool RequestGroup::fileExists() const -{ - return _segmentMan->fileExists(); -} - -bool RequestGroup::segmentFileExists() const -{ - return _segmentMan->segmentFileExists(); -} - string RequestGroup::getFilePath() const { - if(_segmentMan.isNull()) { + assert(!_downloadContext.isNull()); + if(_downloadContext.isNull()) { return ""; } else { - return _segmentMan->getFilePath(); + return _downloadContext->getActualBasePath(); } } -string RequestGroup::getDir() const +int64_t RequestGroup::getTotalLength() const { - if(_segmentMan.isNull()) { - return ""; + if(_pieceStorage.isNull()) { + return 0; } else { - return _segmentMan->dir; - } -} - -void RequestGroup::loadAndOpenFile() -{ - bool segFileExists = segmentFileExists(); - if(segFileExists) { - load(); - openExistingFile(); - } else if(fileExists() && _option->get(PREF_CONTINUE) == V_TRUE) { - File existingFile(getFilePath()); - if(getTotalLength() < existingFile.size()) { - throw new DlAbortEx(EX_FILE_LENGTH_MISMATCH_BETWEEN_LOCAL_AND_REMOTE, - getFilePath().c_str(), - Util::llitos(existingFile.size()).c_str(), - Util::llitos(getTotalLength()).c_str()); - } - initBitfield(); - openExistingFile(); - _segmentMan->markPieceDone(existingFile.size()); - } else { - shouldCancelDownloadForSafety(); - initBitfield(); -#ifdef ENABLE_MESSAGE_DIGEST - if(fileExists() && _option->get(PREF_CHECK_INTEGRITY) == V_TRUE) { - openExistingFile(); + if(_pieceStorage->isSelectiveDownloadingMode()) { + return _pieceStorage->getFilteredTotalLength(); } else { - initAndOpenFile(); + return _pieceStorage->getTotalLength(); } -#else // ENABLE_MESSAGE_DIGEST - initAndOpenFile(); -#endif // ENABLE_MESSAGE_DIGEST } } -bool RequestGroup::downloadFinishedByFileLength() +int64_t RequestGroup::getCompletedLength() const { - if(_segmentMan->segmentFileExists()) { - return false; - } - File existingFile(getFilePath()); - if(existingFile.exists() && - getTotalLength() == existingFile.size()) { - _segmentMan->downloadStarted = true; - initBitfield(); - _segmentMan->markAllPiecesDone(); - return true; + if(_pieceStorage.isNull()) { + return 0; } else { - return false; - } -} - -void RequestGroup::prepareForNextAction(int cuid, const RequestHandle& req, DownloadEngine* e, DownloadCommand* downloadCommand) -{ - File existingFile(getFilePath()); -#ifdef ENABLE_MESSAGE_DIGEST - if(existingFile.size() > 0 && _option->get(PREF_CHECK_INTEGRITY) == V_TRUE) { - // purge SegmentEntries - _segmentMan->purgeSegmentEntry(); - - CheckIntegrityEntryHandle entry = new CheckIntegrityEntry(cuid, req, this, downloadCommand); - entry->initValidator(); - CheckIntegrityCommand* command = new CheckIntegrityCommand(cuid, this, e, entry); - e->commands.push_back(command); - } else -#endif // ENABLE_MESSAGE_DIGEST - if(needsFileAllocation()) { - FileAllocationEntryHandle entry = new FileAllocationEntry(cuid, req, this, downloadCommand, existingFile.size()); - e->_fileAllocationMan->pushFileAllocationEntry(entry); + if(_pieceStorage->isSelectiveDownloadingMode()) { + return _pieceStorage->getFilteredCompletedLength(); } else { - if(downloadCommand) { - e->commands.push_back(downloadCommand); - } else { - Commands commands = createNextCommandWithAdj(e, -1); - Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, this, e); - commands.push_front(command); - e->addCommand(commands); - } + return _pieceStorage->getCompletedLength(); } + } } void RequestGroup::validateFilename(const string& expectedFilename, @@ -286,12 +302,12 @@ void RequestGroup::validateTotalLength(int64_t expectedTotalLength, void RequestGroup::validateFilename(const string& actualFilename) const { - validateFilename(_segmentMan->filename, actualFilename); + validateFilename(_downloadContext->getFileEntries().front()->getBasename(), actualFilename); } void RequestGroup::validateTotalLength(int64_t actualTotalLength) const { - validateTotalLength(_segmentMan->totalSize, actualTotalLength); + validateTotalLength(getTotalLength(), actualTotalLength); } void RequestGroup::validateFilenameByHint(const string& actualFilename) const @@ -304,31 +320,186 @@ void RequestGroup::validateTotalLengthByHint(int64_t actualTotalLength) const validateTotalLength(_hintTotalLength, actualTotalLength); } -void RequestGroup::setUserDefinedFilename(const string& filename) +void RequestGroup::increaseStreamConnection() { - _ufilename = filename; + ++_numStreamConnection; } -int64_t RequestGroup::getExistingFileLength() const +void RequestGroup::decreaseStreamConnection() { - return File(getFilePath()).size(); + --_numStreamConnection; } -bool RequestGroup::tryAutoFileRenaming() +int32_t RequestGroup::getNumConnection() const { - string filepath = getFilePath(); - if(filepath.empty()) { - return false; - } - for(int32_t i = 1; i < 10000; ++i) { - File newfile(filepath+"."+Util::itos(i)); - if(!newfile.exists()) { - _ufilename = newfile.getBasename(); - if(!_segmentMan.isNull()) { - _segmentMan->ufilename = _ufilename; + int32_t numConnection = _numStreamConnection; +#ifdef ENABLE_BITTORRENT + { + BtContextHandle btContext = _downloadContext; + if(!btContext.isNull()) { + BtRuntimeHandle btRuntime = BT_RUNTIME(btContext); + if(!btRuntime.isNull()) { + numConnection += btRuntime->getConnections(); } - return true; } } - return false; +#endif // ENABLE_BITTORRENT + return numConnection; +} + +void RequestGroup::increaseNumCommand() +{ + ++_numCommand; +} + +void RequestGroup::decreaseNumCommand() +{ + --_numCommand; +} + + +TransferStat RequestGroup::calculateStat() +{ + TransferStat stat; +#ifdef ENABLE_BITTORRENT + { + BtContextHandle btContext = _downloadContext; + if(!btContext.isNull()) { + PeerStorageHandle peerStorage = PEER_STORAGE(btContext); + if(!peerStorage.isNull()) { + stat = peerStorage->calculateStat(); + } + } + } +#endif // ENABLE_BITTORRENT + if(!_segmentMan.isNull()) { + stat.setDownloadSpeed(stat.getDownloadSpeed()+_segmentMan->calculateDownloadSpeed()); + } + return stat; +} + +void RequestGroup::setHaltRequested(bool f) +{ + _haltRequested = f; +#ifdef ENABLE_BITTORRENT + { + BtContextHandle btContext = _downloadContext; + if(!btContext.isNull()) { + BtRuntimeHandle btRuntime = BT_RUNTIME(btContext); + if(!btRuntime.isNull()) { + btRuntime->setHalt(f); + } + } + } +#endif // ENABLE_BITTORRENT +} + +void RequestGroup::releaseRuntimeResource() +{ +#ifdef ENABLE_BITTORRENT + BtContextHandle btContext = _downloadContext; + if(!btContext.isNull()) { + BtRegistry::unregister(btContext->getInfoHashAsString()); + } +#endif // ENABLE_BITTORRENT + if(!_pieceStorage.isNull()) { + _pieceStorage->removeAdvertisedPiece(0); + } +} + +RequestGroups RequestGroup::postDownloadProcessing() +{ + for(PostDownloadHandlers::const_iterator itr = _postDownloadHandlers.begin(); + itr != _postDownloadHandlers.end(); ++itr) { + if((*itr)->canHandle(getFilePath())) { + return (*itr)->getNextRequestGroups(getFilePath()); + } + } + return RequestGroups(); +} + +void RequestGroup::initializePostDownloadHandler() +{ + _postDownloadHandlers.push_back(new BtPostDownloadHandler(_option)); + _postDownloadHandlers.push_back(new MetalinkPostDownloadHandler(_option)); +} + +Strings RequestGroup::getUris() const +{ + Strings temp(_spentUris.begin(), _spentUris.end()); + temp.insert(temp.end(), _uris.begin(), _uris.end()); + return temp; +} + +bool RequestGroup::isDependencyResolved() +{ + if(_dependency.isNull()) { + return true; + } + return _dependency->resolve(); +} + +void RequestGroup::setSegmentManFactory(const SegmentManFactoryHandle& segmentManFactory) +{ + _segmentManFactory = segmentManFactory; +} + +void RequestGroup::dependsOn(const DependencyHandle& dep) +{ + _dependency = dep; +} + +void RequestGroup::setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory) +{ + _diskWriterFactory = diskWriterFactory; +} + +DiskWriterFactoryHandle RequestGroup::getDiskWriterFactory() const +{ + return _diskWriterFactory; +} + +void RequestGroup::addPostDownloadHandler(const PostDownloadHandlerHandle& handler) +{ + _postDownloadHandlers.push_back(handler); +} + +void RequestGroup::clearPostDowloadHandler() +{ + _postDownloadHandlers.clear(); +} + +SegmentManHandle RequestGroup::getSegmentMan() const +{ + return _segmentMan; +} + +DownloadContextHandle RequestGroup::getDownloadContext() const +{ + return _downloadContext; +} + +void RequestGroup::setDownloadContext(const DownloadContextHandle& downloadContext) +{ + _downloadContext = downloadContext; +} + +PieceStorageHandle RequestGroup::getPieceStorage() const +{ + return _pieceStorage; +} + +void RequestGroup::setPieceStorage(const PieceStorageHandle& pieceStorage) +{ + _pieceStorage = pieceStorage; +} + +BtProgressInfoFileHandle RequestGroup::getProgressInfoFile() const +{ + return _progressInfoFile; +} + +void RequestGroup::setProgressInfoFile(const BtProgressInfoFileHandle& progressInfoFile) +{ + _progressInfoFile = progressInfoFile; } diff --git a/src/RequestGroup.h b/src/RequestGroup.h index 83317786..f60aea33 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -36,38 +36,86 @@ #define _D_REQUEST_GROUP_H_ #include "common.h" -#include "SegmentMan.h" -#include "LogFactory.h" -#include "Command.h" -#include "SegmentManFactory.h" -#include "DefaultSegmentManFactory.h" -#ifdef ENABLE_MESSAGE_DIGEST -# include "ChunkChecksum.h" -# include "Checksum.h" -#endif // ENABLE_MESSAGE_DIGEST - -class DownloadCommand; +#include "TransferStat.h" class DownloadEngine; +class SegmentMan; +extern typedef SharedHandle SegmentManHandle; +class SegmentManFactory; +extern typedef SharedHandle SegmentManFactoryHandle; +class Command; +extern typedef deque Commands; +class DownloadContext; +extern typedef SharedHandle DownloadContextHandle; +class PieceStorage; +extern typedef SharedHandle PieceStorageHandle; +class BtProgressInfoFile; +extern typedef SharedHandle BtProgressInfoFileHandle; +class Dependency; +extern typedef SharedHandle DependencyHandle; +class DlAbortEx; +class PostDownloadHandler; +extern typedef SharedHandle PostDownloadHandlerHandle; +extern typedef deque PostDownloadHandlers; +class DiskWriterFactory; +extern typedef SharedHandle DiskWriterFactoryHandle; +class Option; +class Logger; + +class RequestGroup; +extern typedef SharedHandle RequestGroupHandle; +extern typedef deque RequestGroups; class RequestGroup { private: + static int32_t _gidCounter; + int32_t _gid; + + /** + * Hint for total length and filename. + * These values are used to verify whether the file http/ftp server sends back + * is correct one. + */ int64_t _hintTotalLength; string _hintFilename; - string _ufilename; - string _topDir; + Strings _uris; Strings _spentUris; + + int32_t _numConcurrentCommand; + + /** + * This is the number of connections used in streaming protocol(http/ftp) + */ + int32_t _numStreamConnection; + + int32_t _numCommand; + SegmentManHandle _segmentMan; SegmentManFactoryHandle _segmentManFactory; + + DownloadContextHandle _downloadContext; + + PieceStorageHandle _pieceStorage; + + BtProgressInfoFileHandle _progressInfoFile; + + DiskWriterFactoryHandle _diskWriterFactory; + + DependencyHandle _dependency; + + bool _fileAllocationEnabled; + + bool _preLocalFileCheckEnabled; + + bool _haltRequested; + + PostDownloadHandlers _postDownloadHandlers; + const Option* _option; - const Logger* logger; -#ifdef ENABLE_MESSAGE_DIGEST - ChunkChecksumHandle _chunkChecksum; - ChecksumHandle _checksum; -#endif // ENABLE_MESSAGE_DIGEST - int32_t _numConcurrentCommand; + + const Logger* _logger; void validateFilename(const string& expectedFilename, const string& actualFilename) const; @@ -75,56 +123,20 @@ private: void validateTotalLength(int64_t expectedTotalLength, int64_t actualTotalLength) const; + void initializePostDownloadHandler(); public: + RequestGroup(const Option* option, const Strings& uris); - int32_t numConnection; - - bool isTorrent; - - RequestGroup(const Strings& uris, const Option* option): - _gid(0), - _hintTotalLength(0), - _uris(uris), - _segmentMan(0), - _segmentManFactory(new DefaultSegmentManFactory(option)), - _option(option), - logger(LogFactory::getInstance()), -#ifdef ENABLE_MESSAGE_DIGEST - _chunkChecksum(0), - _checksum(0), -#endif // ENABLE_MESSAGE_DIGEST - _numConcurrentCommand(0), - numConnection(0), - isTorrent(false) {} - - RequestGroup(const string& uri, const Option* option): - _gid(0), - _hintTotalLength(0), - _segmentMan(0), - _segmentManFactory(new DefaultSegmentManFactory(option)), - _option(option), - logger(LogFactory::getInstance()), -#ifdef ENABLE_MESSAGE_DIGEST - _chunkChecksum(0), - _checksum(0), -#endif // ENABLE_MESSAGE_DIGEST - _numConcurrentCommand(0), - numConnection(0), - isTorrent(false) - { - _uris.push_back(uri); - } - + ~RequestGroup(); /** * Reinitializes SegmentMan based on current property values and * returns new one. */ SegmentManHandle initSegmentMan(); - SegmentManHandle getSegmentMan() const - { - return _segmentMan; - } + SegmentManHandle getSegmentMan() const; + + Commands createInitialCommand(DownloadEngine* e); Commands createNextCommandWithAdj(DownloadEngine* e, int32_t numAdj); @@ -135,98 +147,17 @@ public: _uris.push_back(uri); } -#ifdef ENABLE_MESSAGE_DIGEST - void setChunkChecksum(const ChunkChecksumHandle& chunkChecksum) - { - _chunkChecksum = chunkChecksum; - } + bool downloadFinished() const; - ChunkChecksumHandle getChunkChecksum() const - { - return _chunkChecksum; - } - - void setChecksum(const ChecksumHandle& checksum) - { - _checksum = checksum; - } - - ChecksumHandle getChecksum() const - { - return _checksum; - } -#endif // ENABLE_MESSAGE_DIGEST - - void initBitfield(); - - void openExistingFile(); - - void markAllPiecesDone(); - - void markExistingPiecesDone(); - - void markPieceDone(int64_t length); - - void shouldCancelDownloadForSafety(); - - void initAndOpenFile(); - - bool needsFileAllocation() const; - - bool downloadFinished() const - { - if(_segmentMan.isNull()) { - return false; - } else { - return _segmentMan->finished(); - } - } - - void load() - { - _segmentMan->load(); - } - - void save() - { - _segmentMan->save(); - } - - void remove() - { - _segmentMan->remove(); - } - - void closeFile() - { - _segmentMan->diskWriter->closeFile(); - } - - bool fileExists() const; - - bool segmentFileExists() const; + void closeFile(); string getFilePath() const; string getDir() const; - int64_t getExistingFileLength() const; + int64_t getTotalLength() const; - int64_t getTotalLength() const - { - return _segmentMan->totalSize; - } - - int64_t getDownloadLength() const - { - return _segmentMan->getDownloadLength(); - } - - void loadAndOpenFile(); - - void prepareForNextAction(int cuid, const RequestHandle& req, DownloadEngine* e, DownloadCommand* downloadCommand = 0); - - bool downloadFinishedByFileLength(); + int64_t getCompletedLength() const; const string& getHintFilename() const { @@ -258,12 +189,7 @@ public: return _spentUris; } - Strings getUris() const - { - Strings temp(_spentUris.begin(), _spentUris.end()); - temp.insert(temp.end(), _uris.begin(), _uris.end()); - return temp; - } + Strings getUris() const; /** * Compares expected filename with specified actualFilename. @@ -281,42 +207,99 @@ public: void validateTotalLengthByHint(int64_t actualTotalLength) const; - void setSegmentManFactory(const SegmentManFactoryHandle& segmentManFactory) - { - _segmentManFactory = segmentManFactory; - } + void setSegmentManFactory(const SegmentManFactoryHandle& segmentManFactory); void setNumConcurrentCommand(int32_t num) { _numConcurrentCommand = num; } - void setUserDefinedFilename(const string& filename); - - void setGID(int32_t gid) - { - _gid = gid; - } - int32_t getGID() const { return _gid; } - void setTopDir(const string& topDir) + TransferStat calculateStat(); + + DownloadContextHandle getDownloadContext() const; + + void setDownloadContext(const DownloadContextHandle& downloadContext); + + PieceStorageHandle getPieceStorage() const; + + void setPieceStorage(const PieceStorageHandle& pieceStorage); + + BtProgressInfoFileHandle getProgressInfoFile() const; + + void setProgressInfoFile(const BtProgressInfoFileHandle& progressInfoFile); + + void increaseStreamConnection(); + + void decreaseStreamConnection(); + + int32_t getNumConnection() const; + + void increaseNumCommand(); + + void decreaseNumCommand(); + + int32_t getNumCommand() const { - _topDir = topDir; + return _numCommand; } - int32_t calculateDownloadSpeed() const + // TODO is it better to move the following 2 methods to SingleFileDownloadContext? + void setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory); + + DiskWriterFactoryHandle getDiskWriterFactory() const; + + void setFileAllocationEnabled(bool f) { - return _segmentMan->calculateDownloadSpeed(); + _fileAllocationEnabled = f; } - bool tryAutoFileRenaming(); + bool isFileAllocationEnabled() const + { + return _fileAllocationEnabled; + } + + /** + * Setting _preLocalFileCheckEnabled to false, then skip the check to see + * if a file is already exists and control file exists etc. + * Always open file with DiskAdaptor::initAndOpenFile() + */ + void setPreLocalFileCheckEnabled(bool f) + { + _preLocalFileCheckEnabled = f; + } + + bool isPreLocalFileCheckEnabled() const + { + return _preLocalFileCheckEnabled; + } + + void setHaltRequested(bool f); + + bool isHaltRequested() const + { + return _haltRequested; + } + + void dependsOn(const DependencyHandle& dep); + + bool isDependencyResolved(); + + void releaseRuntimeResource(); + + RequestGroups postDownloadProcessing(); + + void addPostDownloadHandler(const PostDownloadHandlerHandle& handler); + + void clearPostDowloadHandler(); }; typedef SharedHandle RequestGroupHandle; +typedef WeakHandle RequestGroupWeakHandle; typedef deque RequestGroups; #endif // _D_REQUEST_GROUP_H_ diff --git a/src/TrackerSegmentManFactory.cc b/src/RequestGroupAware.cc similarity index 84% rename from src/TrackerSegmentManFactory.cc rename to src/RequestGroupAware.cc index e203c2bd..c76f9ba8 100644 --- a/src/TrackerSegmentManFactory.cc +++ b/src/RequestGroupAware.cc @@ -32,13 +32,16 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#include "TrackerSegmentManFactory.h" -#include "ByteArrayDiskWriter.h" +#include "RequestGroupAware.h" +#include "RequestGroup.h" -SegmentManHandle TrackerSegmentManFactory::createNewInstance() +RequestGroupAware::RequestGroupAware(RequestGroup* requestGroup): + _requestGroup(requestGroup) { - SegmentManHandle segmentMan = new SegmentMan(); - segmentMan->diskWriter = new ByteArrayDiskWriter(); - segmentMan->option = _option; - return segmentMan; + _requestGroup->increaseNumCommand(); +} + +RequestGroupAware::~RequestGroupAware() +{ + _requestGroup->decreaseNumCommand(); } diff --git a/src/TorrentConsoleDownloadEngine.h b/src/RequestGroupAware.h similarity index 80% rename from src/TorrentConsoleDownloadEngine.h rename to src/RequestGroupAware.h index dea43c82..1f5e6283 100644 --- a/src/TorrentConsoleDownloadEngine.h +++ b/src/RequestGroupAware.h @@ -32,19 +32,20 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_ -#define _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_ +#ifndef _D_REQUEST_GROUP_AWARE_H_ +#define _D_REQUEST_GROUP_AWARE_H_ -#include "TorrentDownloadEngine.h" +#include "common.h" -class TorrentConsoleDownloadEngine : public TorrentDownloadEngine { +class RequestGroup; + +class RequestGroupAware { protected: - virtual void sendStatistics(); + RequestGroup* _requestGroup; public: - TorrentConsoleDownloadEngine(); - ~TorrentConsoleDownloadEngine(); + RequestGroupAware(RequestGroup* requestGroup); - virtual void afterEachIteration(); + ~RequestGroupAware(); }; -#endif // _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_ +#endif // _D_REQUEST_GROUP_AWARE_H_ diff --git a/src/RequestGroupEntry.cc b/src/RequestGroupEntry.cc index 980d65b0..cd17e043 100644 --- a/src/RequestGroupEntry.cc +++ b/src/RequestGroupEntry.cc @@ -33,12 +33,26 @@ */ /* copyright --> */ #include "RequestGroupEntry.h" -#include "DownloadCommand.h" +#include "RequestGroup.h" +#include "Command.h" + +RequestGroupEntry::RequestGroupEntry(RequestGroup* requestGroup, + Command* nextCommand): + _requestGroup(requestGroup), + _nextCommand(nextCommand) +{ + _requestGroup->increaseNumCommand(); +} RequestGroupEntry::~RequestGroupEntry() { - if(_shouldAddNumConnection) { - --_requestGroup->numConnection; - } - delete _nextDownloadCommand; + _requestGroup->decreaseNumCommand(); + delete _nextCommand; +} + +Command* RequestGroupEntry::popNextCommand() +{ + Command* temp = _nextCommand; + _nextCommand = 0; + return temp; } diff --git a/src/RequestGroupEntry.h b/src/RequestGroupEntry.h index 157f3048..812720f7 100644 --- a/src/RequestGroupEntry.h +++ b/src/RequestGroupEntry.h @@ -36,74 +36,32 @@ #define _D_REQUEST_GROUP_ENTRY_H_ #include "ProgressAwareEntry.h" -#include "Request.h" -#include "RequestGroup.h" +class RequestGroup; +class Command; class DownloadCommand; -class RequestGroupEntry : public ProgressAwareEntry { +class RequestGroupEntry { protected: - int32_t _cuid; - RequestHandle _currentRequest; RequestGroup* _requestGroup; - DownloadCommand* _nextDownloadCommand; - bool _shouldAddNumConnection; + Command* _nextCommand; public: - RequestGroupEntry(int32_t cuid, - const RequestHandle& currentRequest, - RequestGroup* requestGroup, - DownloadCommand* nextDownloadCommand = 0): - _cuid(cuid), - _currentRequest(currentRequest), - _requestGroup(requestGroup), - _nextDownloadCommand(nextDownloadCommand) - { - if(nextDownloadCommand) { - _shouldAddNumConnection = false; - } else { - _shouldAddNumConnection = true; - ++_requestGroup->numConnection; - } - } + RequestGroupEntry(RequestGroup* requestGroup, + Command* nextCommand = 0); virtual ~RequestGroupEntry(); - virtual int64_t getTotalLength() const - { - return _requestGroup->getTotalLength(); - } - - int32_t getCUID() const - { - return _cuid; - } - - RequestHandle getCurrentRequest() const - { - return _currentRequest; - } - RequestGroup* getRequestGroup() const { return _requestGroup; } - /* - void setNextDownloadCommand(DownloadCommand* command) + + Command* getNextCommand() const { - _nextDownloadCommand = command; - } - */ - DownloadCommand* getNextDownloadCommand() const - { - return _nextDownloadCommand; + return _nextCommand; } - DownloadCommand* popNextDownloadCommand() - { - DownloadCommand* temp = _nextDownloadCommand; - _nextDownloadCommand = 0; - return temp; - } + Command* popNextCommand(); bool operator==(const RequestGroupEntry& entry) const { diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index b1b87713..5d13a845 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -33,9 +33,64 @@ */ /* copyright --> */ #include "RequestGroupMan.h" +#include "BtProgressInfoFile.h" +#include "DlAbortEx.h" +#include "RequestGroup.h" +#include "LogFactory.h" #include "DownloadEngine.h" #include "message.h" #include +#include + +RequestGroupMan::RequestGroupMan(const RequestGroups& requestGroups, + int32_t maxSimultaneousDownloads): + _requestGroups(requestGroups), + _logger(LogFactory::getInstance()), + _maxSimultaneousDownloads(maxSimultaneousDownloads), + _gidCounter(0) {} + +bool RequestGroupMan::downloadFinished() +{ + if(!_reservedGroups.empty()) { + return false; + } + for(RequestGroups::iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + if((*itr)->getNumCommand() > 0 || !(*itr)->downloadFinished()) { + return false; + } + } + return true; +} + +void RequestGroupMan::addRequestGroup(const RequestGroupHandle& group) +{ + _requestGroups.push_back(group); +} + +void RequestGroupMan::addReservedGroup(const RequestGroups& groups) +{ + _reservedGroups.insert(_reservedGroups.end(), groups.begin(), groups.end()); +} + +void RequestGroupMan::addReservedGroup(const RequestGroupHandle& group) +{ + _reservedGroups.push_back(group); +} + +int32_t RequestGroupMan::countRequestGroup() const +{ + return _requestGroups.size(); +} + +RequestGroupHandle RequestGroupMan::getRequestGroup(int32_t index) const +{ + if(index < (int32_t)_requestGroups.size()) { + return _requestGroups[index]; + } else { + return 0; + } +} void RequestGroupMan::removeStoppedGroup() { @@ -43,18 +98,27 @@ void RequestGroupMan::removeStoppedGroup() RequestGroups temp; for(RequestGroups::iterator itr = _requestGroups.begin(); itr != _requestGroups.end(); ++itr) { - if((*itr)->numConnection > 0) { + if((*itr)->getNumCommand() > 0) { temp.push_back(*itr); } else { (*itr)->closeFile(); + RequestGroups nextGroups = (*itr)->postDownloadProcessing(); + if((*itr)->downloadFinished()) { _logger->notice(MSG_FILE_DOWNLOAD_COMPLETED, (*itr)->getFilePath().c_str()); - (*itr)->remove(); + (*itr)->getProgressInfoFile()->removeFile(); } else { - (*itr)->save(); + try { + (*itr)->getProgressInfoFile()->save(); + } catch(DlAbortEx* ex) { + _logger->error(EX_EXCEPTION_CAUGHT, ex); + delete ex; + } } + (*itr)->releaseRuntimeResource(); ++count; + _spentGroups.push_back(*itr); } } _requestGroups = temp; @@ -65,22 +129,28 @@ void RequestGroupMan::removeStoppedGroup() void RequestGroupMan::fillRequestGroupFromReserver(DownloadEngine* e) { + RequestGroups temp; removeStoppedGroup(); - int32_t count = 0; for(int32_t num = _maxSimultaneousDownloads-_requestGroups.size(); num > 0 && _reservedGroups.size() > 0; --num) { - RequestGroupHandle groupToAdd = _reservedGroups.front(); _reservedGroups.pop_front(); - - _requestGroups.push_back(groupToAdd); - groupToAdd->initSegmentMan(); - groupToAdd->setGID(++_gidCounter); - Commands commands = groupToAdd->createNextCommand(e, 1); - count += commands.size(); - e->addCommand(commands); + if(!groupToAdd->isDependencyResolved()) { + temp.push_front(groupToAdd); + continue; + } + try { + _requestGroups.push_back(groupToAdd); + Commands commands = groupToAdd->createInitialCommand(e); + ++count; + e->addCommand(commands); + } catch(DlAbortEx* ex) { + _logger->error(EX_EXCEPTION_CAUGHT, ex); + delete ex; + } } + copy(temp.begin(), temp.end(), front_inserter(_reservedGroups)); if(count > 0) { _logger->debug("%d RequestGroup(s) added.", count); } @@ -89,18 +159,48 @@ void RequestGroupMan::fillRequestGroupFromReserver(DownloadEngine* e) Commands RequestGroupMan::getInitialCommands(DownloadEngine* e) { Commands commands; - for(RequestGroups::const_iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - (*itr)->initSegmentMan(); - (*itr)->setGID(++_gidCounter); - Commands nextCommands = (*itr)->createNextCommand(e, 1); - if(!nextCommands.empty()) { - commands.push_back(nextCommands.front()); + for(RequestGroups::iterator itr = _requestGroups.begin(); + itr != _requestGroups.end();) { + if((*itr)->isDependencyResolved()) { + try { + Commands nextCommands = (*itr)->createInitialCommand(e); + copy(nextCommands.begin(), nextCommands.end(), back_inserter(commands)); + ++itr; + } catch(DlAbortEx* e) { + _logger->error(EX_EXCEPTION_CAUGHT, e); + delete e; + } + } else { + _reservedGroups.push_front((*itr)); + itr = _requestGroups.erase(itr); } } return commands; } +void RequestGroupMan::save() +{ + for(RequestGroups::iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + if(!(*itr)->downloadFinished()) { + try { + (*itr)->getProgressInfoFile()->save(); + } catch(DlAbortEx* e) { + _logger->error(EX_EXCEPTION_CAUGHT, e); + delete e; + } + } + } +} + +void RequestGroupMan::closeFile() +{ + for(RequestGroups::iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + (*itr)->closeFile(); + } +} + void RequestGroupMan::showDownloadResults(ostream& o) const { // Download Results: @@ -110,30 +210,48 @@ void RequestGroupMan::showDownloadResults(ostream& o) const <<_("Download Results:") << "\n" << "idx|stat|path/URI" << "\n" << "===+====+======================================================================" << "\n"; + /* + RequestGroups groups(_spentGroups.begin(), _spentGroups.end()); for(RequestGroups::const_iterator itr = _requestGroups.begin(); itr != _requestGroups.end(); ++itr) { - o << setw(3) << (*itr)->getGID() << "|"; if((*itr)->downloadFinished()) { - o << "OK "; - } else { - o << "ERR "; + groups.push_back(*itr); } - o << "|"; - if((*itr)->downloadFinished()) { - o << (*itr)->getFilePath(); - } else { - Strings uris = (*itr)->getUris(); - if(uris.empty()) { + } + */ + for(RequestGroups::const_iterator itr = _spentGroups.begin(); + itr != _spentGroups.end(); ++itr) { + o << formatDownloadResult((*itr)->downloadFinished()?"OK":"ERR", *itr) << "\n"; + } + for(RequestGroups::const_iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + o << formatDownloadResult((*itr)->downloadFinished()?"OK":"INPR", *itr) << "\n"; + } +} + +string RequestGroupMan::formatDownloadResult(const string& status, const RequestGroupHandle& requestGroup) const +{ + stringstream o; + o << setw(3) << requestGroup->getGID() << "|" + << setw(4) << status << "|"; + if(requestGroup->downloadFinished()) { + o << requestGroup->getFilePath(); + } else { + Strings uris = requestGroup->getUris(); + if(uris.empty()) { + if(requestGroup->getFilePath().empty()) { o << "n/a"; } else { - o << uris.front(); - if(uris.size() > 1) { - o << " (" << uris.size()-1 << "more)"; - } + o << requestGroup->getFilePath(); + } + } else { + o << uris.front(); + if(uris.size() > 1) { + o << " (" << uris.size()-1 << "more)"; } } - o << "\n"; } + return o.str(); } bool RequestGroupMan::isSameFileBeingDownloaded(RequestGroup* requestGroup) const @@ -147,3 +265,21 @@ bool RequestGroupMan::isSameFileBeingDownloaded(RequestGroup* requestGroup) cons } return false; } + +void RequestGroupMan::halt() +{ + for(RequestGroups::const_iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + (*itr)->setHaltRequested(true); + } +} + +TransferStat RequestGroupMan::calculateStat() +{ + TransferStat stat; + for(RequestGroups::const_iterator itr = _requestGroups.begin(); + itr != _requestGroups.end(); ++itr) { + stat = stat+(*itr)->calculateStat(); + } + return stat; +} diff --git a/src/RequestGroupMan.h b/src/RequestGroupMan.h index a78de75e..a533b71c 100644 --- a/src/RequestGroupMan.h +++ b/src/RequestGroupMan.h @@ -36,73 +36,37 @@ #define _D_REQUEST_GROUP_MAN_H_ #include "common.h" -#include "RequestGroup.h" -#include "LogFactory.h" +#include "TransferStat.h" class DownloadEngine; +class RequestGroup; +extern typedef SharedHandle RequestGroupHandle; +extern typedef deque RequestGroups; +class Command; +extern typedef deque Commands; +class Logger; class RequestGroupMan { private: RequestGroups _requestGroups; RequestGroups _reservedGroups; + RequestGroups _spentGroups; const Logger* _logger; int32_t _maxSimultaneousDownloads; int32_t _gidCounter; + + string formatDownloadResult(const string& status, const RequestGroupHandle& requestGroup) const; + public: - RequestGroupMan(const RequestGroups& requestGroups = RequestGroups(), int32_t maxSimultaneousDownloads = 1): - _requestGroups(requestGroups), - _logger(LogFactory::getInstance()), - _maxSimultaneousDownloads(maxSimultaneousDownloads), - _gidCounter(0) {} + RequestGroupMan(const RequestGroups& requestGroups, int32_t maxSimultaneousDownloads = 1); - bool downloadFinished() - { - for(RequestGroups::iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - if((*itr)->numConnection > 0 || !(*itr)->getSegmentMan()->finished()) { - return false; - } - } - return true; - } + bool downloadFinished(); - void save() - { - for(RequestGroups::iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - if(!(*itr)->getSegmentMan()->finished()) { - (*itr)->getSegmentMan()->save(); - } - } - } + void save(); - void closeFile() - { - for(RequestGroups::iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - (*itr)->getSegmentMan()->diskWriter->closeFile(); - } - } + void closeFile(); - int64_t getDownloadLength() const - { - int64_t downloadLength = 0; - for(RequestGroups::const_iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - downloadLength += (*itr)->getSegmentMan()->getDownloadLength(); - } - return downloadLength; - } - - int64_t getTotalLength() const - { - int64_t totalLength = 0; - for(RequestGroups::const_iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - totalLength += (*itr)->getSegmentMan()->totalSize; - } - return totalLength; - } + void halt(); Commands getInitialCommands(DownloadEngine* e); @@ -110,48 +74,21 @@ public: void fillRequestGroupFromReserver(DownloadEngine* e); - void addRequestGroup(const RequestGroupHandle& group) - { - _requestGroups.push_back(group); - } + void addRequestGroup(const RequestGroupHandle& group); - void addReservedGroup(const RequestGroups& groups) - { - _reservedGroups.insert(_reservedGroups.end(), groups.begin(), groups.end()); - } + void addReservedGroup(const RequestGroups& groups); - void addReservedGroup(const RequestGroupHandle& group) - { - _reservedGroups.push_back(group); - } + void addReservedGroup(const RequestGroupHandle& group); - int32_t countRequestGroup() const - { - return _requestGroups.size(); - } + int32_t countRequestGroup() const; - RequestGroupHandle getRequestGroup(int32_t index) const - { - if(index < (int32_t)_requestGroups.size()) { - return _requestGroups[index]; - } else { - return 0; - } - } + RequestGroupHandle getRequestGroup(int32_t index) const; void showDownloadResults(ostream& o) const; - int32_t getErrors() const - { - int32_t errors = 0; - for(RequestGroups::const_iterator itr = _requestGroups.begin(); - itr != _requestGroups.end(); ++itr) { - errors += (*itr)->getSegmentMan()->errors; - } - return errors; - } - bool isSameFileBeingDownloaded(RequestGroup* requestGroup) const; + + TransferStat calculateStat(); }; typedef SharedHandle RequestGroupManHandle; diff --git a/src/SeedCheckCommand.cc b/src/SeedCheckCommand.cc index b419738c..07ac79ee 100644 --- a/src/SeedCheckCommand.cc +++ b/src/SeedCheckCommand.cc @@ -36,10 +36,13 @@ #include "message.h" SeedCheckCommand::SeedCheckCommand(int cuid, - TorrentDownloadEngine* e, + RequestGroup* requestGroup, + DownloadEngine* e, const BtContextHandle& btContext, SeedCriteriaHandle seedCriteria) - :BtContextAwareCommand(cuid, btContext), + :Command(cuid), + BtContextAwareCommand(btContext), + RequestGroupAware(requestGroup), e(e), seedCriteria(seedCriteria), checkStarted(false) {} diff --git a/src/SeedCheckCommand.h b/src/SeedCheckCommand.h index 4ade4094..8716dad0 100644 --- a/src/SeedCheckCommand.h +++ b/src/SeedCheckCommand.h @@ -35,20 +35,26 @@ #ifndef _D_SEED_CHECK_COMMAND_H_ #define _D_SEED_CHECK_COMMAND_H_ +#include "Command.h" #include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" +#include "DownloadEngine.h" #include "TimeA2.h" #include "SeedCriteria.h" +#include "RequestGroupAware.h" -class SeedCheckCommand : public BtContextAwareCommand { +class SeedCheckCommand : public Command, + public BtContextAwareCommand, + public RequestGroupAware +{ private: - TorrentDownloadEngine* e; + DownloadEngine* e; Time checkPoint; SeedCriteriaHandle seedCriteria; bool checkStarted; public: SeedCheckCommand(int cuid, - TorrentDownloadEngine* e, + RequestGroup* requestGroup, + DownloadEngine* e, const BtContextHandle& btContext, SeedCriteriaHandle seedCriteria); diff --git a/src/Segment.cc b/src/Segment.cc index b4881c1e..79f8ce20 100644 --- a/src/Segment.cc +++ b/src/Segment.cc @@ -36,9 +36,13 @@ #include "Segment.h" ostream& operator<<(ostream& o, const Segment& segment) { - o << "index = " << segment.index << ", "; - o << "length = " << segment.length << ", "; - o << "segmentLength = " << segment.segmentLength << ", "; - o << "writtenLength = " << segment.writtenLength; + o << "index = " << segment._piece->getIndex() << ", "; + o << "length = " << segment._piece->getLength() << ", "; + o << "segmentLength = " << segment._pieceLength << ", "; + if(segment.complete()) { + o << "writtenLength = " << segment._piece->getLength(); + } else { + o << "writtenLength = " << (segment._piece->getMissingUnusedBlockIndex()-1)*BLOCK_LENGTH; + } return o; } diff --git a/src/Segment.h b/src/Segment.h index d082fbc1..00d05b89 100644 --- a/src/Segment.h +++ b/src/Segment.h @@ -36,56 +36,35 @@ #define _D_SEGMENT_H_ #include "common.h" -#include -using namespace std; +class Piece; +extern typedef SharedHandle PieceHandle; class Segment { public: - int32_t index; - int32_t length; - int32_t segmentLength; - int32_t writtenLength; + virtual ~Segment() {} - Segment(int32_t index, int32_t length, int32_t segmentLength, int32_t writtenLength = 0) - :index(index), length(length), segmentLength(segmentLength), - writtenLength(writtenLength) {} + virtual bool complete() const = 0; - Segment():index(-1), length(0), segmentLength(0), writtenLength(0) {} + virtual int32_t getIndex() const = 0; - bool complete() const { - return length <= writtenLength; - } + virtual int64_t getPosition() const = 0; + + virtual int64_t getPositionToWrite() const = 0; - bool isNull() const { - return index == -1; - } + virtual int32_t getLength() const = 0; - int64_t getPosition() const { - return ((int64_t)index)*segmentLength; - } + virtual int32_t getSegmentLength() const = 0; - int64_t getPositionToWrite() const - { - return getPosition()+writtenLength; - } + virtual int32_t getWrittenLength() const = 0; - bool operator==(const Segment& segment) const { - return index == segment.index && - length == segment.length && - segmentLength == segment.segmentLength && - writtenLength == segment.writtenLength; - } + virtual int32_t getOverflowLength() const = 0; - bool operator!=(const Segment& segment) const { - return !(*this == segment); - } + virtual void updateWrittenLength(int32_t bytes) = 0; - friend ostream& operator<<(ostream& o, const Segment& segment); + virtual PieceHandle getPiece() const = 0; }; -ostream& operator<<(ostream& o, const Segment& segment); - typedef SharedHandle SegmentHandle; #endif // _D_SEGMENT_H_ diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 0240bc2d..9ae96d7a 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -38,244 +38,95 @@ #include "File.h" #include "message.h" #include "prefs.h" +#include "PiecedSegment.h" +#include "GrowSegment.h" +#include "DiskAdaptor.h" #include "LogFactory.h" -#include "BitfieldManFactory.h" +#include "PieceStorage.h" +#include "PeerStat.h" +#include "Option.h" +#include "DownloadContext.h" +#include "Piece.h" #ifdef ENABLE_MESSAGE_DIGEST #include "MessageDigestHelper.h" #endif // ENABLE_MESSAGE_DIGEST #include "a2io.h" #include -SegmentMan::SegmentMan():logger(LogFactory::getInstance()), - bitfield(0), - totalSize(0), - isSplittable(true), - downloadStarted(false), - dir("."), - errors(0), - diskWriter(0) +SegmentEntry::SegmentEntry(int32_t cuid, const SegmentHandle& segment): + cuid(cuid), segment(segment) {} + +SegmentEntry::~SegmentEntry() {} + +SegmentMan::SegmentMan(const Option* option, + const DownloadContextHandle& downloadContext, + const PieceStorageHandle& pieceStorage): + _option(option), + logger(LogFactory::getInstance()), + _downloadContext(downloadContext), + _pieceStorage(pieceStorage) {} -SegmentMan::~SegmentMan() { - delete bitfield; -} +SegmentMan::~SegmentMan() {} -bool SegmentMan::segmentFileExists() const { - if(!isSplittable) { +bool SegmentMan::downloadFinished() const +{ + if(_pieceStorage.isNull()) { return false; - } - string segFilename = getSegmentFilePath(); - File f(segFilename); - if(f.isFile()) { - logger->info(MSG_SEGMENT_FILE_EXISTS, segFilename.c_str()); - return true; } else { - logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, segFilename.c_str()); - return false; + return _pieceStorage->downloadFinished(); } } -void SegmentMan::load() { - if(!isSplittable) { - return; - } - string segFilename = getSegmentFilePath(); - logger->info(MSG_LOADING_SEGMENT_FILE, segFilename.c_str()); - FILE* segFile = openSegFile(segFilename, "r+b"); - try { - read(segFile); - fclose(segFile); - } catch(string ex) { - fclose(segFile); - throw new DlAbortEx(EX_SEGMENT_FILE_READ, - segFilename.c_str(), strerror(errno)); - } - logger->info(MSG_LOADED_SEGMENT_FILE); +void SegmentMan::init() +{ + // TODO Do we have to do something about DownloadContext and PieceStorage here? } -void SegmentMan::save() const { - if(!isSplittable || totalSize == 0 || !bitfield) { - return; - } - string segFilename = getSegmentFilePath(); - logger->info(MSG_SAVING_SEGMENT_FILE, segFilename.c_str()); - - string segFilenameTemp = segFilename+"__temp"; - FILE* segFile = openSegFile(segFilenameTemp, "wb"); - try { - if(fwrite(&totalSize, sizeof(totalSize), 1, segFile) < 1) { - throw string("writeError"); - } - int32_t segmentLength = bitfield->getBlockLength(); - if(fwrite(&segmentLength, sizeof(segmentLength), 1, segFile) < 1) { - throw string("writeError"); - } - if(bitfield) { - int32_t bitfieldLength = bitfield->getBitfieldLength(); - if(fwrite(&bitfieldLength, sizeof(bitfieldLength), 1, segFile) < 1) { - throw string("writeError"); - } - if(fwrite(bitfield->getBitfield(), bitfield->getBitfieldLength(), - 1, segFile) < 1) { - throw string("writeError"); - } - } else { - int32_t i = 0; - if(fwrite(&i, sizeof(i), 1, segFile) < 1) { - throw string("writeError"); - } - } - int32_t usedSegmentCount = usedSegmentEntries.size(); - if(fwrite(&usedSegmentCount, sizeof(usedSegmentCount), 1, segFile) < 1) { - throw string("writeError"); - } - for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); itr++) { - if(fwrite((*itr)->segment.get(), sizeof(Segment), 1, segFile) < 1) { - throw string("writeError"); - } - } - fclose(segFile); - logger->info(MSG_SAVED_SEGMENT_FILE); - } catch(string ex) { - fclose(segFile); - throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, - segFilename.c_str(), strerror(errno)); - } - - if(rename(segFilenameTemp.c_str(), segFilename.c_str()) == -1) { - throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, - segFilename.c_str(), strerror(errno)); - } -} - -FILE* SegmentMan::openSegFile(const string& segFilename, const string& mode) const { - FILE* segFile = fopen(segFilename.c_str(), mode.c_str()); - if(segFile == NULL) { - throw new DlAbortEx(EX_SEGMENT_FILE_OPEN, - segFilename.c_str(), strerror(errno)); - } - return segFile; -} - -void SegmentMan::read(FILE* file) { - assert(file != NULL); - if(fread(&totalSize, sizeof(totalSize), 1, file) < 1) { - throw string("readError"); - } - int32_t segmentSize; - if(fread(&segmentSize, sizeof(segmentSize), 1, file) < 1) { - throw string("readError"); - } - int32_t bitfieldLength; - if(fread(&bitfieldLength, sizeof(bitfieldLength), 1, file) < 1) { - throw string("readError"); - } - if(bitfieldLength > 0) { - initBitfield(segmentSize, totalSize); - unsigned char* savedBitfield = new unsigned char[bitfield->getBitfieldLength()]; - if(fread(savedBitfield, bitfield->getBitfieldLength(), 1, file) < 1) { - delete [] savedBitfield; - throw string("readError"); - } else { - bitfield->setBitfield(savedBitfield, bitfield->getBitfieldLength()); - delete [] savedBitfield; - } - } - int32_t segmentCount; - if(fread(&segmentCount, sizeof(segmentCount), 1, file) < 1) { - throw string("readError"); - } - while(segmentCount--) { - SegmentHandle seg; - if(fread(seg.get(), sizeof(Segment), 1, file) < 1) { - throw string("readError"); - } - usedSegmentEntries.push_back(SegmentEntryHandle(new SegmentEntry(0, seg))); - } -} - -void SegmentMan::remove() const { - if(!isSplittable) { - return; - } - if(segmentFileExists()) { - File f(getSegmentFilePath()); - f.remove(); - } -} - -bool SegmentMan::finished() const { - if(!downloadStarted) { - return false; - } - if(!bitfield) { - return false; - } - assert(bitfield); - return bitfield->isAllBitSet(); -} - -void SegmentMan::removeIfFinished() const { - if(finished()) { - remove(); - } -} - -void SegmentMan::init() { - totalSize = 0; - isSplittable = false; - downloadStarted = false; - errors = 0; - //segments.clear(); - usedSegmentEntries.clear(); - delete bitfield; - bitfield = 0; - peerStats.clear(); - diskWriter->closeFile(); - -} - -void SegmentMan::initBitfield(int32_t segmentLength, int64_t totalLength) { - delete bitfield; - this->bitfield = BitfieldManFactory::getFactoryInstance()->createBitfieldMan(segmentLength, totalLength); -} - -SegmentHandle SegmentMan::checkoutSegment(int32_t cuid, int32_t index) { - logger->debug("Attach segment#%d to CUID#%d.", index, cuid); - bitfield->setUseBit(index); - SegmentEntryHandle segmentEntry = getSegmentEntryByIndex(index); - SegmentHandle segment(0); - if(segmentEntry.isNull()) { - segment = new Segment(index, bitfield->getBlockLength(index), - bitfield->getBlockLength()); - SegmentEntryHandle entry = new SegmentEntry(cuid, segment); - usedSegmentEntries.push_back(entry); +int64_t SegmentMan::getTotalLength() const +{ + if(_pieceStorage.isNull()) { + return 0; } else { - segmentEntry->cuid = cuid; - segment = segmentEntry->segment; + return _pieceStorage->getTotalLength(); } +} + +void SegmentMan::setPieceStorage(const PieceStorageHandle& pieceStorage) +{ + _pieceStorage = pieceStorage; +} + +void SegmentMan::setDownloadContext(const DownloadContextHandle& downloadContext) +{ + _downloadContext = downloadContext; +} + +SegmentHandle SegmentMan::checkoutSegment(int32_t cuid, + const PieceHandle& piece) +{ + if(piece.isNull()) { + return 0; + } + logger->debug("Attach segment#%d to CUID#%d.", piece->getIndex(), cuid); + + SegmentHandle segment = 0; + if(piece->getLength() == 0) { + segment = new GrowSegment(piece); + } else { + segment = new PiecedSegment(_downloadContext->getPieceLength(), piece); + } + SegmentEntryHandle entry = new SegmentEntry(cuid, segment); + usedSegmentEntries.push_back(entry); + logger->debug("index=%d, length=%d, segmentLength=%d, writtenLength=%d", - segment->index, segment->length, segment->segmentLength, - segment->writtenLength); + segment->getIndex(), + segment->getLength(), + segment->getSegmentLength(), + segment->getWrittenLength()); return segment; } -SegmentHandle SegmentMan::onNullBitfield(int32_t cuid) { - if(usedSegmentEntries.size() == 0) { - SegmentHandle segment = new Segment(0, 0, 0); - usedSegmentEntries.push_back(SegmentEntryHandle(new SegmentEntry(cuid, segment))); - return segment; - } else { - SegmentEntryHandle segmentEntry = getSegmentEntryByCuid(cuid); - if(segmentEntry.isNull()) { - return 0; - } else { - return segmentEntry->segment; - } - } -} - SegmentEntryHandle SegmentMan::findSlowerSegmentEntry(const PeerStatHandle& peerStat) const { int32_t speed = (int32_t)(peerStat->getAvgDownloadSpeed()*0.8); SegmentEntryHandle slowSegmentEntry(0); @@ -288,7 +139,7 @@ SegmentEntryHandle SegmentMan::findSlowerSegmentEntry(const PeerStatHandle& peer PeerStatHandle p = getPeerStat(segmentEntry->cuid); if(!p.get() || p->getCuid() == peerStat->getCuid() || p->getStatus() != PeerStat::ACTIVE || - !p->getDownloadStartTime().elapsed(option->getAsInt(PREF_STARTUP_IDLE_TIME))) { + !p->getDownloadStartTime().elapsed(_option->getAsInt(PREF_STARTUP_IDLE_TIME))) { continue; } int32_t pSpeed = p->calculateDownloadSpeed(); @@ -301,91 +152,55 @@ SegmentEntryHandle SegmentMan::findSlowerSegmentEntry(const PeerStatHandle& peer } SegmentHandle SegmentMan::getSegment(int32_t cuid) { - if(!bitfield) { - return onNullBitfield(cuid); - } SegmentEntryHandle segmentEntry = getSegmentEntryByCuid(cuid); if(!segmentEntry.isNull()) { return segmentEntry->segment; } - int32_t index = bitfield->getSparseMissingUnusedIndex(); - if(index == -1) { + PieceHandle piece = _pieceStorage->getMissingPiece(); + if(piece.isNull()) { PeerStatHandle myPeerStat = getPeerStat(cuid); - if(!myPeerStat.get()) { + if(myPeerStat.isNull()) { return 0; } SegmentEntryHandle slowSegmentEntry = findSlowerSegmentEntry(myPeerStat); if(slowSegmentEntry.get()) { logger->info(MSG_SEGMENT_FORWARDING, slowSegmentEntry->cuid, - slowSegmentEntry->segment->index, + slowSegmentEntry->segment->getIndex(), cuid); PeerStatHandle slowPeerStat = getPeerStat(slowSegmentEntry->cuid); slowPeerStat->requestIdle(); cancelSegment(slowSegmentEntry->cuid); - return checkoutSegment(cuid, slowSegmentEntry->segment->index); + return checkoutSegment(cuid, slowSegmentEntry->segment->getPiece()); } else { return 0; } } else { - return checkoutSegment(cuid, index); + return checkoutSegment(cuid, piece); } } SegmentHandle SegmentMan::getSegment(int32_t cuid, int32_t index) { - if(!bitfield) { - return onNullBitfield(cuid); - } - if(index < 0 || (int32_t)bitfield->countBlock() <= index) { + if(index < 0 || _downloadContext->getNumPieces() <= index) { return 0; } - if(bitfield->isBitSet(index) || bitfield->isUseBitSet(index)) { - return 0; - } else { - return checkoutSegment(cuid, index); - } + return checkoutSegment(cuid, _pieceStorage->getMissingPiece(index)); } -/* -bool SegmentMan::updateSegment(int cuid, const Segment& segment) { - if(segment.isNull()) { - return false; - } - SegmentEntryHandle segmentEntry = getSegmentEntryByCuid(cuid); - if(segmentEntry.isNull()) { - return false; - } else { - segmentEntry->segment = segment; - return true; - } -} -*/ void SegmentMan::cancelSegment(int32_t cuid) { - if(bitfield) { - for(SegmentEntries::iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); ++itr) { - if((*itr)->cuid == cuid) { - bitfield->unsetUseBit((*itr)->segment->index); - (*itr)->cuid = 0; - break; - } + for(SegmentEntries::iterator itr = usedSegmentEntries.begin(); + itr != usedSegmentEntries.end(); ++itr) { + if((*itr)->cuid == cuid) { + _pieceStorage->cancelPiece((*itr)->segment->getPiece()); + usedSegmentEntries.erase(itr); + break; } - } else { - usedSegmentEntries.clear(); } } bool SegmentMan::completeSegment(int32_t cuid, const SegmentHandle& segment) { - if(segment->isNull()) { - return false; - } - if(bitfield) { - bitfield->unsetUseBit(segment->index); - bitfield->setBit(segment->index); - } else { - initBitfield(option->getAsInt(PREF_SEGMENT_SIZE), segment->writtenLength); - bitfield->setAllBit(); - } + _pieceStorage->completePiece(segment->getPiece()); + _pieceStorage->advertisePiece(cuid, segment->getPiece()->getIndex()); SegmentEntries::iterator itr = getSegmentEntryIteratorByCuid(cuid); if(itr == usedSegmentEntries.end()) { return false; @@ -396,23 +211,15 @@ bool SegmentMan::completeSegment(int32_t cuid, const SegmentHandle& segment) { } bool SegmentMan::hasSegment(int32_t index) const { - if(bitfield) { - return bitfield->isBitSet(index); - } else { - return false; - } + return _pieceStorage->hasPiece(index); } int64_t SegmentMan::getDownloadLength() const { - int64_t dlLength = 0; - if(bitfield) { - dlLength += bitfield->getCompletedLength(); + if(_pieceStorage.isNull()) { + return 0; + } else { + return _pieceStorage->getCompletedLength(); } - for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); itr++) { - dlLength += (*itr)->segment->writtenLength; - } - return dlLength; } void SegmentMan::registerPeerStat(const PeerStatHandle& peerStat) { @@ -422,6 +229,17 @@ void SegmentMan::registerPeerStat(const PeerStatHandle& peerStat) { } } +PeerStatHandle SegmentMan::getPeerStat(int32_t cuid) const +{ + for(PeerStats::const_iterator itr = peerStats.begin(); itr != peerStats.end(); ++itr) { + const PeerStatHandle& peerStat = *itr; + if(peerStat->getCuid() == cuid) { + return peerStat; + } + } + return 0; +} + int32_t SegmentMan::calculateDownloadSpeed() const { int32_t speed = 0; for(PeerStats::const_iterator itr = peerStats.begin(); @@ -434,19 +252,15 @@ int32_t SegmentMan::calculateDownloadSpeed() const { return speed; } -bool SegmentMan::fileExists() const { - return File(getFilePath()).exists(); -} - void SegmentMan::markAllPiecesDone() { - if(bitfield) { - bitfield->setAllBit(); - } + _pieceStorage->markAllPiecesDone(); } void SegmentMan::markPieceDone(int64_t length) { + // TODO implement this function later + /* if(bitfield) { if(length == bitfield->getTotalLength()) { bitfield->setAllBit(); @@ -465,18 +279,45 @@ void SegmentMan::markPieceDone(int64_t length) } } } + */ } #ifdef ENABLE_MESSAGE_DIGEST +void SegmentMan::validatePieceHash(const SegmentHandle& segment, + const string& expectedPieceHash) +{ + string actualPieceHash = + MessageDigestHelper::digest("sha1", + _pieceStorage->getDiskAdaptor(), + segment->getPosition(), + segment->getLength()); + if(actualPieceHash == expectedPieceHash) { + logger->info(MSG_GOOD_CHUNK_CHECKSUM, actualPieceHash.c_str()); + } else { + _pieceStorage->markPieceMissing(segment->getIndex()); + logger->info(EX_INVALID_CHUNK_CHECKSUM, + segment->getIndex(), + Util::llitos(segment->getPosition(), true).c_str(), + expectedPieceHash.c_str(), + actualPieceHash.c_str()); + } +} + +/* bool SegmentMan::isChunkChecksumValidationReady(const ChunkChecksumHandle& chunkChecksum) const { - return !chunkChecksum.isNull() && bitfield && totalSize > 0 && + return false; + // TODO fix this + return !chunkChecksum.isNull() && !_downloadContext.isNull() && totalSize > 0 && chunkChecksum->getEstimatedDataLength() >= totalSize; } +*/ #endif // ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST + /* void SegmentMan::tryChunkChecksumValidation(const SegmentHandle& segment, const ChunkChecksumHandle& chunkChecksum) { + // TODO implement this function later if(!isChunkChecksumValidationReady(chunkChecksum)) { return; } @@ -528,4 +369,41 @@ void SegmentMan::tryChunkChecksumValidation(const SegmentHandle& segment, const } } } + */ #endif // ENABLE_MESSAGE_DIGEST + +SegmentEntryHandle SegmentMan::getSegmentEntryByIndex(int32_t index) +{ + for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); + itr != usedSegmentEntries.end(); ++itr) { + const SegmentEntryHandle& segmentEntry = *itr; + if(segmentEntry->segment->getIndex() == index) { + return segmentEntry; + } + } + return 0; +} + +SegmentEntryHandle SegmentMan::getSegmentEntryByCuid(int32_t cuid) +{ + for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); + itr != usedSegmentEntries.end(); ++itr) { + const SegmentEntryHandle& segmentEntry = *itr; + if(segmentEntry->cuid == cuid) { + return segmentEntry; + } + } + return 0; +} + +SegmentEntries::iterator SegmentMan::getSegmentEntryIteratorByCuid(int32_t cuid) +{ + for(SegmentEntries::iterator itr = usedSegmentEntries.begin(); + itr != usedSegmentEntries.end(); ++itr) { + const SegmentEntryHandle& segmentEntry = *itr; + if(segmentEntry->cuid == cuid) { + return itr; + } + } + return usedSegmentEntries.end(); +} diff --git a/src/SegmentMan.h b/src/SegmentMan.h index fc67214a..41430c22 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -36,18 +36,20 @@ #define _D_SEGMENT_MAN_H_ #include "common.h" -#include "Logger.h" -#include "Segment.h" -#include "Option.h" -#include "DiskWriter.h" -#include "Request.h" -#include "BitfieldMan.h" -#include "PeerStat.h" -#ifdef ENABLE_MESSAGE_DIGEST -# include "ChunkChecksum.h" -#endif // ENABLE_MESSAGE_DIGEST -using namespace std; +class Segment; +extern typedef SharedHandle SegmentHandle; +class Logger; +class Option; +class PeerStat; +extern typedef SharedHandle PeerStatHandle; +typedef deque PeerStats; +class DownloadContext; +extern typedef SharedHandle DownloadContextHandle; +class PieceStorage; +extern typedef SharedHandle PieceStorageHandle; +class Piece; +extern typedef SharedHandle PieceHandle; #define SEGMENT_FILE_EXTENSION ".aria2" @@ -56,162 +58,67 @@ public: int32_t cuid; SegmentHandle segment; public: - SegmentEntry(int32_t cuid, const SegmentHandle& segment) - :cuid(cuid), segment(segment) {} - ~SegmentEntry() {} + SegmentEntry(int32_t cuid, const SegmentHandle& segment); + + ~SegmentEntry(); }; typedef SharedHandle SegmentEntryHandle; typedef deque SegmentEntries; -typedef deque PeerStats; /** * This class holds the download progress of the one download entry. */ class SegmentMan { private: + const Option* _option; + const Logger* logger; - BitfieldMan* bitfield; + + DownloadContextHandle _downloadContext; + + PieceStorageHandle _pieceStorage; + SegmentEntries usedSegmentEntries; + PeerStats peerStats; - void read(FILE* file); - FILE* openSegFile(const string& segFilename, const string& mode) const; - SegmentHandle onNullBitfield(int32_t cuid); - SegmentHandle checkoutSegment(int32_t cuid, int32_t index); - SegmentEntryHandle findSlowerSegmentEntry(const PeerStatHandle& peerStat) const; - SegmentEntryHandle getSegmentEntryByIndex(int32_t index) { - for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); ++itr) { - const SegmentEntryHandle& segmentEntry = *itr; - if(segmentEntry->segment->index == index) { - return segmentEntry; - } - } - return 0; - } - - SegmentEntryHandle getSegmentEntryByCuid(int32_t cuid) { - for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); ++itr) { - const SegmentEntryHandle& segmentEntry = *itr; - if(segmentEntry->cuid == cuid) { - return segmentEntry; - } - } - return 0; - } + SegmentHandle checkoutSegment(int32_t cuid, const PieceHandle& piece); - SegmentEntries::iterator getSegmentEntryIteratorByCuid(int32_t cuid) { - for(SegmentEntries::iterator itr = usedSegmentEntries.begin(); - itr != usedSegmentEntries.end(); ++itr) { - const SegmentEntryHandle& segmentEntry = *itr; - if(segmentEntry->cuid == cuid) { - return itr; - } - } - return usedSegmentEntries.end(); - } + SegmentEntryHandle findSlowerSegmentEntry(const PeerStatHandle& peerStat) const; + + SegmentEntryHandle getSegmentEntryByIndex(int32_t index); + + SegmentEntryHandle getSegmentEntryByCuid(int32_t cuid); + + SegmentEntries::iterator getSegmentEntryIteratorByCuid(int32_t cuid); public: - /** - * The total number of bytes to download. - * If Transfer-Encoding is Chunked or Content-Length header is not provided, - * then this value is set to be 0. - */ - int64_t totalSize; - /** - * Represents whether this download is splittable. - * In Split download(or segmented download), http client establishes - * more than one connections to the server, and downloads sevral parts of - * a file at the same time. This boosts download speed. - * This value is true by default. If total number of bytes is not known or - * Chunked transfer encoding is used, then this value is set to be 0 by - * DownloadCommand class. - */ - bool isSplittable; - /** - * Represents whether the download is start or not. - * The default value is false. - */ - bool downloadStarted; - /** - * Respresents the file name of the downloaded file. - * If the URL does not contain file name part(http://www.rednoah.com/, for - * example), this value may be 0 length string. - * The default value is 0 length string. - */ - string filename; - /** - * directory to store a file - */ - string dir; - /** - * User defined file name for downloaded content - */ - string ufilename; + SegmentMan(const Option* option, + const DownloadContextHandle& downloadContext = 0, + const PieceStorageHandle& pieceStorage = 0); - /** - * Represents the number of failures(usually, DlAbortEx) in downloads. - */ - int32_t errors; - - const Option* option; - DiskWriterHandle diskWriter; - Requests reserved; - - SegmentMan(); ~SegmentMan(); - + + // Initializes totalSize, isSplittable, downloadStarted, errors. // Clears command queue. Also, closes diskWriter. void init(); /** - * Returns dir+"/"+filename. - * If filename is empty, then returns dir+"/"+"inex.html"; + * The total number of bytes to download. + * If Transfer-Encoding is Chunked or Content-Length header is not provided, + * then this value is set to be 0. */ - string getFilePath() const { - return (dir == "" ? "." : dir)+"/"+ - (ufilename == "" ? - (filename == "" ? "index.html" : filename) : ufilename); - } + int64_t getTotalLength() const; - string getSegmentFilePath() const { - return getFilePath()+SEGMENT_FILE_EXTENSION; - } - - /** - * Returns true only if the segment data file exists. - * The file name of the segment data is filename appended by ".aria2". - * If isSplittable is false, then returns simply false without any operation. - */ - bool segmentFileExists() const; - /** - * Loads the segment data file. - * If isSplittable is false, then returns without any operation. - */ - void load(); - /** - * Saves the segment data file. - * If isSplittable is false, then returns without any operation. - */ - void save() const; - /** - * Removes the segment data file. - * If isSplittable is false, then returns without any operation. - */ - void remove() const; /** * Returs true when the download has finished. * If downloadStarted is false or the number of the segments of this object * holds is 0, then returns false. */ - bool finished() const; - /** - * if finished() is true, then call remove() - */ - void removeIfFinished() const; + bool downloadFinished() const; + /** * Returns a vacant segment. * If there is no vacant segment, then returns a segment instance whose @@ -238,14 +145,17 @@ public: * Tells SegmentMan that the segment has been downloaded successfully. */ bool completeSegment(int32_t cuid, const SegmentHandle& segment); + /** - * Initializes bitfield with the provided length parameters. + * Injects PieceStorage. */ - void initBitfield(int32_t segmentLength, int64_t totalLength); - BitfieldMan* getBitfield() const - { - return bitfield; - } + void setPieceStorage(const PieceStorageHandle& pieceStorage); + + /** + * Injects DownloadContext. + */ + void setDownloadContext(const DownloadContextHandle& downloadContext); + /** * Returns true if the segment whose index is index has been downloaded. */ @@ -265,39 +175,25 @@ public: * Returns peerStat whose cuid is given cuid. If it is not found, returns * 0. */ - PeerStatHandle getPeerStat(int32_t cuid) const { - for(PeerStats::const_iterator itr = peerStats.begin(); itr != peerStats.end(); ++itr) { - const PeerStatHandle& peerStat = *itr; - if(peerStat->getCuid() == cuid) { - return peerStat; - } - } - return 0; - } + PeerStatHandle getPeerStat(int32_t cuid) const; /** * Returns current download speed in bytes per sec. */ int32_t calculateDownloadSpeed() const; - bool fileExists() const; - void markAllPiecesDone(); void markPieceDone(int64_t length); - /** - * This function must be called when none of segment entries is used. - */ - void purgeSegmentEntry() - { - usedSegmentEntries.clear(); - } - #ifdef ENABLE_MESSAGE_DIGEST + + void validatePieceHash(const SegmentHandle& segment, const string& pieceHash); + /* void tryChunkChecksumValidation(const SegmentHandle& segment, const ChunkChecksumHandle& chunkChecksum); bool isChunkChecksumValidationReady(const ChunkChecksumHandle& chunkChecksum) const; + */ #endif // ENABLE_MESSAGE_DIGEST }; diff --git a/src/SegmentManFactory.h b/src/SegmentManFactory.h index 4e601926..75754a86 100644 --- a/src/SegmentManFactory.h +++ b/src/SegmentManFactory.h @@ -42,7 +42,8 @@ class SegmentManFactory { public: virtual ~SegmentManFactory() {} - virtual SegmentManHandle createNewInstance() = 0; + virtual SegmentManHandle createNewInstance(const DownloadContextHandle& dc, + const PieceStorageHandle& ps) = 0; }; typedef SharedHandle SegmentManFactoryHandle; diff --git a/src/SingleFileAllocationIterator.cc b/src/SingleFileAllocationIterator.cc new file mode 100644 index 00000000..1384c163 --- /dev/null +++ b/src/SingleFileAllocationIterator.cc @@ -0,0 +1,67 @@ +/* */ +#include "SingleFileAllocationIterator.h" +#include "AbstractSingleDiskAdaptor.h" + +#define BUFSIZE 16*1024 + +SingleFileAllocationIterator::SingleFileAllocationIterator(AbstractSingleDiskAdaptor* diskAdaptor):_diskAdaptor(diskAdaptor), _offset(diskAdaptor->size()) {} + +SingleFileAllocationIterator::~SingleFileAllocationIterator() {} + +void SingleFileAllocationIterator::allocateChunk() +{ + int32_t bufSize = BUFSIZE; + unsigned char buf[BUFSIZE]; + memset(buf, 0, bufSize); + + _diskAdaptor->writeData(buf, bufSize, _offset); + _offset += bufSize; + + if(_diskAdaptor->getTotalLength() < _offset) { + _diskAdaptor->truncate(getTotalLength()); + _offset = getTotalLength(); + } +} + +bool SingleFileAllocationIterator::finished() +{ + return getCurrentLength() >= getTotalLength(); +} + +int64_t SingleFileAllocationIterator::getTotalLength() +{ + return _diskAdaptor->getTotalLength(); +} diff --git a/src/SingleFileAllocationIterator.h b/src/SingleFileAllocationIterator.h new file mode 100644 index 00000000..4b401f13 --- /dev/null +++ b/src/SingleFileAllocationIterator.h @@ -0,0 +1,66 @@ +/* */ +#ifndef _D_SINGLE_FILE_ALLOCATION_ITERATOR_H_ +#define _D_SINGLE_FILE_ALLOCATION_ITERATOR_H_ + +#include "FileAllocationIterator.h" + +class AbstractSingleDiskAdaptor; + +class SingleFileAllocationIterator:public FileAllocationIterator +{ +private: + AbstractSingleDiskAdaptor* _diskAdaptor; + int64_t _offset; +public: + SingleFileAllocationIterator(AbstractSingleDiskAdaptor* diskAdaptor); + + virtual ~SingleFileAllocationIterator(); + + virtual void allocateChunk(); + + virtual bool finished(); + + virtual int64_t getCurrentLength() + { + return _offset; + } + + virtual int64_t getTotalLength(); +}; + +typedef SharedHandle SingleFileAllocationIteratorHandle; + +#endif // _D_SINGLE_FILE_ALLOCATION_ITERATOR_H_ diff --git a/src/SingleFileDownloadContext.h b/src/SingleFileDownloadContext.h new file mode 100644 index 00000000..f980fb5e --- /dev/null +++ b/src/SingleFileDownloadContext.h @@ -0,0 +1,165 @@ +/* */ +#ifndef _D_SINGLE_FILE_DOWNLOAD_CONTEXT_H_ +#define _D_SINGLE_FILE_DOWNLOAD_CONTEXT_H_ + +#include "DownloadContext.h" + +class SingleFileDownloadContext:public DownloadContext +{ +private: + int32_t _pieceLength; + /** + * Actual file path is _dir + _filename. + * If _ufilename is not zero-length string, then _dir + _ufilename. + */ + FileEntryHandle _fileEntry; + string _filename; + string _ufilename; + + Strings _pieceHashes; + string _pieceHashAlgo; + + void updateFileEntry() + { + if(_ufilename != "") { + _fileEntry->setPath(_ufilename); + } else if(_filename != "") { + _fileEntry->setPath(_filename); + } else { + _fileEntry->setPath("index.html"); + } + } +public: + SingleFileDownloadContext(int32_t pieceLength, + int64_t totalLength, + const string& filename, + const string& ufilename = ""): + _pieceLength(pieceLength), + _fileEntry(new FileEntry(filename, totalLength, 0)), + _filename(filename), + _ufilename(ufilename) + { + updateFileEntry(); + } + + virtual ~SingleFileDownloadContext() {} + + virtual string getPieceHash(int32_t index) const + { + if(index < 0 || _pieceHashes.size() <= (size_t)index) { + return ""; + } + return _pieceHashes[index]; + } + + virtual const Strings& getPieceHashes() const + { + return _pieceHashes; + } + + virtual int64_t getTotalLength() const + { + return _fileEntry->getLength(); + } + + virtual FILE_MODE getFileMode() const + { + return SINGLE; + } + + virtual FileEntries getFileEntries() const + { + FileEntries fs; + fs.push_back(_fileEntry); + return fs; + } + + virtual string getName() const + { + return _filename; + } + + virtual int32_t getPieceLength() const + { + return _pieceLength; + } + + virtual int32_t getNumPieces() const + { + return (_fileEntry->getLength()+_pieceLength-1)/_pieceLength; + } + + virtual string getActualBasePath() const + { + return _dir+"/"+_fileEntry->getPath(); + } + + virtual string getPieceHashAlgo() const + { + return _pieceHashAlgo; + } + + void setPieceHashes(const Strings& pieceHashes) + { + _pieceHashes = pieceHashes; + } + + void setFilename(const string& filename) + { + _filename = filename; + updateFileEntry(); + } + + void setUFilename(const string& ufilename) + { + _ufilename = ufilename; + updateFileEntry(); + } + + void setTotalLength(int64_t totalLength) + { + _fileEntry->setLength(totalLength); + } + + void setPieceHashAlgo(const string& algo) + { + _pieceHashAlgo = algo; + } +}; + +typedef SharedHandle SingleFileDownloadContextHandle; + +#endif // _D_SINGLE_FILE_DOWNLOAD_CONTEXT_H_ diff --git a/src/SocketCore.cc b/src/SocketCore.cc index 66466a9e..45b61667 100644 --- a/src/SocketCore.cc +++ b/src/SocketCore.cc @@ -33,8 +33,6 @@ */ /* copyright --> */ #include "SocketCore.h" -#include "DlRetryEx.h" -#include "DlAbortEx.h" #include "message.h" #include "a2netcompat.h" #include "a2time.h" @@ -56,7 +54,8 @@ SocketCore::SocketCore(int32_t sockfd):sockfd(sockfd) { init(); } -void SocketCore::init() { +void SocketCore::init() +{ use = 1; blocking = true; secure = false; @@ -81,7 +80,9 @@ SocketCore::~SocketCore() { #endif // HAVE_LIBGNUTLS } -void SocketCore::beginListen(int32_t port) { +void SocketCore::beginListen(int32_t port) + throw(DlAbortEx*) +{ closeConnection(); //sockfd = socket(AF_UNSPEC, SOCK_STREAM, PF_UNSPEC); sockfd = socket(AF_INET, SOCK_STREAM, 0); @@ -116,7 +117,9 @@ void SocketCore::beginListen(int32_t port) { setNonBlockingMode(); } -SocketCore* SocketCore::acceptConnection() const { +SocketCore* SocketCore::acceptConnection() const + throw(DlAbortEx*) +{ struct sockaddr_in sockaddr; socklen_t len = sizeof(sockaddr); memset((char*)&sockaddr, 0, sizeof(sockaddr)); @@ -129,7 +132,9 @@ SocketCore* SocketCore::acceptConnection() const { return s; } -void SocketCore::getAddrInfo(pair& addrinfo) const { +void SocketCore::getAddrInfo(pair& addrinfo) const + throw(DlAbortEx*) +{ struct sockaddr_in listenaddr; memset((char*)&listenaddr, 0, sizeof(listenaddr)); socklen_t len = sizeof(listenaddr); @@ -140,7 +145,9 @@ void SocketCore::getAddrInfo(pair& addrinfo) const { addrinfo.second = ntohs(listenaddr.sin_port); } -void SocketCore::getPeerInfo(pair& peerinfo) const { +void SocketCore::getPeerInfo(pair& peerinfo) const + throw(DlAbortEx*) +{ struct sockaddr_in peerin; memset(&peerin, 0, sizeof(peerin)); int32_t len = sizeof(peerin); @@ -151,7 +158,9 @@ void SocketCore::getPeerInfo(pair& peerinfo) const { peerinfo.second = ntohs(peerin.sin_port); } -void SocketCore::establishConnection(const string& host, int32_t port) { +void SocketCore::establishConnection(const string& host, int32_t port) + throw(DlAbortEx*) +{ closeConnection(); sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd == -1) { @@ -199,7 +208,9 @@ WSAEWOULDBLOCK } } -void SocketCore::setNonBlockingMode() { +void SocketCore::setNonBlockingMode() + throw(DlAbortEx*) +{ #ifdef __MINGW32__ static u_long flag = 1; if (::ioctlsocket(sockfd, FIONBIO, &flag) == -1) { @@ -213,7 +224,9 @@ void SocketCore::setNonBlockingMode() { blocking = false; } -void SocketCore::setBlockingMode() { +void SocketCore::setBlockingMode() + throw(DlAbortEx*) +{ #ifdef __MINGW32__ static u_long flag = 0; if (::ioctlsocket(sockfd, FIONBIO, &flag) == -1) { @@ -227,7 +240,8 @@ void SocketCore::setBlockingMode() { blocking = true; } -void SocketCore::closeConnection() { +void SocketCore::closeConnection() +{ #ifdef HAVE_LIBSSL // for SSL if(secure) { @@ -262,7 +276,9 @@ void SocketCore::closeConnection() { #endif // HAVE_LIBGNUTLS } -bool SocketCore::isWritable(int32_t timeout) const { +bool SocketCore::isWritable(int32_t timeout) const + throw(DlRetryEx*) +{ fd_set fds; FD_ZERO(&fds); FD_SET(sockfd, &fds); @@ -286,7 +302,9 @@ bool SocketCore::isWritable(int32_t timeout) const { } } -bool SocketCore::isReadable(int32_t timeout) const { +bool SocketCore::isReadable(int32_t timeout) const + throw(DlRetryEx*) +{ #ifdef HAVE_LIBGNUTLS if(secure && peekBufLength > 0) { return true; @@ -315,7 +333,9 @@ bool SocketCore::isReadable(int32_t timeout) const { } } -void SocketCore::writeData(const char* data, int32_t len) { +void SocketCore::writeData(const char* data, int32_t len) + throw(DlRetryEx*) +{ int32_t ret = 0; if(!secure) { @@ -338,7 +358,9 @@ void SocketCore::writeData(const char* data, int32_t len) { } } -void SocketCore::readData(char* data, int32_t& len) { +void SocketCore::readData(char* data, int32_t& len) + throw(DlRetryEx*) +{ int32_t ret = 0; if(!secure) { @@ -363,7 +385,9 @@ void SocketCore::readData(char* data, int32_t& len) { len = ret; } -void SocketCore::peekData(char* data, int32_t& len) { +void SocketCore::peekData(char* data, int32_t& len) + throw(DlRetryEx*) +{ int32_t ret = 0; if(!secure) { @@ -389,7 +413,8 @@ void SocketCore::peekData(char* data, int32_t& len) { } #ifdef HAVE_LIBGNUTLS -int32_t SocketCore::shiftPeekData(char* data, int32_t len) { +int32_t SocketCore::shiftPeekData(char* data, int32_t len) +{ if(peekBufLength <= len) { memcpy(data, peekBuf, peekBufLength); int32_t ret = peekBufLength; @@ -407,7 +432,8 @@ int32_t SocketCore::shiftPeekData(char* data, int32_t len) { } -void SocketCore::addPeekData(char* data, int32_t len) { +void SocketCore::addPeekData(char* data, int32_t len) +{ if(peekBufLength+len > peekBufMax) { char* temp = new char[peekBufMax+len]; memcpy(temp, peekBuf, peekBufLength); @@ -419,7 +445,9 @@ void SocketCore::addPeekData(char* data, int32_t len) { peekBufLength += len; } -int32_t SocketCore::gnutlsRecv(char* data, int32_t len) { +int32_t SocketCore::gnutlsRecv(char* data, int32_t len) + throw(DlRetryEx*) +{ int32_t plen = shiftPeekData(data, len); if(plen < len) { int32_t ret = gnutls_record_recv(sslSession, data+plen, len-plen); @@ -432,7 +460,9 @@ int32_t SocketCore::gnutlsRecv(char* data, int32_t len) { } } -int32_t SocketCore::gnutlsPeek(char* data, int32_t len) { +int32_t SocketCore::gnutlsPeek(char* data, int32_t len) + throw(DlRetryEx*) +{ if(peekBufLength >= len) { memcpy(data, peekBuf, len); return len; @@ -448,7 +478,9 @@ int32_t SocketCore::gnutlsPeek(char* data, int32_t len) { } #endif // HAVE_LIBGNUTLS -void SocketCore::initiateSecureConnection() { +void SocketCore::initiateSecureConnection() + throw(DlAbortEx*) +{ #ifdef HAVE_LIBSSL // for SSL if(!secure) { @@ -518,15 +550,18 @@ void SocketCore::initiateSecureConnection() { secure = true; } -/* static */ int SocketCore::error() { +/* static */ int SocketCore::error() +{ return SOCKET_ERRNO; } -/* static */ const char *SocketCore::errorMsg() { +/* static */ const char *SocketCore::errorMsg() +{ return errorMsg(SOCKET_ERRNO); } -/* static */ const char *SocketCore::errorMsg(const int err) { +/* static */ const char *SocketCore::errorMsg(const int err) +{ #ifndef __MINGW32__ return strerror(err); #else diff --git a/src/SocketCore.h b/src/SocketCore.h index 6c35b1ef..8a5b44c6 100644 --- a/src/SocketCore.h +++ b/src/SocketCore.h @@ -36,6 +36,8 @@ #define _D_SOCKET_CORE_H_ #include "common.h" +#include "DlRetryEx.h" +#include "DlAbortEx.h" #include #include @@ -75,8 +77,8 @@ private: int32_t shiftPeekData(char* data, int32_t len); void addPeekData(char* data, int32_t len); - int32_t gnutlsRecv(char* data, int32_t len); - int32_t gnutlsPeek(char* data, int32_t len); + int32_t gnutlsRecv(char* data, int32_t len) throw(DlRetryEx*); + int32_t gnutlsPeek(char* data, int32_t len) throw(DlRetryEx*); #endif // HAVE_LIBGNUTLS void init(); @@ -97,26 +99,26 @@ public: * @param port port to listen. If 0 is specified, os automaticaly * choose avaiable port. */ - void beginListen(int32_t port = 0); + void beginListen(int32_t port = 0) throw(DlAbortEx*); /** * Stores host address and port of this socket to addrinfo. * @param addrinfo placeholder to store host address and port. */ - void getAddrInfo(pair& addrinfo) const; + void getAddrInfo(pair& addrinfo) const throw(DlAbortEx*); /** * Stores peer's address and port to peerinfo. * @param peerinfo placeholder to store peer's address and port. */ - void getPeerInfo(pair& peerinfo) const; + void getPeerInfo(pair& peerinfo) const throw(DlAbortEx*); /** * Accepts incoming connection on this socket. * You must call beginListen() before calling this method. * @return accepted socket. The caller must delete it after using it. */ - SocketCore* acceptConnection() const; + SocketCore* acceptConnection() const throw(DlAbortEx*); /** * Connects to the server named host and the destination port is port. @@ -126,14 +128,14 @@ public: * @param host hostname or ip address to connect to * @param port service port number to connect to */ - void establishConnection(const string& host, int32_t port); + void establishConnection(const string& host, int32_t port) throw(DlAbortEx*); - void setNonBlockingMode(); + void setNonBlockingMode() throw(DlAbortEx*); /** * Makes this socket blocking mode. */ - void setBlockingMode(); + void setBlockingMode() throw(DlAbortEx*); /** * Closes the connection of this socket. @@ -147,7 +149,7 @@ public: * @return true if the socket is available for writing, * otherwise returns false. */ - bool isWritable(int32_t timeout) const; + bool isWritable(int32_t timeout) const throw(DlRetryEx*); /** * Checks whether this socket is available for reading. @@ -156,7 +158,7 @@ public: * @return true if the socket is available for reading, * otherwise returns false. */ - bool isReadable(int32_t timeout) const; + bool isReadable(int32_t timeout) const throw(DlRetryEx*); /** * Writes characters into this socket. data is a pointer pointing the first @@ -166,8 +168,11 @@ public: * @param data data to write * @param len length of data */ - void writeData(const char* data, int32_t len); - void writeData(const string& msg) { writeData(msg.c_str(), msg.size()); } + void writeData(const char* data, int32_t len) throw(DlRetryEx*); + void writeData(const string& msg) throw(DlRetryEx*) + { + writeData(msg.c_str(), msg.size()); + } /** * Reads up to len bytes from this socket. @@ -181,7 +186,7 @@ public: * @param len the maximum size data can store. This method assigns * the number of bytes read to len. */ - void readData(char* data, int32_t& len); + void readData(char* data, int32_t& len) throw(DlRetryEx*); /** * Reads up to len bytes from this socket, but bytes are not removed from @@ -192,14 +197,14 @@ public: * @param len the maximum size data can store. This method assigns * the number of bytes read to len. */ - void peekData(char* data, int32_t& len); + void peekData(char* data, int32_t& len) throw(DlRetryEx*); /** * Makes this socket secure. * If the system has not OpenSSL, then this method do nothing. * connection must be established before calling this method. */ - void initiateSecureConnection() ; + void initiateSecureConnection() throw(DlAbortEx*); bool operator==(const SocketCore& s) { return sockfd == s.sockfd; diff --git a/src/FileAllocator.h b/src/StatCalc.h similarity index 71% rename from src/FileAllocator.h rename to src/StatCalc.h index 43e68b84..ba3ce80d 100644 --- a/src/FileAllocator.h +++ b/src/StatCalc.h @@ -32,29 +32,27 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_FILE_ALLOCATOR_H_ -#define _D_FILE_ALLOCATOR_H_ +#ifndef _D_STAT_CALC_H_ +#define _D_STAT_CALC_H_ #include "common.h" -#include "FileAllocationMonitor.h" -#include "NullFileAllocationMonitor.h" -class FileAllocator { -protected: - FileAllocationMonitorHandle fileAllocationMonitor; +class RequestGroupMan; +extern typedef SharedHandle RequestGroupManHandle; +class FileAllocationMan; +extern typedef SharedHandle FileAllocationManHandle; +class CheckIntegrityMan; +extern typedef SharedHandle CheckIntegrityManHandle; + +class StatCalc { public: - FileAllocator():fileAllocationMonitor(new NullFileAllocationMonitor()) {} + virtual ~StatCalc() {} - virtual ~FileAllocator() {} - - virtual void allocate(int fd, int64_t totalLength) = 0; - - void setFileAllocationMonitor(const FileAllocationMonitorHandle& monitor) - { - this->fileAllocationMonitor = monitor; - } + virtual void calculateStat(const RequestGroupManHandle& requestGroupMan, + const FileAllocationManHandle& fileAllocationMan, + const CheckIntegrityManHandle& checkIntegrityMan) = 0; }; -typedef SharedHandle FileAllocatorHandle; +typedef SharedHandle StatCalcHandle; -#endif // _D_FILE_ALLOCATOR_H_ +#endif // _D_STAT_CALC_H_ diff --git a/src/TorrentDownloadEngine.h b/src/StreamCheckIntegrityEntry.cc similarity index 52% rename from src/TorrentDownloadEngine.h rename to src/StreamCheckIntegrityEntry.cc index ba0cfda1..f2e607ce 100644 --- a/src/TorrentDownloadEngine.h +++ b/src/StreamCheckIntegrityEntry.cc @@ -32,60 +32,44 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_TORRENT_DOWNLOAD_ENGINE_H_ -#define _D_TORRENT_DOWNLOAD_ENGINE_H_ - +#include "StreamCheckIntegrityEntry.h" +#include "RequestGroup.h" #include "DownloadEngine.h" -#include "TimeA2.h" -#include "BtContext.h" -#include "BtRuntime.h" +#include "StreamFileAllocationEntry.h" +#include "InitiateConnectionCommandFactory.h" +#include "CUIDCounter.h" #include "PieceStorage.h" -#include "PeerStorage.h" -#include "BtAnnounce.h" -#include "BtProgressInfoFile.h" +#include "FileAllocationMan.h" +#include "DiskAdaptor.h" -class TorrentDownloadEngine : public DownloadEngine { -private: - bool filenameFixed; +StreamCheckIntegrityEntry::StreamCheckIntegrityEntry(const RequestHandle& currentRequest, + RequestGroup* requestGroup, + Command* nextCommand): + CheckIntegrityEntry(requestGroup, nextCommand), + _currentRequest(currentRequest) +{} - void initStatistics(); - void calculateStatistics(); -protected: - Time cp; - Time lastCalcStat; - int32_t downloadSpeed; - int32_t uploadSpeed; - int64_t selectedDownloadLengthDiff; - int64_t selectedTotalLength; - // The time when startup - Time startup; - // The average speed(bytes per second) since startup - int32_t avgSpeed; - // The estimated remaining time to complete the download. - int32_t eta; - int64_t downloadLength; - int64_t uploadLength; - int64_t totalLength; +StreamCheckIntegrityEntry::~StreamCheckIntegrityEntry() {} - BtContextHandle btContext; - BtRuntimeHandle btRuntime; - PieceStorageHandle pieceStorage; - PeerStorageHandle peerStorage; - BtAnnounceHandle btAnnounce; - BtProgressInfoFileHandle btProgressInfoFile; - - int32_t calculateSpeed(int64_t sessionLength, int32_t elapsed); - void calculateStat(); - - virtual void onEndOfRun(); - virtual void sendStatistics() = 0; -public: - TorrentDownloadEngine(); - virtual ~TorrentDownloadEngine(); - - bool isFilenameFixed() const { return filenameFixed; } - - void setBtContext(const BtContextHandle& btContext); -}; - -#endif // _D_TORRENT_DOWNLOAD_ENGINE_H_ +Commands StreamCheckIntegrityEntry::prepareForNextAction(DownloadEngine* e) +{ + Commands commands; + if(_requestGroup->isFileAllocationEnabled() && !_requestGroup->getPieceStorage()->getDiskAdaptor()->fileAllocationIterator()->finished()) { + FileAllocationEntryHandle entry = + new StreamFileAllocationEntry(_currentRequest, _requestGroup, + popNextCommand()); + e->_fileAllocationMan->pushFileAllocationEntry(entry); + } else { + if(_nextCommand) { + commands.push_back(popNextCommand()); + } else { + Commands streamCommands = _requestGroup->createNextCommandWithAdj(e, -1); + Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(), + _currentRequest, _requestGroup, e); + + commands.push_front(command); + copy(streamCommands.begin(), streamCommands.end(), back_inserter(commands)); + } + } + return commands; +} diff --git a/src/StreamCheckIntegrityEntry.h b/src/StreamCheckIntegrityEntry.h new file mode 100644 index 00000000..7b864962 --- /dev/null +++ b/src/StreamCheckIntegrityEntry.h @@ -0,0 +1,65 @@ +/* */ +#ifndef _D_STREAM_CHECK_INTEGRITY_ENTRY_H_ +#define _D_STREAM_CHECK_INTEGRITY_ENTRY_H_ + +#include "CheckIntegrityEntry.h" +#include "TimeA2.h" + +class Request; +typedef SharedHandle RequestHandle; +class Command; +typedef deque Commands; +class RequestGroup; +class DownloadEngine; + +class StreamCheckIntegrityEntry:public CheckIntegrityEntry +{ +private: + RequestHandle _currentRequest; + Time _timer; +public: + StreamCheckIntegrityEntry(const RequestHandle& currentRequest, + RequestGroup* requestGroup, + Command* nextCommand = 0); + + virtual ~StreamCheckIntegrityEntry(); + + virtual Commands prepareForNextAction(DownloadEngine* e); +}; + +typedef SharedHandle StreamCheckIntegrityEntryHandle; + +#endif // _D_STREAM_CHECK_INTEGRITY_ENTRY_H_ diff --git a/src/DefaultFileAllocator.cc b/src/StreamFileAllocationEntry.cc similarity index 57% rename from src/DefaultFileAllocator.cc rename to src/StreamFileAllocationEntry.cc index 5ab85f3d..b229a0a2 100644 --- a/src/DefaultFileAllocator.cc +++ b/src/StreamFileAllocationEntry.cc @@ -32,39 +32,38 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#include "DefaultFileAllocator.h" -#include "DlAbortEx.h" -#include "TimeA2.h" -#include "a2io.h" -#include -#include -#include +#include "StreamFileAllocationEntry.h" +#include "CUIDCounter.h" +#include "Command.h" +#include "DownloadEngine.h" +#include "Option.h" +#include "Request.h" +#include "prefs.h" +#include "RequestGroup.h" +#include "InitiateConnectionCommandFactory.h" -void DefaultFileAllocator::allocate(int fd, int64_t totalLength) +StreamFileAllocationEntry::StreamFileAllocationEntry(const RequestHandle& currentRequest, + RequestGroup* requestGroup, + Command* nextCommand): + FileAllocationEntry(requestGroup, nextCommand), + _currentRequest(currentRequest) +{} + +StreamFileAllocationEntry::~StreamFileAllocationEntry() {} + +Commands StreamFileAllocationEntry::prepareForNextAction(DownloadEngine* e) { - if(0 != lseek(fd, 0, SEEK_SET)) { - throw new DlAbortEx("Seek failed: %s", strerror(errno)); + Commands commands; + if(_timer.difference() <= e->option->getAsInt(PREF_DIRECT_DOWNLOAD_TIMEOUT) && + _nextCommand) { + commands.push_back(popNextCommand()); + } else { + Commands streamCommands = _requestGroup->createNextCommandWithAdj(e, -1); + Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(CUIDCounterSingletonHolder::instance()->newID(), + _currentRequest, _requestGroup, e); + + commands.push_back(command); + copy(streamCommands.begin(), streamCommands.end(), back_inserter(commands)); } - int32_t bufSize = 4096; - char buf[4096]; - memset(buf, 0, bufSize); - int64_t x = (totalLength+bufSize-1)/bufSize; - fileAllocationMonitor->setMinValue(0); - fileAllocationMonitor->setMaxValue(totalLength); - fileAllocationMonitor->setCurrentValue(0); - fileAllocationMonitor->showProgress(); - Time cp; - for(int64_t i = 0; i < x; ++i) { - if(write(fd, buf, bufSize) < 0) { - throw new DlAbortEx("Allocation failed: %s", strerror(errno)); - } - if(cp.elapsedInMillis(500)) { - fileAllocationMonitor->setCurrentValue(i*bufSize); - fileAllocationMonitor->showProgress(); - cp.reset(); - } - } - fileAllocationMonitor->setCurrentValue(totalLength); - fileAllocationMonitor->showProgress(); - ftruncate(fd, totalLength); + return commands; } diff --git a/src/TrackerUpdateCommand.h b/src/StreamFileAllocationEntry.h similarity index 68% rename from src/TrackerUpdateCommand.h rename to src/StreamFileAllocationEntry.h index 3c50fe9d..df272883 100644 --- a/src/TrackerUpdateCommand.h +++ b/src/StreamFileAllocationEntry.h @@ -32,27 +32,30 @@ * files in the program, then also delete it here. */ /* copyright --> */ -#ifndef _D_TRACKER_UPDATE_COMMAND_H_ -#define _D_TRACKER_UPDATE_COMMAND_H_ +#ifndef _D_STREAM_FILE_ALLOCATION_ENTRY_H_ +#define _D_STREAM_FILE_ALLOCATION_ENTRY_H_ -#include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" -#include "Logger.h" +#include "FileAllocationEntry.h" +#include "TimeA2.h" -class TrackerUpdateCommand : public BtContextAwareCommand { +class Request; +extern typedef SharedHandle RequestHandle; + +class StreamFileAllocationEntry : public FileAllocationEntry { private: - TorrentDownloadEngine* e; - const Logger* logger; - bool prepareForRetry(); - string getTrackerResponse(); + RequestHandle _currentRequest; + Time _timer; public: - TrackerUpdateCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext); + StreamFileAllocationEntry(const RequestHandle& currentRequest, + RequestGroup* requestGroup, + Command* nextCommand = 0); - virtual ~TrackerUpdateCommand(); + virtual ~StreamFileAllocationEntry(); - bool execute(); + virtual Commands prepareForNextAction(DownloadEngine* e); }; -#endif // _D_TRACKER_UPDATE_COMMAND_H_ +typedef SharedHandle StreamFileAllocationEntryHandle; +typedef deque StreamFileAllocationEntries; + +#endif // _D_STREAM_FILE_ALLOCATION_ENTRY_H_ diff --git a/src/TimeBasedCommand.cc b/src/TimeBasedCommand.cc index 1803a38e..ac26bb2d 100644 --- a/src/TimeBasedCommand.cc +++ b/src/TimeBasedCommand.cc @@ -33,6 +33,12 @@ */ /* copyright --> */ #include "TimeBasedCommand.h" +#include "DownloadEngine.h" + +TimeBasedCommand::TimeBasedCommand(int32_t cuid, DownloadEngine* e, int32_t interval): + Command(cuid), _e(e),_exit(false), _interval(interval) {} + +TimeBasedCommand::~TimeBasedCommand() {} bool TimeBasedCommand::execute() { diff --git a/src/TimeBasedCommand.h b/src/TimeBasedCommand.h index f23353f6..b4829e5c 100644 --- a/src/TimeBasedCommand.h +++ b/src/TimeBasedCommand.h @@ -37,7 +37,8 @@ #include "Command.h" #include "TimeA2.h" -#include "DownloadEngine.h" + +class DownloadEngine; class TimeBasedCommand : public Command { @@ -73,10 +74,9 @@ public: virtual void postProcess() {}; public: - TimeBasedCommand(int32_t cuid, DownloadEngine* e, int32_t interval): - Command(cuid), _e(e),_exit(false), _interval(interval) {} + TimeBasedCommand(int32_t cuid, DownloadEngine* e, int32_t interval); - virtual ~TimeBasedCommand() {} + virtual ~TimeBasedCommand(); virtual bool execute(); }; diff --git a/src/TorrentDownloadEngine.cc b/src/TorrentDownloadEngine.cc deleted file mode 100644 index 1a5f4017..00000000 --- a/src/TorrentDownloadEngine.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* */ -#include "TorrentDownloadEngine.h" -#include "Util.h" -#include "BtRegistry.h" - -TorrentDownloadEngine::TorrentDownloadEngine(): - filenameFixed(false), - btContext(0), - btRuntime(0), - pieceStorage(0), - peerStorage(0), - btAnnounce(0), - btProgressInfoFile(0) {} - -TorrentDownloadEngine::~TorrentDownloadEngine() { -} - -void TorrentDownloadEngine::setBtContext(const BtContextHandle& btContext) { - this->btContext = btContext; - btRuntime = BT_RUNTIME(btContext); - pieceStorage = PIECE_STORAGE(btContext); - peerStorage = PEER_STORAGE(btContext); - btAnnounce = BT_ANNOUNCE(btContext); - btProgressInfoFile = BT_PROGRESS_INFO_FILE(btContext); -} - -void TorrentDownloadEngine::onEndOfRun() { - pieceStorage->getDiskAdaptor()->closeFile(); - if(pieceStorage->allDownloadFinished()) { - btProgressInfoFile->removeFile(); - } else { - btProgressInfoFile->save(); - } -} - -void TorrentDownloadEngine::initStatistics() { - downloadSpeed = 0; - uploadSpeed = 0; - cp.reset(); - startup.reset(); - eta = 0; - avgSpeed = 0; - downloadLength = 0; - uploadLength = 0; - totalLength = 0; -} - -int32_t TorrentDownloadEngine::calculateSpeed(int64_t length, int32_t elapsed) { - int32_t nowSpeed = length/elapsed; - return nowSpeed; -} - -void TorrentDownloadEngine::calculateStat() { - TransferStat stat = peerStorage->calculateStat(); - - if(pieceStorage->isSelectiveDownloadingMode()) { - downloadLength = pieceStorage->getFilteredCompletedLength(); - totalLength = pieceStorage->getFilteredTotalLength(); - } else { - downloadLength = pieceStorage->getCompletedLength(); - totalLength = pieceStorage->getTotalLength(); - } - uploadLength = stat.getSessionUploadLength()+ - btRuntime->getUploadLengthAtStartup(); - - downloadSpeed = stat.getDownloadSpeed(); - uploadSpeed = stat.getUploadSpeed(); - avgSpeed = calculateSpeed(stat.getSessionDownloadLength(), - startup.difference()); - if(avgSpeed < 0) { - avgSpeed = 0; - } else if(avgSpeed != 0) { - eta = (totalLength-downloadLength)/avgSpeed; - } -} - -void TorrentDownloadEngine::calculateStatistics() { - if(cp.difference() >= 1) { - calculateStat(); - sendStatistics(); - cp.reset(); - } -} diff --git a/src/TorrentRequestInfo.cc b/src/TorrentRequestInfo.cc deleted file mode 100644 index 1eb6391b..00000000 --- a/src/TorrentRequestInfo.cc +++ /dev/null @@ -1,130 +0,0 @@ -/* */ -#include "TorrentRequestInfo.h" -#include "DownloadEngineFactory.h" -#include "prefs.h" -#include "Util.h" -#include "BtRegistry.h" -#include "DefaultBtContext.h" -#include "FatalException.h" -#include "message.h" -#include "RecoverableException.h" -#include "DNSCache.h" -#include - -#ifndef SA_RESETHAND -# define SA_RESETHAND 0x80000000 -#endif // SA_RESETHAND - -extern volatile sig_atomic_t btHaltRequested; - -void torrentHandler(int signal) { - btHaltRequested = 1; -} - -RequestInfos TorrentRequestInfo::execute() { - { - DNSCacheHandle dnsCache = new NullDNSCache(); - DNSCacheSingletonHolder::instance(dnsCache); - } - - DefaultBtContextHandle btContext = new DefaultBtContext(); - btContext->load(torrentFile); - if(op->defined(PREF_PEER_ID_PREFIX)) { - btContext->setPeerIdPrefix(op->get(PREF_PEER_ID_PREFIX)); - } - - if(op->get(PREF_SHOW_FILES) == V_TRUE) { - Util::toStream(cout, btContext->getFileEntries()); - return RequestInfos(); - } - // set max_tries to 1. AnnounceList handles retries. - op->put(PREF_MAX_TRIES, "1"); - SharedHandle - e(DownloadEngineFactory::newTorrentConsoleEngine(btContext, - op, - targetFiles)); - - if(BT_PROGRESS_INFO_FILE(btContext)->exists()) { - // load .aria2 file if it exists. - BT_PROGRESS_INFO_FILE(btContext)->load(); - PIECE_STORAGE(btContext)->getDiskAdaptor()->openFile(); -#ifdef ENABLE_MESSAGE_DIGEST - if(op->get(PREF_CHECK_INTEGRITY) == V_TRUE) { - PIECE_STORAGE(btContext)->checkIntegrity(); - } -#endif // ENABLE_MESSAGE_DIGEST - } else { - if(PIECE_STORAGE(btContext)->getDiskAdaptor()->fileExists()) { - if(op->get(PREF_ALLOW_OVERWRITE) != V_TRUE) { - logger->notice(MSG_FILE_ALREADY_EXISTS, - PIECE_STORAGE(btContext)->getDiskAdaptor()->getFilePath().c_str(), - BT_PROGRESS_INFO_FILE(btContext)->getFilename().c_str()); - throw new FatalException(EX_DOWNLOAD_ABORTED); - } else { - PIECE_STORAGE(btContext)->getDiskAdaptor()->openFile(); -#ifdef ENABLE_MESSAGE_DIGEST - if(op->get(PREF_CHECK_INTEGRITY) == V_TRUE) { - PIECE_STORAGE(btContext)->markAllPiecesDone(); - PIECE_STORAGE(btContext)->checkIntegrity(); - } -#endif // ENABLE_MESSAGE_DIGEST - } - } else { - PIECE_STORAGE(btContext)->getDiskAdaptor()->openFile(); - } - } - - Util::setGlobalSignalHandler(SIGINT, torrentHandler, SA_RESETHAND); - Util::setGlobalSignalHandler(SIGTERM, torrentHandler, SA_RESETHAND); - - try { - e->run(); - if(PIECE_STORAGE(btContext)->downloadFinished()) { - printDownloadCompeleteMessage(); - } - } catch(RecoverableException* ex) { - logger->error(EX_EXCEPTION_CAUGHT, ex); - fail = true; - delete ex; - } - // TODO we want just 1 torrent download to clear - BtRegistry::clear(); - - Util::setGlobalSignalHandler(SIGINT, SIG_DFL, 0); - Util::setGlobalSignalHandler(SIGTERM, SIG_DFL, 0); - - return RequestInfos(); -} diff --git a/src/TrackerUpdateCommand.cc b/src/TrackerUpdateCommand.cc deleted file mode 100644 index b66cda17..00000000 --- a/src/TrackerUpdateCommand.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* */ -#include "TrackerUpdateCommand.h" -#include "LogFactory.h" -#include "DlAbortEx.h" -#include "message.h" -#include "PeerInitiateConnectionCommand.h" -#include "SleepCommand.h" -#include "Util.h" -#include "CUIDCounter.h" -#include - -TrackerUpdateCommand::TrackerUpdateCommand(int32_t cuid, - TorrentDownloadEngine* e, - const BtContextHandle& btContext): - BtContextAwareCommand(cuid, btContext), e(e) -{ - logger = LogFactory::getInstance(); -} - -TrackerUpdateCommand::~TrackerUpdateCommand() {} - -bool TrackerUpdateCommand::prepareForRetry() { - e->commands.push_back(this); - return false; -} - -string TrackerUpdateCommand::getTrackerResponse() { - stringstream strm; - char data[2048]; - try { - while(1) { - int32_t dataLength = e->_requestGroupMan->getRequestGroup(0)->getSegmentMan()->diskWriter->readData(data, sizeof(data), strm.tellp()); - strm.write(data, dataLength); - if(dataLength != sizeof(data)) { - break; - } - } - return strm.str(); - } catch(RecoverableException* e) { - throw; - } -} - -bool TrackerUpdateCommand::execute() { - if(btAnnounce->noMoreAnnounce()) { - return true; - } - if(e->_requestGroupMan->countRequestGroup() == 0 || - !e->_requestGroupMan->downloadFinished()) { - return prepareForRetry(); - } - - try { - string trackerResponse = getTrackerResponse(); - - btAnnounce->processAnnounceResponse(trackerResponse.c_str(), - trackerResponse.size()); - while(!btRuntime->isHalt() && btRuntime->lessThanMinPeer()) { - PeerHandle peer = peerStorage->getUnusedPeer(); - if(peer.isNull()) { - break; - } - peer->cuid = CUIDCounterSingletonHolder::instance()->newID(); - PeerInitiateConnectionCommand* command = - new PeerInitiateConnectionCommand(peer->cuid, - peer, - e, - btContext); - e->commands.push_back(command); - logger->debug("CUID#%d - Adding new command CUID#%d", cuid, peer->cuid); - } - btAnnounce->announceSuccess(); - btAnnounce->resetAnnounce(); - e->_requestGroupMan->removeStoppedGroup(); - } catch(RecoverableException* err) { - logger->error(MSG_TRACKER_RESPONSE_PROCESSING_FAILED, err, cuid); - e->_requestGroupMan->getRequestGroup(0)->getSegmentMan()->errors++; - delete err; - } - return prepareForRetry(); -} - diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index 49ebc899..600c727b 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -33,18 +33,28 @@ */ /* copyright --> */ #include "TrackerWatcherCommand.h" -#include "InitiateConnectionCommandFactory.h" +#include "DownloadEngine.h" #include "Util.h" -#include "SleepCommand.h" #include "prefs.h" -#include "RequestFactory.h" -#include "TrackerSegmentManFactory.h" #include "message.h" +#include "SingleFileDownloadContext.h" +#include "ByteArrayDiskWriterFactory.h" +#include "RecoverableException.h" +#include "CUIDCounter.h" +#include "PeerInitiateConnectionCommand.h" +#include "DiskAdaptor.h" +#include "RequestGroup.h" +#include "Option.h" -TrackerWatcherCommand::TrackerWatcherCommand(int cuid, - TorrentDownloadEngine* e, +TrackerWatcherCommand::TrackerWatcherCommand(int32_t cuid, + RequestGroup* requestGroup, + DownloadEngine* e, const BtContextHandle& btContext): - BtContextAwareCommand(cuid, btContext), e(e) + Command(cuid), + BtContextAwareCommand(btContext), + RequestGroupAware(requestGroup), + e(e), + _trackerRequestGroup(0) { } @@ -53,53 +63,107 @@ TrackerWatcherCommand::~TrackerWatcherCommand() {} bool TrackerWatcherCommand::execute() { if(btAnnounce->noMoreAnnounce()) { + logger->debug("no more announce"); return true; } - Command* command = createCommand(); - if(command) { - e->commands.push_back(command); + if(_trackerRequestGroup.isNull()) { + _trackerRequestGroup = createAnnounce(); + if(!_trackerRequestGroup.isNull()) { + //e->_requestGroupMan->addReservedGroup(_trackerRequestGroup); + //e->_requestGroupMan->fillRequestGroupFromReserver(e); + e->addCommand(_trackerRequestGroup->createInitialCommand(e)); + logger->debug("added tracker request command"); + } + } else if(_trackerRequestGroup->downloadFinished()){ + try { + string trackerResponse = getTrackerResponse(_trackerRequestGroup); + + processTrackerResponse(trackerResponse); + btAnnounce->announceSuccess(); + btAnnounce->resetAnnounce(); + } catch(DlAbortEx* ex) { + btAnnounce->announceFailure(); + if(btAnnounce->isAllAnnounceFailed()) { + btAnnounce->resetAnnounce(); + } + delete ex; + } + _trackerRequestGroup = 0; + } else if(_trackerRequestGroup->getNumCommand() == 0){ + // handle errors here + btAnnounce->announceFailure(); // inside it, trackers = 0. + _trackerRequestGroup = 0; + if(btAnnounce->isAllAnnounceFailed()) { + btAnnounce->resetAnnounce(); + } } e->commands.push_back(this); return false; } -Command* TrackerWatcherCommand::createCommand() { - Command* command = 0; - - if(btAnnounce->isAnnounceReady()) { - command = createRequestCommand(btAnnounce->getAnnounceUrl()); - btAnnounce->announceStart(); // inside it, trackers++. - } else if(e->_requestGroupMan->getErrors() > 0) { - btAnnounce->announceFailure(); // inside it, trackers = 0. - e->_requestGroupMan->removeStoppedGroup(); - if(btAnnounce->isAllAnnounceFailed()) { - btAnnounce->resetAnnounce(); - return 0; - } else if(btAnnounce->isAnnounceReady()) { - command = - new SleepCommand(cuid, e, - createRequestCommand(btAnnounce->getAnnounceUrl()), - e->option->getAsInt(PREF_RETRY_WAIT)); - btAnnounce->announceStart(); // inside it, tracker++. +string TrackerWatcherCommand::getTrackerResponse(const RequestGroupHandle& requestGroup) +{ + stringstream strm; + char data[2048]; + requestGroup->getPieceStorage()->getDiskAdaptor()->openFile(); + while(1) { + int32_t dataLength = requestGroup->getPieceStorage()->getDiskAdaptor()->readData((unsigned char*)data, sizeof(data), strm.tellp()); + strm.write(data, dataLength); + if(dataLength == 0) { + break; } } - return command; + return strm.str(); } -Command* TrackerWatcherCommand::createRequestCommand(const string& url) +// TODO we have to deal with the exception thrown By BtAnnounce +void TrackerWatcherCommand::processTrackerResponse(const string& trackerResponse) { - RequestGroupHandle rg = new RequestGroup(url, e->option); - rg->setUserDefinedFilename("[tracker.announce]"); - rg->isTorrent = true; - rg->setSegmentManFactory(new TrackerSegmentManFactory(e->option)); - e->_requestGroupMan->addRequestGroup(rg); - Commands commands = e->_requestGroupMan->getInitialCommands(e); - - if(commands.empty()) { - logger->error(MSG_TRACKER_REQUEST_CREATION_FAILED, cuid); - return 0; + btAnnounce->processAnnounceResponse(trackerResponse.c_str(), + trackerResponse.size()); + while(!btRuntime->isHalt() && btRuntime->lessThanMinPeer()) { + PeerHandle peer = peerStorage->getUnusedPeer(); + if(peer.isNull()) { + break; + } + peer->cuid = CUIDCounterSingletonHolder::instance()->newID(); + PeerInitiateConnectionCommand* command = + new PeerInitiateConnectionCommand(peer->cuid, + _requestGroup, + peer, + e, + btContext); + e->commands.push_back(command); + logger->debug("CUID#%d - Adding new command CUID#%d", cuid, peer->cuid); } - logger->info(MSG_CREATING_TRACKER_REQUEST, cuid, - commands.front()->getCuid()); - return commands.front(); +} + +RequestGroupHandle TrackerWatcherCommand::createAnnounce() { + RequestGroupHandle rg = 0; + if(btAnnounce->isAnnounceReady()) { + rg = createRequestGroup(btAnnounce->getAnnounceUrl()); + btAnnounce->announceStart(); // inside it, trackers++. + } + return rg; +} + +RequestGroupHandle +TrackerWatcherCommand::createRequestGroup(const string& uri) +{ + Strings uris; + uris.push_back(uri); + RequestGroupHandle rg = new RequestGroup(e->option, uris); + + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(e->option->getAsInt(PREF_SEGMENT_SIZE), + 0, + "", + "[tracker.announce]"); + dctx->setDir(""); + rg->setDownloadContext(dctx); + rg->setDiskWriterFactory(new ByteArrayDiskWriterFactory()); + rg->setFileAllocationEnabled(false); + rg->setPreLocalFileCheckEnabled(false); + logger->info("Creating tracker request group GID#%d", rg->getGID()); + return rg; } diff --git a/src/TrackerWatcherCommand.h b/src/TrackerWatcherCommand.h index 785fa7c3..4cc02f93 100644 --- a/src/TrackerWatcherCommand.h +++ b/src/TrackerWatcherCommand.h @@ -35,28 +35,43 @@ #ifndef _D_TRACKER_WATCHER_COMMAND_H_ #define _D_TRACKER_WATCHER_COMMAND_H_ +#include "Command.h" #include "BtContextAwareCommand.h" -#include "TorrentDownloadEngine.h" +#include "RequestGroupAware.h" -class TrackerWatcherCommand : public BtContextAwareCommand { +class DownloadEngine; +class RequestGroup; +extern typedef SharedHandle RequestGroupHandle; + +class TrackerWatcherCommand : public Command, + public BtContextAwareCommand, + public RequestGroupAware +{ private: - TorrentDownloadEngine* e; + DownloadEngine* e; + RequestGroupHandle _trackerRequestGroup; /** * Returns a command for announce request. Returns 0 if no announce request * is needed. */ - Command* createRequestCommand(const string& url); + RequestGroupHandle createRequestGroup(const string& url); + + string getTrackerResponse(const RequestGroupHandle& requestGroup); + + void processTrackerResponse(const string& response); + public: - TrackerWatcherCommand(int cuid, - TorrentDownloadEngine* e, + TrackerWatcherCommand(int32_t cuid, + RequestGroup* requestGroup, + DownloadEngine* e, const BtContextHandle& btContext); - ~TrackerWatcherCommand(); + virtual ~TrackerWatcherCommand(); - Command* createCommand(); + RequestGroupHandle createAnnounce(); - bool execute(); + virtual bool execute(); }; #endif // _D_TRACKER_WATCHER_COMMAND_H_ diff --git a/src/TransferStat.cc b/src/TransferStat.cc new file mode 100644 index 00000000..95cef7b9 --- /dev/null +++ b/src/TransferStat.cc @@ -0,0 +1,45 @@ +/* */ +#include "TransferStat.h" + +TransferStat operator+(const TransferStat& a, const TransferStat& b) +{ + TransferStat c; + c.downloadSpeed = a.downloadSpeed+b.downloadSpeed; + c.uploadSpeed = a.uploadSpeed+b.uploadSpeed; + c.sessionUploadLength = a.sessionUploadLength+b.sessionUploadLength; + c.sessionDownloadLength = a.sessionDownloadLength+b.sessionDownloadLength; + return c; +} diff --git a/src/TransferStat.h b/src/TransferStat.h new file mode 100644 index 00000000..ac782d74 --- /dev/null +++ b/src/TransferStat.h @@ -0,0 +1,121 @@ +/* */ +#ifndef _D_TRANSFER_STAT_H_ +#define _D_TRANSFER_STAT_H_ + +#include "common.h" + +class TransferStat { +public: + int32_t downloadSpeed; + int32_t uploadSpeed; + int64_t sessionDownloadLength; + int64_t sessionUploadLength; + int64_t allTimeUploadLength; + + void copy(const TransferStat& stat) + { + downloadSpeed = stat.downloadSpeed; + uploadSpeed = stat.uploadSpeed; + sessionDownloadLength = stat.sessionDownloadLength; + sessionUploadLength = stat.sessionUploadLength; + allTimeUploadLength = stat.allTimeUploadLength; + } +public: + TransferStat():downloadSpeed(0), uploadSpeed(0), + sessionDownloadLength(0), sessionUploadLength(0), + allTimeUploadLength(0) {} + + TransferStat(const TransferStat& stat) + { + copy(stat); + } + + TransferStat& operator=(const TransferStat& stat) + { + if(this != &stat) { + copy(stat); + } + return *this; + } + + friend TransferStat operator+(const TransferStat& a, const TransferStat& b); + + int32_t getDownloadSpeed() const { + return downloadSpeed; + } + + void setDownloadSpeed(int32_t s) { downloadSpeed = s; } + + int32_t getUploadSpeed() const { + return uploadSpeed; + } + + void setUploadSpeed(int32_t s) { uploadSpeed = s; } + + /** + * Returns the number of bytes downloaded since the program started. + * This is not the total number of bytes downloaded. + */ + int64_t getSessionDownloadLength() const { + return sessionDownloadLength; + } + + void setSessionDownloadLength(int64_t s) { sessionDownloadLength = s; } + + /** + * Returns the number of bytes uploaded since the program started. + * This is not the total number of bytes uploaded. + */ + int64_t getSessionUploadLength() const { + return sessionUploadLength; + } + + void setSessionUploadLength(int64_t s) { sessionUploadLength = s; } + + void setAllTimeUploadLength(int64_t s) + { + allTimeUploadLength = s; + } + + int64_t getAllTimeUploadLength() const + { + return allTimeUploadLength; + } +}; + +TransferStat operator+(const TransferStat& a, const TransferStat& b); + +#endif // _D_TRANSFER_STAT_H_ diff --git a/src/UnknownLengthPieceStorage.cc b/src/UnknownLengthPieceStorage.cc new file mode 100644 index 00000000..3955c889 --- /dev/null +++ b/src/UnknownLengthPieceStorage.cc @@ -0,0 +1,171 @@ +/* */ +#include "UnknownLengthPieceStorage.h" +#include "DefaultDiskWriter.h" +#include "DirectDiskAdaptor.h" +#include "prefs.h" +#include "DefaultDiskWriterFactory.h" +#include "DownloadContext.h" +#include "PieceStorage.h" +#include "Piece.h" + +UnknownLengthPieceStorage::UnknownLengthPieceStorage(const DownloadContextHandle& downloadContext, + const Option* option): + _downloadContext(downloadContext), + _option(option), + _diskAdaptor(0), + _diskWriterFactory(new DefaultDiskWriterFactory()), + _totalLength(0), + _downloadFinished(false), + _piece(0) {} + +UnknownLengthPieceStorage::~UnknownLengthPieceStorage() {} + +void UnknownLengthPieceStorage::initStorage() +{ + DiskWriterHandle writer = _diskWriterFactory->newDiskWriter(); + DirectDiskAdaptorHandle directDiskAdaptor = new DirectDiskAdaptor(); + directDiskAdaptor->setDiskWriter(writer); + directDiskAdaptor->setTotalLength(_downloadContext->getTotalLength()); + _diskAdaptor = directDiskAdaptor; + string storeDir = _downloadContext->getDir(); +// if(storeDir == "") { +// storeDir = "."; +// } + _diskAdaptor->setStoreDir(storeDir); + _diskAdaptor->setFileEntries(_downloadContext->getFileEntries()); +} + +PieceHandle UnknownLengthPieceStorage::getMissingPiece() +{ + if(_downloadFinished) { + return 0; + } + if(_piece.isNull()) { + _piece = new Piece(); + return _piece; + } else { + return 0; + } +} + +PieceHandle UnknownLengthPieceStorage::getMissingPiece(int32_t index) +{ + if(index == 0) { + return getMissingPiece(); + } else { + return 0; + } +} + +PieceHandle UnknownLengthPieceStorage::getPiece(int32_t index) +{ + if(index == 0) { + if(_piece.isNull()) { + return new Piece(); + } else { + return _piece; + } + } else { + return 0; + } +} + +void UnknownLengthPieceStorage::completePiece(const PieceHandle& piece) +{ + if(_piece == piece) { + _downloadFinished = true; + _totalLength = _piece->getLength(); + _piece = 0; + } +} + +void UnknownLengthPieceStorage::cancelPiece(const PieceHandle& piece) +{ + if(_piece == piece) { + _piece = 0; + } +} + +bool UnknownLengthPieceStorage::hasPiece(int32_t index) +{ + if(index == 0 && _downloadFinished) { + return true; + } else { + return false; + } +} + +bool UnknownLengthPieceStorage::isPieceUsed(int32_t index) +{ + if(index == 0 && !_piece.isNull()) { + return true; + } else { + return false; + } +} + +DiskAdaptorHandle UnknownLengthPieceStorage::getDiskAdaptor() +{ + return _diskAdaptor; +} + +int32_t UnknownLengthPieceStorage::getPieceLength(int32_t index) +{ + if(index == 0) { + return _totalLength; + } else { + return 0; + } +} + +void UnknownLengthPieceStorage::markAllPiecesDone() +{ + if(!_piece.isNull()) { + _totalLength = _piece->getLength(); + _piece = 0; + } + _downloadFinished = true; +} + +Pieces UnknownLengthPieceStorage::getInFlightPieces() +{ + return Pieces(); +} + +void UnknownLengthPieceStorage::setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory) +{ + _diskWriterFactory = diskWriterFactory; +} diff --git a/src/UnknownLengthPieceStorage.h b/src/UnknownLengthPieceStorage.h new file mode 100644 index 00000000..8b4ee353 --- /dev/null +++ b/src/UnknownLengthPieceStorage.h @@ -0,0 +1,272 @@ +/* */ +#ifndef _D_UNKNOWN_LENGTH_PIECE_STORAGE_H_ +#define _D_UNKNOWN_LENGTH_PIECE_STORAGE_H_ + +#include "PieceStorage.h" + +class Option; +class DownloadContext; +extern typedef SharedHandle DownloadContextHandle; +class DiskWriterFactory; +extern typedef SharedHandle DiskWriterFactoryHandle; + +class UnknownLengthPieceStorage:public PieceStorage { +private: + DownloadContextHandle _downloadContext; + + const Option* _option; + + DiskAdaptorHandle _diskAdaptor; + + DiskWriterFactoryHandle _diskWriterFactory; + + int64_t _totalLength; + + bool _downloadFinished; + + PieceHandle _piece; +public: + UnknownLengthPieceStorage(const DownloadContextHandle& downloadContext, + const Option* option); + + virtual ~UnknownLengthPieceStorage(); + + /** + * Returns true if the peer has a piece that localhost doesn't have. + * Otherwise returns false. + */ + virtual bool hasMissingPiece(const PeerHandle& peer) + { + abort(); + } + + /** + * Returns a piece that the peer has but localhost doesn't. + * The piece will be marked "used" status in order to prevent other command + * from get the same piece. But in end game mode, same piece may be returned + * to several commands. + */ + virtual PieceHandle getMissingPiece(const PeerHandle& peer) + { + abort(); + } + /** + * Returns a piece that the peer has but localhost doesn't. + * Only pieces that declared as "fast" are returned. + * The piece will be marked "used" status in order to prevent other command + * from get the same piece. But in end game mode, same piece may be returned + * to several commands. + */ + virtual PieceHandle getMissingFastPiece(const PeerHandle& peer) + { + abort(); + } + /** + * Returns a missing piece if available. Otherwise returns 0; + */ + virtual PieceHandle getMissingPiece(); + + /** + * Returns a missing piece whose index is index. + * If a piece whose index is index is already acquired or currently used, + * then returns 0. + * Also returns 0 if any of missing piece is not available. + */ + virtual PieceHandle getMissingPiece(int32_t index); + + /** + * Returns the piece denoted by index. + * No status of the piece is changed in this method. + */ + virtual PieceHandle getPiece(int32_t index); + + /** + * Tells that the download of the specfied piece completes. + */ + virtual void completePiece(const PieceHandle& piece); + + /** + * Tells that the download of the specified piece is canceled. + */ + virtual void cancelPiece(const PieceHandle& piece); + + /** + * Returns true if the specified piece is already downloaded. + * Otherwise returns false. + */ + virtual bool hasPiece(int32_t index); + + virtual bool isPieceUsed(int32_t index); + + virtual int64_t getTotalLength() + { + return _totalLength; + } + + virtual int64_t getFilteredTotalLength() + { + return _totalLength; + } + + virtual int64_t getCompletedLength() + { + // TODO we have to return actual completed length here? + return _totalLength; + } + + virtual int64_t getFilteredCompletedLength() + { + return getCompletedLength(); + } + + virtual void setFileFilter(const Strings& filePaths) {} + + virtual void setFileFilter(const Integers& fileIndexes) {} + + virtual void clearFileFilter() {} + + /** + * Returns true if download has completed. + * If file filter is enabled, then returns true if those files have + * downloaded. + */ + virtual bool downloadFinished() + { + return _downloadFinished; + } + + /** + * Returns true if all files have downloaded. + * The file filter is ignored. + */ + virtual bool allDownloadFinished() + { + return downloadFinished(); + } + + /** + * Initializes DiskAdaptor. + * TODO add better documentation here. + */ + virtual void initStorage(); + + virtual const unsigned char* getBitfield() + { + return 0; + } + + virtual void setBitfield(const unsigned char* bitfield, + int32_t bitfieldLength) {} + + virtual int32_t getBitfieldLength() + { + return 0; + } + + virtual bool isSelectiveDownloadingMode() + { + return false; + } + + virtual void finishSelectiveDownloadingMode() {} + + virtual bool isEndGame() + { + return false; + } + + virtual DiskAdaptorHandle getDiskAdaptor(); + + virtual int32_t getPieceLength(int32_t index); + + /** + * Adds piece index to advertise to other commands. They send have message + * based on this information. + */ + virtual void advertisePiece(int32_t cuid, int32_t index) {} + + /** + * Returns piece index which is not advertised by the caller command and + * newer than lastCheckTime. + */ + virtual Integers getAdvertisedPieceIndexes(int32_t myCuid, + const Time& lastCheckTime) + { + return Integers(); + } + + /** + * Removes have entry if specified seconds have elapsed since its + * registration. + */ + virtual void removeAdvertisedPiece(int32_t elapsed) {} + + /** + * Sets all bits in bitfield to 1. + */ + virtual void markAllPiecesDone(); + + virtual void markPiecesDone(int64_t length) + { + // TODO not implemented yet + abort(); + } + + virtual void markPieceMissing(int32_t index) + { + // TODO not implemented yet + abort(); + } + + /** + * Do nothing because loading in-flight piece is not supported for this + * class. + */ + virtual void addInFlightPiece(const Pieces& pieces) {} + + virtual int32_t countInFlightPiece() + { + return 0; + } + + virtual Pieces getInFlightPieces(); + + void setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory); +}; + +typedef SharedHandle UnknownLengthPieceStorageHandle; + +#endif // _D_UNKNOWN_LENGTH_PIECE_STORAGE_H_ diff --git a/src/Util.cc b/src/Util.cc index bbd31465..3afe870e 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -33,7 +33,6 @@ */ /* copyright --> */ #include "Util.h" -#include "DlAbortEx.h" #include "File.h" #include "message.h" #include "SimpleRandomizer.h" @@ -54,7 +53,8 @@ #endif // HAVE_SLEEP template -string uint2str(T value, bool comma) { +string uint2str(T value, bool comma) +{ string str; if(value == 0) { str = "0"; @@ -74,7 +74,8 @@ string uint2str(T value, bool comma) { } template -string int2str(T value, bool comma) { +string int2str(T value, bool comma) +{ bool flag = false; if(value < 0) { flag = true; @@ -89,23 +90,28 @@ string int2str(T value, bool comma) { -string Util::uitos(uint16_t value, bool comma) { +string Util::uitos(uint16_t value, bool comma) +{ return uint2str(value, comma); } -string Util::itos(int16_t value, bool comma) { +string Util::itos(int16_t value, bool comma) +{ return int2str(value, comma); } -string Util::uitos(uint32_t value, bool comma) { +string Util::uitos(uint32_t value, bool comma) +{ return uint2str(value, comma); } -string Util::itos(int32_t value, bool comma) { +string Util::itos(int32_t value, bool comma) +{ return int2str(value, comma); } -string Util::ullitos(uint64_t value, bool comma) { +string Util::ullitos(uint64_t value, bool comma) +{ return uint2str(value, comma); } @@ -114,7 +120,8 @@ string Util::llitos(int64_t value, bool comma) return int2str(value, comma); } -string Util::trim(const string& src, const string& trimCharset) { +string Util::trim(const string& src, const string& trimCharset) +{ string::size_type sp = src.find_first_not_of(trimCharset); string::size_type ep = src.find_last_not_of(trimCharset); if(sp == string::npos || ep == string::npos) { @@ -124,7 +131,8 @@ string Util::trim(const string& src, const string& trimCharset) { } } -void Util::split(pair& hp, const string& src, char delim) { +void Util::split(pair& hp, const string& src, char delim) +{ hp.first = ""; hp.second = ""; string::size_type p = src.find(delim); @@ -322,7 +330,9 @@ void Util::fileCopy(const string& dest, const string& src) { rangedFileCopy(dest, src, 0, file.size()); } -void Util::rangedFileCopy(const string& dest, const string& src, int64_t srcOffset, int64_t length) { +void Util::rangedFileCopy(const string& dest, const string& src, int64_t srcOffset, int64_t length) + throw(DlAbortEx*) +{ int32_t bufSize = 4096; char buf[bufSize]; int32_t destFd = -1; diff --git a/src/Util.h b/src/Util.h index 66163f2d..7f85d699 100644 --- a/src/Util.h +++ b/src/Util.h @@ -36,6 +36,7 @@ #define _D_UTIL_H_ #include "common.h" +#include "DlAbortEx.h" #include "a2time.h" #include "FileEntry.h" #include @@ -93,7 +94,7 @@ public: static void fileCopy(const string& destFile, const string& src); - static void rangedFileCopy(const string& destFile, const string& src, int64_t srcOffset, int64_t length); + static void rangedFileCopy(const string& destFile, const string& src, int64_t srcOffset, int64_t length) throw(DlAbortEx*); static bool isPowerOf(int32_t num, int32_t base); diff --git a/src/main.cc b/src/main.cc index 837360e1..b7e171b4 100644 --- a/src/main.cc +++ b/src/main.cc @@ -37,14 +37,10 @@ #include "Util.h" #include "FeatureConfig.h" #include "MultiUrlRequestInfo.h" -#include "TorrentRequestInfo.h" #include "BitfieldManFactory.h" #include "SimpleRandomizer.h" -#include "ConsoleFileAllocationMonitor.h" #include "Netrc.h" #include "RequestFactory.h" -#include "OptionParser.h" -#include "OptionHandlerFactory.h" #include "FatalException.h" #include "File.h" #include "CUIDCounter.h" @@ -59,6 +55,9 @@ #include "prefs.h" #include "ParameterizedStringParser.h" #include "PStringBuildVisitor.h" +#include "SingleFileDownloadContext.h" +#include "DefaultBtContext.h" +#include "RequestGroup.h" #include #include #include @@ -66,14 +65,13 @@ #include #include #include -#include extern char* optarg; extern int optind, opterr, optopt; #include #ifdef ENABLE_METALINK -#include "MetalinkRequestInfo.h" #include "Xml2MetalinkProcessor.h" +#include "Metalink2RequestGroup.h" #endif #ifdef HAVE_LIBSSL @@ -85,282 +83,6 @@ extern int optind, opterr, optopt; # include #endif // HAVE_LIBGNUTLS -using namespace std; - -void showVersion() { - cout << PACKAGE << _(" version ") << PACKAGE_VERSION << endl; - cout << "**Configuration**" << endl; - cout << FeatureConfig::getInstance()->getConfigurationSummary(); -#ifdef ENABLE_MESSAGE_DIGEST - cout << "message digest algorithms: " << MessageDigestContext::getSupportedAlgoString() << endl; -#endif // ENABLE_MESSAGE_DIGEST - cout << endl; - cout << "Copyright (C) 2006, 2007 Tatsuhiro Tsujikawa" << endl; - cout << endl; - cout << - _("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with this program; if not, write to the Free Software\n" - "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"); - cout << endl; - cout << _("Contact Info:") << endl; - cout << "Tatsuhiro Tsujikawa " << endl; - cout << endl; - -} - -void showUsage() { - printf(_("Usage: %s [options] URL ...\n"), PACKAGE_NAME); -#ifdef ENABLE_BITTORRENT - printf(_(" %s [options] -T TORRENT_FILE FILE ...\n"), PACKAGE_NAME); -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - printf(_(" %s [options] -M METALINK_FILE\n"), PACKAGE_NAME); -#endif // ENABLE_METALINK - cout << endl; - cout << _("Options:") << endl; - cout << _(" -d, --dir=DIR The directory to store the downloaded file.") << endl; - cout << _(" -o, --out=FILE The file name of the downloaded file.") << endl; - cout << _(" -l, --log=LOG The file name of the log file. If '-' is\n" - " specified, log is written to stdout.") << endl; -#ifdef HAVE_DAEMON - cout << _(" -D, --daemon Run as daemon.") << endl; -#endif // HAVE_DAEMON - cout << _(" -s, --split=N Download a file using N connections. N must be\n" - " between 1 and 5. This option affects all URLs.\n" - " Thus, aria2 connects to each URL with\n" - " N connections.\n" - " Default: 1") << endl; - cout << _(" --retry-wait=SEC Set the seconds to wait to retry after an error\n" - " has occured. Specify a value between 0 and 60.\n" - " Default: 5") << endl; - cout << _(" -t, --timeout=SEC Set timeout in seconds. Default: 60") << endl; - cout << _(" -m, --max-tries=N Set number of tries. 0 means unlimited.\n" - " Default: 5") << endl; - /* - cout << _(" --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n" - " K or M(1K = 1024, 1M = 1024K). This\n" - " value must be greater than or equal to\n" - " 1024. Default: 1M") << endl; - */ - cout << _(" --http-proxy=HOST:PORT Use HTTP proxy server. This affects all URLs.") << endl; - cout << _(" --http-user=USER Set HTTP user. This affects all URLs.") << endl; - cout << _(" --http-passwd=PASSWD Set HTTP password. This affects all URLs.") << endl; - cout << _(" --http-proxy-user=USER Set HTTP proxy user. This affects all URLs.") << endl; - cout << _(" --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects all URLs.") << endl; - cout << _(" --http-proxy-method=METHOD Set the method to use in proxy request.\n" - " METHOD is either 'get' or 'tunnel'.\n" - " Default: tunnel") << endl; - cout << _(" --http-auth-scheme=SCHEME Set HTTP authentication scheme. Currently, basic\n" - " is the only supported scheme.\n" - " Default: basic") << endl; - cout << _(" --referer=REFERER Set Referer. This affects all URLs.") << endl; - cout << _(" --ftp-user=USER Set FTP user. This affects all URLs.\n" - " Default: anonymous") << endl; - cout << _(" --ftp-passwd=PASSWD Set FTP password. This affects all URLs.\n" - " Default: ARIA2USER@") << endl; - cout << _(" --ftp-type=TYPE Set FTP transfer type. TYPE is either 'binary'\n" - " or 'ascii'.\n" - " Default: binary") << endl; - cout << _(" -p, --ftp-pasv Use passive mode in FTP.") << endl; - cout << _(" --ftp-via-http-proxy=METHOD Use HTTP proxy in FTP. METHOD is either 'get' or\n" - " 'tunnel'.\n" - " Default: tunnel") << endl; - cout << _(" --lowest-speed-limit=SPEED Close connection if download speed is lower than\n" - " or equal to this value(bytes per sec).\n" - " 0 means aria2 does not have a lowest speed limit.\n" - " You can append K or M(1K = 1024, 1M = 1024K).\n" - - " This option does not affect BitTorrent downloads.\n" - " Default: 0") << endl; - cout << _(" --max-download-limit=SPEED Set max download speed in bytes per sec.\n" - " 0 means unrestricted.\n" - " You can append K or M(1K = 1024, 1M = 1024K).\n" - " Default: 0") << endl; - cout << _(" --file-allocation=METHOD Specify file allocation method. METHOD is either\n" - " 'none' or 'prealloc'. 'none' doesn't pre-allocate\n" - " file space. 'prealloc' pre-allocates file space\n" - " before download begins. This may take some time\n" - " depending on the size of the file.\n" - " Default: none") << endl; - cout << _(" --allow-overwrite=true|false If false, aria2 doesn't download a file which\n" - " already exists but the corresponding .aria2 file\n" - " doesn't exist.\n" - " Default: false") << endl; - cout << _(" -Z, --force-sequential[=true|false] Fetch URIs in the command-line sequentially\n" - " and download each URI in a separate session, like\n" - " the usual command-line download utilities.\n" - " Default: false") << endl; - cout << _(" --auto-file-renaming[=true|false] Rename file name if the same file already\n" - " exists. This option works only in http(s)/ftp\n" - " download.\n" - " The new file name has a dot and a number(1..9999)\n" - " appended.\n" - " Default: true") << endl; - cout << _(" -P, --parameterized-uri[=true|false] Enable parameterized URI support.\n" - " You can specify set of parts:\n" - " http://{sv1,sv2,sv3}/foo.iso\n" - " Also you can specify numeric sequences with step\n" - " counter:\n" - " http://host/image[000-100:2].img\n" - " A step counter can be omitted.\n" - " If all URIs do not point to the same file, such\n" - " as the second example above, -Z option is\n" - " required.\n" - " Default: false") << endl; -#ifdef ENABLE_MESSAGE_DIGEST - cout << _(" --check-integrity=true|false Check file integrity by validating piece hash.\n" - " This option only affects in BitTorrent downloads\n" - " and Metalink downloads with chunk checksums.\n" - " Use this option to re-download a damaged portion\n" - " of a file.\n" - " You may need to specify --allow-overwrite=true\n" - " if the .aria2 file doesn't exist.\n" - " Default: false") << endl; - cout << _(" --realtime-chunk-checksum=true|false Validate chunk checksum while\n" - " downloading a file in Metalink mode. This option\n" - " on affects Metalink mode with chunk checksums.\n" - " Default: true") << endl; -#endif // ENABLE_MESSAGE_DIGEST - cout << _(" -c, --continue Continue downloading a partially downloaded\n" - " file. Use this option to resume a download\n" - " started by a web browser or another program\n" - " which downloads files sequentially from the\n" - " beginning. Currently this option is only\n" - " applicable to http(s)/ftp downloads.") << endl; - cout << _(" -U, --user-agent=USER_AGENT Set user agent for http(s) downloads.") << endl; - cout << _(" -n, --no-netrc Disables netrc support.") << endl; - cout << _(" -i, --input-file=FILE Downloads URIs found in FILE. You can specify\n" - " multiple URIs for a single entity: separate\n" - " URIs on a single line using the TAB character.\n" - " Reads input from stdin when '-' is specified.") << endl; - cout << _(" -j, --max-concurrent-downloads=N Set maximum number of concurrent downloads.\n" - " It should be used with the -i option.\n" - " Default: 5") << endl; - cout << _(" --load-cookies=FILE Load cookies from FILE. The format of FILE is\n" - " the same used by Netscape and Mozilla.") << endl; -#if defined ENABLE_BITTORRENT || ENABLE_METALINK - cout << _(" -S, --show-files Print file listing of .torrent or .metalink file\n" - " and exit.") << endl; - cout << _(" --select-file=INDEX... Set file to download by specifing its index.\n" - " You can find the file index using the\n" - " --show-files option. Multiple indexes can be\n" - " specified by using ',', for example: \"3,6\".\n" - " You can also use '-' to specify a range: \"1-5\".\n" - " ',' and '-' can be used together.\n" - " When used with the -M option, index may vary\n" - " depending on the query(see --metalink-* options).") << endl; -#endif // ENABLE_BITTORRENT || ENABLE_METALINK -#ifdef ENABLE_BITTORRENT - cout << _(" -T, --torrent-file=TORRENT_FILE The path to the .torrent file.") << endl; - cout << _(" --follow-torrent=true|false Set to false to prevent aria2 from\n" - " entering BitTorrent mode even if the filename of\n" - " the downloaded file ends with .torrent.\n" - " Default: true") << endl; - cout << _(" --direct-file-mapping=true|false Directly read from and write to each file\n" - " mentioned in .torrent file.\n" - " Default: true") << endl; - cout << _(" --listen-port=PORT Set TCP port number for BitTorrent downloads.\n" - " Default: 6881-6999") << endl; - cout << _(" --max-upload-limit=SPEED Set max upload speed in bytes per sec.\n" - " 0 means unrestricted.\n" - " You can append K or M(1K = 1024, 1M = 1024K).\n" - " Default: 0") << endl; - cout << _(" --seed-time=MINUTES Specify seeding time in minutes. Also see the\n" - " --seed-ratio option.") << endl; - cout << _(" --seed-ratio=RATIO Specify share ratio. Seed completed torrents\n" - " until share ratio reaches RATIO. 1.0 is\n" - " encouraged. If --seed-time option is specified\n" - " along with this option, seeding ends when at\n" - " least one of the conditions is satisfied.") << endl; - cout << _(" --peer-id-prefix=PEERI_ID_PREFIX Specify the prefix of peer ID. The peer ID in\n" - " in BitTorrent is 20 byte length. If more than 20\n" - " bytes are specified, only first 20\n" - " bytes are used. If less than 20 bytes are\n" - " specified, the random alphabet characters are\n" - " added to make it's length 20 bytes.\n" - " Default: -aria2-") << endl; -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - cout << _(" -M, --metalink-file=METALINK_FILE The file path to the .metalink file.") << endl; - cout << _(" -C, --metalink-servers=NUM_SERVERS The number of servers to connect to\n" - " simultaneously.\n" - " Default: 5") << endl; - cout << _(" --metalink-version=VERSION The version of the file to download.") << endl; - cout << _(" --metalink-language=LANGUAGE The language of the file to download.") << endl; - cout << _(" --metalink-os=OS The operating system of the file to download.") << endl; - cout << _(" --metalink-location=LOCATION The location of the prefered server.") << endl; - cout << _(" --follow-metalink=true|false Set to false to prevent aria2 from\n" - " entering Metalink mode even if the filename of\n" - " the downloaded file ends with .metalink.\n" - " Default: true") << endl; -#endif // ENABLE_METALINK - cout << _(" -v, --version Print the version number and exit.") << endl; - cout << _(" -h, --help Print this message and exit.") << endl; - cout << endl; - cout << "URL:" << endl; - cout << _(" You can specify multiple URLs. All URLs must point to the same file\n" - " or downloading will fail.") << endl; - cout << endl; -#ifdef ENABLE_BITTORRENT - cout << "FILE:" << endl; - cout << _(" Specify files in multi-file torrent to download. Use in conjunction with the\n" - " -T option. This argument is ignored if you specify the --select-file option.") << endl; - cout << endl; -#endif // ENABLE_BITTORRENT - cout << _("Examples:") << endl; - cout << _(" Download a file using 1 connection:") << endl; - cout << " aria2c http://AAA.BBB.CCC/file.zip" << endl; - cout << _(" Download a file using 2 connections:") << endl; - cout << " aria2c -s 2 http://AAA.BBB.CCC/file.zip" << endl; - cout << _(" Download a file using 2 connections, each connects to a different server:") << endl; - cout << " aria2c http://AAA.BBB.CCC/file.zip http://DDD.EEE.FFF/GGG/file.zip" << endl; - cout << _(" You can mix up different protocols:") << endl; - cout << " aria2c http://AAA.BBB.CCC/file.zip ftp://DDD.EEE.FFF/GGG/file.zip" << endl; - cout << _(" Parameterized URI:") << endl; - cout << " aria2c -P http://{server1,server2,server3}/file.iso" << endl; - cout << _(" Parameterized URI. -Z option is required in this case:") << endl; - cout << " aria2c -P -Z http://host/file[001-100:2].img" << endl; -#ifdef ENABLE_BITTORRENT - cout << endl; - cout << _(" Download a torrent:") << endl; - cout << " aria2c -o test.torrent http://AAA.BBB.CCC/file.torrent" << endl; - cout << _(" Download a torrent using a local .torrent file:") << endl; - cout << " aria2c -T test.torrent" << endl; - cout << _(" Download only selected files:") << endl; - cout << " aria2c -T test.torrent dir/file1.zip dir/file2.zip" << endl; - cout << _(" Print file listing of .torrent file:") << endl; - cout << " aria2c -T test.torrent -S" << endl; -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - cout << endl; - cout << _(" Metalink downloading:") << endl; - cout << " aria2c http://AAA.BBB.CCC/file.metalink" << endl; - cout << _(" Download a file using local .metalink file:") << endl; - cout << " aria2c -M test.metalink" << endl; - cout << _(" Metalink downloading with preferences:") << endl; - cout << " aria2c -M test.metalink --metalink-version=1.1.1 --metalink-language=en-US" << endl; - cout << _(" Download only selected files:") << endl; - cout << " aria2c -M test.metalink --metalink-language=en-US dir/file1.zip dir/file2.zip" << endl; - cout << _(" Download only selected files using index:") << endl; - cout << " aria2c -M test.metalink --metalink-language=en-US --select-file 1,3-5" << endl; - cout << _(" Print file listing of .metalink file:") << endl; - cout << " aria2c -M test.metalink -S --metalink-language=en-US" << endl; -#endif // ENABLE_METALINK - cout << endl; - printf(_("Report bugs to %s"), ""); - cout << endl; -} - Strings unfoldURI(const Strings& args) { Strings nargs; @@ -375,17 +97,22 @@ Strings unfoldURI(const Strings& args) return nargs; } -string toBoolArg(const char* optarg) +RequestGroupHandle createRequestGroup(const Option* op, const Strings& uris, + const string& ufilename = "") { - string arg; - if(!optarg || string(optarg) == "") { - arg = V_TRUE; - } else { - arg = optarg; - } - return arg; + RequestGroupHandle rg = new RequestGroup(op, uris); + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(op->getAsInt(PREF_SEGMENT_SIZE), + 0, + "", + ufilename); + dctx->setDir(op->get(PREF_DIR)); + rg->setDownloadContext(dctx); + return rg; } +extern Option* option_processing(int argc, char* const argv[]); + int main(int argc, char* argv[]) { #ifdef HAVE_WINSOCK2_H Platform platform; @@ -397,374 +124,7 @@ int main(int argc, char* argv[]) { bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); #endif // ENABLE_NLS - stringstream cmdstream; - int32_t c; - Option* op = new Option(); - op->put(PREF_STDOUT_LOG, V_FALSE); - op->put(PREF_DIR, "."); - op->put(PREF_SPLIT, "1"); - op->put(PREF_DAEMON, V_FALSE); - op->put(PREF_SEGMENT_SIZE, Util::itos((int32_t)(1024*1024))); - op->put(PREF_HTTP_KEEP_ALIVE, V_FALSE); - op->put(PREF_LISTEN_PORT, "-1"); - op->put(PREF_METALINK_SERVERS, "5"); - op->put(PREF_FOLLOW_TORRENT, -#ifdef ENABLE_BITTORRENT - V_TRUE -#else - V_FALSE -#endif // ENABLE_BITTORRENT - ); - op->put(PREF_FOLLOW_METALINK, -#ifdef ENABLE_METALINK - V_TRUE -#else - V_FALSE -#endif // ENABLE_METALINK - ); - op->put(PREF_RETRY_WAIT, "5"); - op->put(PREF_TIMEOUT, "60"); - op->put(PREF_DNS_TIMEOUT, "10"); - op->put(PREF_PEER_CONNECTION_TIMEOUT, "60"); - op->put(PREF_BT_TIMEOUT, "180"); - op->put(PREF_BT_REQUEST_TIMEOUT, "60"); - op->put(PREF_BT_KEEP_ALIVE_INTERVAL, "120"); - op->put(PREF_MIN_SEGMENT_SIZE, "1048576");// 1M - op->put(PREF_MAX_TRIES, "5"); - op->put(PREF_HTTP_AUTH_SCHEME, V_BASIC); - op->put(PREF_HTTP_PROXY_METHOD, V_TUNNEL); - op->put(PREF_FTP_TYPE, V_BINARY); - op->put(PREF_FTP_VIA_HTTP_PROXY, V_TUNNEL); - op->put(PREF_AUTO_SAVE_INTERVAL, "60"); - op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE); - op->put(PREF_LOWEST_SPEED_LIMIT, "0"); - op->put(PREF_MAX_DOWNLOAD_LIMIT, "0"); - op->put(PREF_MAX_UPLOAD_LIMIT, "0"); - op->put(PREF_STARTUP_IDLE_TIME, "10"); - op->put(PREF_TRACKER_MAX_TRIES, "10"); - op->put(PREF_FILE_ALLOCATION, V_NONE); - op->put(PREF_ALLOW_OVERWRITE, V_FALSE); - op->put(PREF_REALTIME_CHUNK_CHECKSUM, V_TRUE); - op->put(PREF_CHECK_INTEGRITY, V_FALSE); - op->put(PREF_NETRC_PATH, Util::getHomeDir()+"/.netrc"); - op->put(PREF_CONTINUE, V_FALSE); - op->put(PREF_USER_AGENT, "aria2"); - op->put(PREF_NO_NETRC, V_FALSE); - op->put(PREF_MAX_CONCURRENT_DOWNLOADS, "5"); - op->put(PREF_DIRECT_DOWNLOAD_TIMEOUT, "15"); - op->put(PREF_FORCE_SEQUENTIAL, V_FALSE); - op->put(PREF_AUTO_FILE_RENAMING, V_TRUE); - op->put(PREF_PARAMETERIZED_URI, V_FALSE); - while(1) { - int optIndex = 0; - int lopt; - static struct option longOpts[] = { -#ifdef HAVE_DAEMON - { "daemon", no_argument, NULL, 'D' }, -#endif // HAVE_DAEMON - { "dir", required_argument, NULL, 'd' }, - { "out", required_argument, NULL, 'o' }, - { "log", required_argument, NULL, 'l' }, - { "split", required_argument, NULL, 's' }, - { "timeout", required_argument, NULL, 't' }, - { "max-tries", required_argument, NULL, 'm' }, - { "http-proxy", required_argument, &lopt, 1 }, - { "http-user", required_argument, &lopt, 2 }, - { "http-passwd", required_argument, &lopt, 3 }, - { "http-proxy-user", required_argument, &lopt, 4 }, - { "http-proxy-passwd", required_argument, &lopt, 5 }, - { "http-auth-scheme", required_argument, &lopt, 6 }, - { "referer", required_argument, &lopt, 7 }, - { "retry-wait", required_argument, &lopt, 8 }, - { "ftp-user", required_argument, &lopt, 9 }, - { "ftp-passwd", required_argument, &lopt, 10 }, - { "ftp-type", required_argument, &lopt, 11 }, - { "ftp-pasv", no_argument, NULL, 'p' }, - { "ftp-via-http-proxy", required_argument, &lopt, 12 }, - //{ "min-segment-size", required_argument, &lopt, 13 }, - { "http-proxy-method", required_argument, &lopt, 14 }, - { "lowest-speed-limit", required_argument, &lopt, 200 }, - { "max-download-limit", required_argument, &lopt, 201 }, - { "file-allocation", required_argument, 0, 'a' }, - { "allow-overwrite", required_argument, &lopt, 202 }, -#ifdef ENABLE_MESSAGE_DIGEST - { "check-integrity", required_argument, &lopt, 203 }, - { "realtime-chunk-checksum", required_argument, &lopt, 204 }, -#endif // ENABLE_MESSAGE_DIGEST - { "continue", no_argument, 0, 'c' }, - { "user-agent", required_argument, 0, 'U' }, - { "no-netrc", no_argument, 0, 'n' }, - { "input-file", required_argument, 0, 'i' }, - { "max-concurrent-downloads", required_argument, 0, 'j' }, - { "load-cookies", required_argument, &lopt, 205 }, - { "force-sequential", optional_argument, 0, 'Z' }, - { "auto-file-renaming", optional_argument, &lopt, 206 }, - { "parameterized-uri", optional_argument, 0, 'P' }, -#if defined ENABLE_BITTORRENT || ENABLE_METALINK - { "show-files", no_argument, NULL, 'S' }, - { "select-file", required_argument, &lopt, 21 }, -#endif // ENABLE_BITTORRENT || ENABLE_METALINK -#ifdef ENABLE_BITTORRENT - { "torrent-file", required_argument, NULL, 'T' }, - { "listen-port", required_argument, &lopt, 15 }, - { "follow-torrent", required_argument, &lopt, 16 }, - { "no-preallocation", no_argument, &lopt, 18 }, - { "direct-file-mapping", required_argument, &lopt, 19 }, - // TODO remove upload-limit. - //{ "upload-limit", required_argument, &lopt, 20 }, - { "seed-time", required_argument, &lopt, 22 }, - { "seed-ratio", required_argument, &lopt, 23 }, - { "max-upload-limit", required_argument, &lopt, 24 }, - { "peer-id-prefix", required_argument, &lopt, 25 }, -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - { "metalink-file", required_argument, NULL, 'M' }, - { "metalink-servers", required_argument, NULL, 'C' }, - { "metalink-version", required_argument, &lopt, 100 }, - { "metalink-language", required_argument, &lopt, 101 }, - { "metalink-os", required_argument, &lopt, 102 }, - { "follow-metalink", required_argument, &lopt, 103 }, - { "metalink-location", required_argument, &lopt, 104 }, -#endif // ENABLE_METALINK - { "version", no_argument, NULL, 'v' }, - { "help", no_argument, NULL, 'h' }, - { 0, 0, 0, 0 } - }; - c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vhST:M:C:a:cU:ni:j:Z::P::", longOpts, &optIndex); - if(c == -1) { - break; - } - switch(c) { - case 0:{ - switch(lopt) { - case 1: - cmdstream << PREF_HTTP_PROXY << "=" << optarg << "\n"; - break; - case 2: - cmdstream << PREF_HTTP_USER << "=" << optarg << "\n"; - break; - case 3: - cmdstream << PREF_HTTP_PASSWD << "=" << optarg << "\n"; - break; - case 4: - cmdstream << PREF_HTTP_PROXY_USER << "=" << optarg << "\n"; - break; - case 5: - cmdstream << PREF_HTTP_PROXY_PASSWD << "=" << optarg << "\n"; - break; - case 6: - cmdstream << PREF_HTTP_AUTH_SCHEME << "=" << optarg << "\n"; - break; - case 7: - cmdstream << PREF_REFERER << "=" << optarg << "\n"; - break; - case 8: - cmdstream << PREF_RETRY_WAIT << "=" << optarg << "\n"; - break; - case 9: - cmdstream << PREF_FTP_USER << "=" << optarg << "\n"; - break; - case 10: - cmdstream << PREF_FTP_PASSWD << "=" << optarg << "\n"; - break; - case 11: - cmdstream << PREF_FTP_TYPE << "=" << optarg << "\n"; - break; - case 12: - cmdstream << PREF_FTP_VIA_HTTP_PROXY << "=" << optarg << "\n"; - break; - case 13: - cmdstream << PREF_MIN_SEGMENT_SIZE << "=" << optarg << "\n"; - break; - case 14: - cmdstream << PREF_HTTP_PROXY_METHOD << "=" << optarg << "\n"; - break; - case 15: - cmdstream << PREF_LISTEN_PORT << "=" << optarg << "\n"; - break; - case 16: - cmdstream << PREF_FOLLOW_TORRENT << "=" << optarg << "\n"; - break; - case 18: - cmdstream << PREF_NO_PREALLOCATION << "=" << V_TRUE << "\n"; - break; - case 19: - cmdstream << PREF_DIRECT_FILE_MAPPING << "=" << optarg << "\n"; - break; - case 21: - cmdstream << PREF_SELECT_FILE << "=" << optarg << "\n"; - break; - case 22: - cmdstream << PREF_SEED_TIME << "=" << optarg << "\n"; - break; - case 23: - cmdstream << PREF_SEED_RATIO << "=" << optarg << "\n"; - break; - case 24: - cmdstream << PREF_MAX_UPLOAD_LIMIT << "=" << optarg << "\n"; - break; - case 25: - cmdstream << PREF_PEER_ID_PREFIX << "=" << optarg << "\n"; - case 100: - cmdstream << PREF_METALINK_VERSION << "=" << optarg << "\n"; - break; - case 101: - cmdstream << PREF_METALINK_LANGUAGE << "=" << optarg << "\n"; - break; - case 102: - cmdstream << PREF_METALINK_OS << "=" << optarg << "\n"; - break; - case 103: - cmdstream << PREF_FOLLOW_METALINK << "=" << optarg << "\n"; - break; - case 104: - cmdstream << PREF_METALINK_LOCATION << "=" << optarg << "\n"; - break; - case 200: - cmdstream << PREF_LOWEST_SPEED_LIMIT << "=" << optarg << "\n"; - break; - case 201: - cmdstream << PREF_MAX_DOWNLOAD_LIMIT << "=" << optarg << "\n"; - break; - case 202: - cmdstream << PREF_ALLOW_OVERWRITE << "=" << optarg << "\n"; - break; - case 203: - cmdstream << PREF_CHECK_INTEGRITY << "=" << optarg << "\n"; - break; - case 204: - cmdstream << PREF_REALTIME_CHUNK_CHECKSUM << "=" << optarg << "\n"; - break; - case 205: - cmdstream << PREF_LOAD_COOKIES << "=" << optarg << "\n"; - break; - case 206: - cmdstream << PREF_AUTO_FILE_RENAMING << "=" << toBoolArg(optarg) << "\n"; - break; - } - break; - } -#ifdef HAVE_DAEMON - case 'D': - cmdstream << PREF_DAEMON << "=" << V_TRUE << "\n"; - break; -#endif // HAVE_DAEMON - case 'd': - cmdstream << PREF_DIR << "=" << optarg << "\n"; - break; - case 'o': - cmdstream << PREF_OUT << "=" << optarg << "\n"; - break; - case 'l': - cmdstream << PREF_LOG << "=" << optarg << "\n"; - break; - case 's': - cmdstream << PREF_SPLIT << "=" << optarg << "\n"; - break; - case 't': - cmdstream << PREF_TIMEOUT << "=" << optarg << "\n"; - break; - case 'm': - cmdstream << PREF_MAX_TRIES << "=" << optarg << "\n"; - break; - case 'p': - cmdstream << PREF_FTP_PASV << "=" << V_TRUE << "\n"; - break; - case 'S': - cmdstream << PREF_SHOW_FILES << "=" << V_TRUE << "\n"; - break; - case 'T': - cmdstream << PREF_TORRENT_FILE << "=" << optarg << "\n"; - break; - case 'M': - cmdstream << PREF_METALINK_FILE << "=" << optarg << "\n"; - break; - case 'C': - cmdstream << PREF_METALINK_SERVERS << "=" << optarg << "\n"; - break; - case 'a': - cmdstream << PREF_FILE_ALLOCATION << "=" << optarg << "\n"; - break; - case 'c': - cmdstream << PREF_CONTINUE << "=" << V_TRUE << "\n"; - break; - case 'U': - cmdstream << PREF_USER_AGENT << "=" << optarg << "\n"; - break; - case 'n': - cmdstream << PREF_NO_NETRC << "=" << V_TRUE << "\n"; - break; - case 'i': - cmdstream << PREF_INPUT_FILE << "=" << optarg << "\n"; - break; - case 'j': - cmdstream << PREF_MAX_CONCURRENT_DOWNLOADS << "=" << optarg << "\n"; - break; - case 'Z': - cmdstream << PREF_FORCE_SEQUENTIAL << "=" << toBoolArg(optarg) << "\n"; - break; - case 'P': - cmdstream << PREF_PARAMETERIZED_URI << "=" << toBoolArg(optarg) << "\n"; - break; - case 'v': - showVersion(); - exit(EXIT_SUCCESS); - case 'h': - showUsage(); - exit(EXIT_SUCCESS); - default: - exit(EXIT_FAILURE); - } - } - - { - OptionParser oparser; - oparser.setOptionHandlers(OptionHandlerFactory::createOptionHandlers()); - string cfname = Util::getHomeDir()+"/.aria2/aria2.conf"; - ifstream cfstream(cfname.c_str()); - try { - oparser.parse(op, cfstream); - } catch(Exception* e) { - cerr << "Parse error in " << cfname << endl; - cerr << e->getMsg() << endl; - delete e; - exit(EXIT_FAILURE); - } - try { - oparser.parse(op, cmdstream); - } catch(Exception* e) { - cerr << e->getMsg() << endl; - delete e; - exit(EXIT_FAILURE); - } - } - if(op->defined(PREF_HTTP_USER)) { - op->put(PREF_HTTP_AUTH_ENABLED, V_TRUE); - } - if(op->defined(PREF_HTTP_PROXY_USER)) { - op->put(PREF_HTTP_PROXY_AUTH_ENABLED, V_TRUE); - } - if( -#ifdef ENABLE_BITTORRENT - !op->defined(PREF_TORRENT_FILE) && -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - !op->defined(PREF_METALINK_FILE) && -#endif // ENABLE_METALINK - !op->defined(PREF_INPUT_FILE)) { - if(optind == argc) { - cerr << MSG_URI_REQUIRED << endl; - exit(EXIT_FAILURE); - } - } -#ifdef HAVE_DAEMON - if(op->getAsBool(PREF_DAEMON)) { - if(daemon(1, 1) < 0) { - perror(MSG_DAEMON_FAILED); - exit(EXIT_FAILURE); - } - } -#endif // HAVE_DAEMON + Option* op = option_processing(argc, argv); Strings args(argv+optind, argv+argc); #ifdef HAVE_LIBSSL @@ -780,7 +140,6 @@ int main(int argc, char* argv[]) { #endif // ENABLE_METALINK SimpleRandomizer::init(); BitfieldManFactory::setDefaultRandomizer(SimpleRandomizer::getInstance()); - FileAllocationMonitorFactory::setFactory(new ConsoleFileAllocationMonitorFactory()); if(op->getAsBool(PREF_STDOUT_LOG)) { LogFactory::setLogFile(DEV_STDOUT); } else if(op->get(PREF_LOG).size()) { @@ -829,28 +188,43 @@ int main(int argc, char* argv[]) { Util::setGlobalSignalHandler(SIGPIPE, SIG_IGN, 0); #endif - RequestInfo* firstReqInfo; + MultiUrlRequestInfo* firstReqInfo; + // TODO added _X for test. Please remove this later on. #ifdef ENABLE_BITTORRENT if(op->defined(PREF_TORRENT_FILE)) { - firstReqInfo = new TorrentRequestInfo(op->get(PREF_TORRENT_FILE), - op); - Strings targetFiles; - if(op->defined(PREF_TORRENT_FILE) && !args.empty()) { - targetFiles = args; + Strings nargs; + if(op->get(PREF_PARAMETERIZED_URI) == V_TRUE) { + nargs = unfoldURI(args); + } else { + nargs = args; } - ((TorrentRequestInfo*)firstReqInfo)->setTargetFiles(targetFiles); + Strings xargs; + ncopy(nargs.begin(), nargs.end(), op->getAsInt(PREF_SPLIT), + back_inserter(xargs)); + + RequestGroupHandle rg = new RequestGroup(op, xargs); + DefaultBtContextHandle btContext = new DefaultBtContext(); + btContext->load(op->get(PREF_TORRENT_FILE)); + if(op->defined(PREF_PEER_ID_PREFIX)) { + btContext->setPeerIdPrefix(op->get(PREF_PEER_ID_PREFIX)); + } + btContext->setDir(op->get(PREF_DIR)); + rg->setDownloadContext(btContext); + btContext->setOwnerRequestGroup(rg.get()); + + RequestGroups groups; + groups.push_back(rg); + firstReqInfo = new MultiUrlRequestInfo(groups, op); } else #endif // ENABLE_BITTORRENT #ifdef ENABLE_METALINK if(op->defined(PREF_METALINK_FILE)) { - firstReqInfo = new MetalinkRequestInfo(op->get(PREF_METALINK_FILE), - op); - Strings targetFiles; - if(op->defined(PREF_METALINK_FILE) && !args.empty()) { - targetFiles = args; + RequestGroups groups = Metalink2RequestGroup(op).generate(op->get(PREF_METALINK_FILE)); + if(groups.empty()) { + throw new FatalException("No files to download."); } - ((MetalinkRequestInfo*)firstReqInfo)->setTargetFiles(targetFiles); + firstReqInfo = new MultiUrlRequestInfo(groups, op); } else #endif // ENABLE_METALINK @@ -872,16 +246,15 @@ int main(int argc, char* argv[]) { for(Strings::const_iterator itr = unfoldedURIs.begin(); itr != unfoldedURIs.end(); ++itr) { Strings xuris; - ncopy(itr, itr+1, op->getAsInt(PREF_SPLIT), - back_inserter(xuris)); - RequestGroupHandle rg = new RequestGroup(xuris, op); + ncopy(itr, itr+1, op->getAsInt(PREF_SPLIT), back_inserter(xuris)); + RequestGroupHandle rg = createRequestGroup(op, xuris); groups.push_back(rg); } } else if(uris.size() > 0) { Strings xuris; ncopy(uris.begin(), uris.end(), op->getAsInt(PREF_SPLIT), back_inserter(xuris)); - RequestGroupHandle rg = new RequestGroup(xuris, op); + RequestGroupHandle rg = createRequestGroup(op, xuris); groups.push_back(rg); } } @@ -901,8 +274,8 @@ int main(int argc, char* argv[]) { itr != nargs.end(); ++itr) { Strings xuris; ncopy(itr, itr+1, op->getAsInt(PREF_SPLIT), - back_inserter(xuris)); - RequestGroupHandle rg = new RequestGroup(xuris, op); + back_inserter(xuris)); + RequestGroupHandle rg = createRequestGroup(op, xuris); groups.push_back(rg); } firstReqInfo = new MultiUrlRequestInfo(groups, op); @@ -910,36 +283,15 @@ int main(int argc, char* argv[]) { Strings xargs; ncopy(nargs.begin(), nargs.end(), op->getAsInt(PREF_SPLIT), back_inserter(xargs)); - firstReqInfo = new MultiUrlRequestInfo(xargs, op); + RequestGroupHandle rg = createRequestGroup(op, xargs, op->get(PREF_OUT)); + RequestGroups groups; + groups.push_back(rg); + firstReqInfo = new MultiUrlRequestInfo(groups, op); } } - RequestInfos reqInfos; - if(firstReqInfo) { - reqInfos.push_front(firstReqInfo); - } - while(reqInfos.size()) { - RequestInfoHandle reqInfo = reqInfos.front(); - reqInfos.pop_front(); - RequestInfos nextReqInfos = reqInfo->execute(); - copy(nextReqInfos.begin(), nextReqInfos.end(), front_inserter(reqInfos)); - /* - if(reqInfo->isFail()) { - exitStatus = EXIT_FAILURE; - } else if(reqInfo->getFileInfo().checkReady()) { - cout << _("Now verifying checksum.\n" - "This may take some time depending on your PC environment" - " and the size of file.") << endl; - if(reqInfo->getFileInfo().check()) { - cout << _("checksum OK.") << endl; - } else { - // TODO - cout << _("checksum ERROR.") << endl; - exitStatus = EXIT_FAILURE; - } - } - */ - } + firstReqInfo->execute(); + } catch(Exception* ex) { cerr << EX_EXCEPTION_CAUGHT << "\n" << ex->getMsg() << endl; delete ex; diff --git a/src/messageDigest.h b/src/messageDigest.h index 7bf37685..612e0920 100644 --- a/src/messageDigest.h +++ b/src/messageDigest.h @@ -36,7 +36,7 @@ #define _D_MESSAGE_DIGEST_H_ #include "common.h" -#include "FatalException.h" +#include "DlAbortEx.h" #include #ifdef HAVE_LIBSSL @@ -94,7 +94,7 @@ public: { DigestAlgoMap::const_iterator itr = digestAlgos.find(algostring); if(itr == digestAlgos.end()) { - throw new FatalException("Digest algorithm %s is not supported.", algostring.c_str()); + throw new DlAbortEx("Digest algorithm %s is not supported.", algostring.c_str()); } return (*itr).second; } diff --git a/src/option_processing.cc b/src/option_processing.cc new file mode 100644 index 00000000..92c4b2f0 --- /dev/null +++ b/src/option_processing.cc @@ -0,0 +1,434 @@ +/* */ +#include "common.h" +#include "Option.h" +#include "prefs.h" +#include "OptionParser.h" +#include "OptionHandlerFactory.h" +#include "Util.h" +#include "message.h" +#include +#include + +extern char* optarg; +extern int optind, opterr, optopt; +#include + +extern void showVersion(); +extern void showUsage(); + +static string toBoolArg(const char* optarg) +{ + string arg; + if(!optarg || string(optarg) == "") { + arg = V_TRUE; + } else { + arg = optarg; + } + return arg; +} + +Option* option_processing(int argc, char* const argv[]) +{ + stringstream cmdstream; + int32_t c; + Option* op = new Option(); + op->put(PREF_STDOUT_LOG, V_FALSE); + op->put(PREF_DIR, "."); + op->put(PREF_SPLIT, "1"); + op->put(PREF_DAEMON, V_FALSE); + op->put(PREF_SEGMENT_SIZE, Util::itos((int32_t)(1024*1024))); + op->put(PREF_HTTP_KEEP_ALIVE, V_FALSE); + op->put(PREF_LISTEN_PORT, "-1"); + op->put(PREF_METALINK_SERVERS, "5"); + op->put(PREF_FOLLOW_TORRENT, +#ifdef ENABLE_BITTORRENT + V_TRUE +#else + V_FALSE +#endif // ENABLE_BITTORRENT + ); + op->put(PREF_FOLLOW_METALINK, +#ifdef ENABLE_METALINK + V_TRUE +#else + V_FALSE +#endif // ENABLE_METALINK + ); + op->put(PREF_RETRY_WAIT, "5"); + op->put(PREF_TIMEOUT, "60"); + op->put(PREF_DNS_TIMEOUT, "10"); + op->put(PREF_PEER_CONNECTION_TIMEOUT, "60"); + op->put(PREF_BT_TIMEOUT, "180"); + op->put(PREF_BT_REQUEST_TIMEOUT, "60"); + op->put(PREF_BT_KEEP_ALIVE_INTERVAL, "120"); + op->put(PREF_MIN_SEGMENT_SIZE, "1048576");// 1M + op->put(PREF_MAX_TRIES, "5"); + op->put(PREF_HTTP_AUTH_SCHEME, V_BASIC); + op->put(PREF_HTTP_PROXY_METHOD, V_TUNNEL); + op->put(PREF_FTP_TYPE, V_BINARY); + op->put(PREF_FTP_VIA_HTTP_PROXY, V_TUNNEL); + op->put(PREF_AUTO_SAVE_INTERVAL, "60"); + op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE); + op->put(PREF_LOWEST_SPEED_LIMIT, "0"); + op->put(PREF_MAX_DOWNLOAD_LIMIT, "0"); + op->put(PREF_MAX_UPLOAD_LIMIT, "0"); + op->put(PREF_STARTUP_IDLE_TIME, "10"); + op->put(PREF_TRACKER_MAX_TRIES, "10"); + op->put(PREF_FILE_ALLOCATION, V_NONE); + op->put(PREF_ALLOW_OVERWRITE, V_FALSE); + op->put(PREF_REALTIME_CHUNK_CHECKSUM, V_TRUE); + op->put(PREF_CHECK_INTEGRITY, V_FALSE); + op->put(PREF_NETRC_PATH, Util::getHomeDir()+"/.netrc"); + op->put(PREF_CONTINUE, V_FALSE); + op->put(PREF_USER_AGENT, "aria2"); + op->put(PREF_NO_NETRC, V_FALSE); + op->put(PREF_MAX_CONCURRENT_DOWNLOADS, "5"); + op->put(PREF_DIRECT_DOWNLOAD_TIMEOUT, "15"); + op->put(PREF_FORCE_SEQUENTIAL, V_FALSE); + op->put(PREF_AUTO_FILE_RENAMING, V_TRUE); + op->put(PREF_PARAMETERIZED_URI, V_FALSE); + while(1) { + int optIndex = 0; + int lopt; + static struct option longOpts[] = { +#ifdef HAVE_DAEMON + { "daemon", no_argument, NULL, 'D' }, +#endif // HAVE_DAEMON + { "dir", required_argument, NULL, 'd' }, + { "out", required_argument, NULL, 'o' }, + { "log", required_argument, NULL, 'l' }, + { "split", required_argument, NULL, 's' }, + { "timeout", required_argument, NULL, 't' }, + { "max-tries", required_argument, NULL, 'm' }, + { "http-proxy", required_argument, &lopt, 1 }, + { "http-user", required_argument, &lopt, 2 }, + { "http-passwd", required_argument, &lopt, 3 }, + { "http-proxy-user", required_argument, &lopt, 4 }, + { "http-proxy-passwd", required_argument, &lopt, 5 }, + { "http-auth-scheme", required_argument, &lopt, 6 }, + { "referer", required_argument, &lopt, 7 }, + { "retry-wait", required_argument, &lopt, 8 }, + { "ftp-user", required_argument, &lopt, 9 }, + { "ftp-passwd", required_argument, &lopt, 10 }, + { "ftp-type", required_argument, &lopt, 11 }, + { "ftp-pasv", no_argument, NULL, 'p' }, + { "ftp-via-http-proxy", required_argument, &lopt, 12 }, + //{ "min-segment-size", required_argument, &lopt, 13 }, + { "http-proxy-method", required_argument, &lopt, 14 }, + { "lowest-speed-limit", required_argument, &lopt, 200 }, + { "max-download-limit", required_argument, &lopt, 201 }, + { "file-allocation", required_argument, 0, 'a' }, + { "allow-overwrite", required_argument, &lopt, 202 }, +#ifdef ENABLE_MESSAGE_DIGEST + { "check-integrity", required_argument, &lopt, 203 }, + { "realtime-chunk-checksum", required_argument, &lopt, 204 }, +#endif // ENABLE_MESSAGE_DIGEST + { "continue", no_argument, 0, 'c' }, + { "user-agent", required_argument, 0, 'U' }, + { "no-netrc", no_argument, 0, 'n' }, + { "input-file", required_argument, 0, 'i' }, + { "max-concurrent-downloads", required_argument, 0, 'j' }, + { "load-cookies", required_argument, &lopt, 205 }, + { "force-sequential", optional_argument, 0, 'Z' }, + { "auto-file-renaming", optional_argument, &lopt, 206 }, + { "parameterized-uri", optional_argument, 0, 'P' }, +#if defined ENABLE_BITTORRENT || ENABLE_METALINK + { "show-files", no_argument, NULL, 'S' }, + { "select-file", required_argument, &lopt, 21 }, +#endif // ENABLE_BITTORRENT || ENABLE_METALINK +#ifdef ENABLE_BITTORRENT + { "torrent-file", required_argument, NULL, 'T' }, + { "listen-port", required_argument, &lopt, 15 }, + { "follow-torrent", required_argument, &lopt, 16 }, + { "no-preallocation", no_argument, &lopt, 18 }, + { "direct-file-mapping", required_argument, &lopt, 19 }, + // TODO remove upload-limit. + //{ "upload-limit", required_argument, &lopt, 20 }, + { "seed-time", required_argument, &lopt, 22 }, + { "seed-ratio", required_argument, &lopt, 23 }, + { "max-upload-limit", required_argument, &lopt, 24 }, + { "peer-id-prefix", required_argument, &lopt, 25 }, +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + { "metalink-file", required_argument, NULL, 'M' }, + { "metalink-servers", required_argument, NULL, 'C' }, + { "metalink-version", required_argument, &lopt, 100 }, + { "metalink-language", required_argument, &lopt, 101 }, + { "metalink-os", required_argument, &lopt, 102 }, + { "follow-metalink", required_argument, &lopt, 103 }, + { "metalink-location", required_argument, &lopt, 104 }, +#endif // ENABLE_METALINK + { "version", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vhST:M:C:a:cU:ni:j:Z::P::", longOpts, &optIndex); + if(c == -1) { + break; + } + switch(c) { + case 0:{ + switch(lopt) { + case 1: + cmdstream << PREF_HTTP_PROXY << "=" << optarg << "\n"; + break; + case 2: + cmdstream << PREF_HTTP_USER << "=" << optarg << "\n"; + break; + case 3: + cmdstream << PREF_HTTP_PASSWD << "=" << optarg << "\n"; + break; + case 4: + cmdstream << PREF_HTTP_PROXY_USER << "=" << optarg << "\n"; + break; + case 5: + cmdstream << PREF_HTTP_PROXY_PASSWD << "=" << optarg << "\n"; + break; + case 6: + cmdstream << PREF_HTTP_AUTH_SCHEME << "=" << optarg << "\n"; + break; + case 7: + cmdstream << PREF_REFERER << "=" << optarg << "\n"; + break; + case 8: + cmdstream << PREF_RETRY_WAIT << "=" << optarg << "\n"; + break; + case 9: + cmdstream << PREF_FTP_USER << "=" << optarg << "\n"; + break; + case 10: + cmdstream << PREF_FTP_PASSWD << "=" << optarg << "\n"; + break; + case 11: + cmdstream << PREF_FTP_TYPE << "=" << optarg << "\n"; + break; + case 12: + cmdstream << PREF_FTP_VIA_HTTP_PROXY << "=" << optarg << "\n"; + break; + case 13: + cmdstream << PREF_MIN_SEGMENT_SIZE << "=" << optarg << "\n"; + break; + case 14: + cmdstream << PREF_HTTP_PROXY_METHOD << "=" << optarg << "\n"; + break; + case 15: + cmdstream << PREF_LISTEN_PORT << "=" << optarg << "\n"; + break; + case 16: + cmdstream << PREF_FOLLOW_TORRENT << "=" << optarg << "\n"; + break; + case 18: + cmdstream << PREF_NO_PREALLOCATION << "=" << V_TRUE << "\n"; + break; + case 19: + cmdstream << PREF_DIRECT_FILE_MAPPING << "=" << optarg << "\n"; + break; + case 21: + cmdstream << PREF_SELECT_FILE << "=" << optarg << "\n"; + break; + case 22: + cmdstream << PREF_SEED_TIME << "=" << optarg << "\n"; + break; + case 23: + cmdstream << PREF_SEED_RATIO << "=" << optarg << "\n"; + break; + case 24: + cmdstream << PREF_MAX_UPLOAD_LIMIT << "=" << optarg << "\n"; + break; + case 25: + cmdstream << PREF_PEER_ID_PREFIX << "=" << optarg << "\n"; + case 100: + cmdstream << PREF_METALINK_VERSION << "=" << optarg << "\n"; + break; + case 101: + cmdstream << PREF_METALINK_LANGUAGE << "=" << optarg << "\n"; + break; + case 102: + cmdstream << PREF_METALINK_OS << "=" << optarg << "\n"; + break; + case 103: + cmdstream << PREF_FOLLOW_METALINK << "=" << optarg << "\n"; + break; + case 104: + cmdstream << PREF_METALINK_LOCATION << "=" << optarg << "\n"; + break; + case 200: + cmdstream << PREF_LOWEST_SPEED_LIMIT << "=" << optarg << "\n"; + break; + case 201: + cmdstream << PREF_MAX_DOWNLOAD_LIMIT << "=" << optarg << "\n"; + break; + case 202: + cmdstream << PREF_ALLOW_OVERWRITE << "=" << optarg << "\n"; + break; + case 203: + cmdstream << PREF_CHECK_INTEGRITY << "=" << optarg << "\n"; + break; + case 204: + cmdstream << PREF_REALTIME_CHUNK_CHECKSUM << "=" << optarg << "\n"; + break; + case 205: + cmdstream << PREF_LOAD_COOKIES << "=" << optarg << "\n"; + break; + case 206: + cmdstream << PREF_AUTO_FILE_RENAMING << "=" << toBoolArg(optarg) << "\n"; + break; + } + break; + } +#ifdef HAVE_DAEMON + case 'D': + cmdstream << PREF_DAEMON << "=" << V_TRUE << "\n"; + break; +#endif // HAVE_DAEMON + case 'd': + cmdstream << PREF_DIR << "=" << optarg << "\n"; + break; + case 'o': + cmdstream << PREF_OUT << "=" << optarg << "\n"; + break; + case 'l': + cmdstream << PREF_LOG << "=" << optarg << "\n"; + break; + case 's': + cmdstream << PREF_SPLIT << "=" << optarg << "\n"; + break; + case 't': + cmdstream << PREF_TIMEOUT << "=" << optarg << "\n"; + break; + case 'm': + cmdstream << PREF_MAX_TRIES << "=" << optarg << "\n"; + break; + case 'p': + cmdstream << PREF_FTP_PASV << "=" << V_TRUE << "\n"; + break; + case 'S': + cmdstream << PREF_SHOW_FILES << "=" << V_TRUE << "\n"; + break; + case 'T': + cmdstream << PREF_TORRENT_FILE << "=" << optarg << "\n"; + break; + case 'M': + cmdstream << PREF_METALINK_FILE << "=" << optarg << "\n"; + break; + case 'C': + cmdstream << PREF_METALINK_SERVERS << "=" << optarg << "\n"; + break; + case 'a': + cmdstream << PREF_FILE_ALLOCATION << "=" << optarg << "\n"; + break; + case 'c': + cmdstream << PREF_CONTINUE << "=" << V_TRUE << "\n"; + break; + case 'U': + cmdstream << PREF_USER_AGENT << "=" << optarg << "\n"; + break; + case 'n': + cmdstream << PREF_NO_NETRC << "=" << V_TRUE << "\n"; + break; + case 'i': + cmdstream << PREF_INPUT_FILE << "=" << optarg << "\n"; + break; + case 'j': + cmdstream << PREF_MAX_CONCURRENT_DOWNLOADS << "=" << optarg << "\n"; + break; + case 'Z': + cmdstream << PREF_FORCE_SEQUENTIAL << "=" << toBoolArg(optarg) << "\n"; + break; + case 'P': + cmdstream << PREF_PARAMETERIZED_URI << "=" << toBoolArg(optarg) << "\n"; + break; + case 'v': + showVersion(); + exit(EXIT_SUCCESS); + case 'h': + showUsage(); + exit(EXIT_SUCCESS); + default: + exit(EXIT_FAILURE); + } + } + + { + OptionParser oparser; + oparser.setOptionHandlers(OptionHandlerFactory::createOptionHandlers()); + string cfname = Util::getHomeDir()+"/.aria2/aria2.conf"; + ifstream cfstream(cfname.c_str()); + try { + oparser.parse(op, cfstream); + } catch(Exception* e) { + cerr << "Parse error in " << cfname << endl; + cerr << e->getMsg() << endl; + delete e; + exit(EXIT_FAILURE); + } + try { + oparser.parse(op, cmdstream); + } catch(Exception* e) { + cerr << e->getMsg() << endl; + delete e; + exit(EXIT_FAILURE); + } + } + if(op->defined(PREF_HTTP_USER)) { + op->put(PREF_HTTP_AUTH_ENABLED, V_TRUE); + } + if(op->defined(PREF_HTTP_PROXY_USER)) { + op->put(PREF_HTTP_PROXY_AUTH_ENABLED, V_TRUE); + } + if( +#ifdef ENABLE_BITTORRENT + !op->defined(PREF_TORRENT_FILE) && +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + !op->defined(PREF_METALINK_FILE) && +#endif // ENABLE_METALINK + !op->defined(PREF_INPUT_FILE)) { + if(optind == argc) { + cerr << MSG_URI_REQUIRED << endl; + exit(EXIT_FAILURE); + } + } +#ifdef HAVE_DAEMON + if(op->getAsBool(PREF_DAEMON)) { + if(daemon(1, 1) < 0) { + perror(MSG_DAEMON_FAILED); + exit(EXIT_FAILURE); + } + } +#endif // HAVE_DAEMON + return op; +} diff --git a/src/version_usage.cc b/src/version_usage.cc new file mode 100644 index 00000000..b246e720 --- /dev/null +++ b/src/version_usage.cc @@ -0,0 +1,305 @@ +/* */ +#include "common.h" +#include "FeatureConfig.h" +#include "messageDigest.h" + +void showVersion() { + cout << PACKAGE << _(" version ") << PACKAGE_VERSION << endl; + cout << "**Configuration**" << endl; + cout << FeatureConfig::getInstance()->getConfigurationSummary(); +#ifdef ENABLE_MESSAGE_DIGEST + cout << "message digest algorithms: " << MessageDigestContext::getSupportedAlgoString() << endl; +#endif // ENABLE_MESSAGE_DIGEST + cout << endl; + cout << "Copyright (C) 2006, 2007 Tatsuhiro Tsujikawa" << endl; + cout << endl; + cout << + _("This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"); + cout << endl; + cout << _("Contact Info:") << endl; + cout << "Tatsuhiro Tsujikawa " << endl; + cout << endl; + +} + +void showUsage() { + printf(_("Usage: %s [options] URL ...\n"), PACKAGE_NAME); +#ifdef ENABLE_BITTORRENT + printf(_(" %s [options] -T TORRENT_FILE URL ...\n"), PACKAGE_NAME); +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + printf(_(" %s [options] -M METALINK_FILE\n"), PACKAGE_NAME); +#endif // ENABLE_METALINK + cout << endl; + cout << _("Options:") << endl; + cout << _(" -d, --dir=DIR The directory to store the downloaded file.") << endl; + cout << _(" -o, --out=FILE The file name of the downloaded file.") << endl; + cout << _(" -l, --log=LOG The file name of the log file. If '-' is\n" + " specified, log is written to stdout.") << endl; +#ifdef HAVE_DAEMON + cout << _(" -D, --daemon Run as daemon.") << endl; +#endif // HAVE_DAEMON + cout << _(" -s, --split=N Download a file using N connections. N must be\n" + " between 1 and 5. This option affects all URLs.\n" + " Thus, aria2 connects to each URL with\n" + " N connections.\n" + " Default: 1") << endl; + cout << _(" --retry-wait=SEC Set the seconds to wait to retry after an error\n" + " has occured. Specify a value between 0 and 60.\n" + " Default: 5") << endl; + cout << _(" -t, --timeout=SEC Set timeout in seconds. Default: 60") << endl; + cout << _(" -m, --max-tries=N Set number of tries. 0 means unlimited.\n" + " Default: 5") << endl; + /* + cout << _(" --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n" + " K or M(1K = 1024, 1M = 1024K). This\n" + " value must be greater than or equal to\n" + " 1024. Default: 1M") << endl; + */ + cout << _(" --http-proxy=HOST:PORT Use HTTP proxy server. This affects all URLs.") << endl; + cout << _(" --http-user=USER Set HTTP user. This affects all URLs.") << endl; + cout << _(" --http-passwd=PASSWD Set HTTP password. This affects all URLs.") << endl; + cout << _(" --http-proxy-user=USER Set HTTP proxy user. This affects all URLs.") << endl; + cout << _(" --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects all URLs.") << endl; + cout << _(" --http-proxy-method=METHOD Set the method to use in proxy request.\n" + " METHOD is either 'get' or 'tunnel'.\n" + " Default: tunnel") << endl; + cout << _(" --http-auth-scheme=SCHEME Set HTTP authentication scheme. Currently, basic\n" + " is the only supported scheme.\n" + " Default: basic") << endl; + cout << _(" --referer=REFERER Set Referer. This affects all URLs.") << endl; + cout << _(" --ftp-user=USER Set FTP user. This affects all URLs.\n" + " Default: anonymous") << endl; + cout << _(" --ftp-passwd=PASSWD Set FTP password. This affects all URLs.\n" + " Default: ARIA2USER@") << endl; + cout << _(" --ftp-type=TYPE Set FTP transfer type. TYPE is either 'binary'\n" + " or 'ascii'.\n" + " Default: binary") << endl; + cout << _(" -p, --ftp-pasv Use passive mode in FTP.") << endl; + cout << _(" --ftp-via-http-proxy=METHOD Use HTTP proxy in FTP. METHOD is either 'get' or\n" + " 'tunnel'.\n" + " Default: tunnel") << endl; + cout << _(" --lowest-speed-limit=SPEED Close connection if download speed is lower than\n" + " or equal to this value(bytes per sec).\n" + " 0 means aria2 does not have a lowest speed limit.\n" + " You can append K or M(1K = 1024, 1M = 1024K).\n" + + " This option does not affect BitTorrent downloads.\n" + " Default: 0") << endl; + cout << _(" --max-download-limit=SPEED Set max download speed in bytes per sec.\n" + " 0 means unrestricted.\n" + " You can append K or M(1K = 1024, 1M = 1024K).\n" + " Default: 0") << endl; + cout << _(" --file-allocation=METHOD Specify file allocation method. METHOD is either\n" + " 'none' or 'prealloc'. 'none' doesn't pre-allocate\n" + " file space. 'prealloc' pre-allocates file space\n" + " before download begins. This may take some time\n" + " depending on the size of the file.\n" + " Default: none") << endl; + cout << _(" --allow-overwrite=true|false If false, aria2 doesn't download a file which\n" + " already exists but the corresponding .aria2 file\n" + " doesn't exist.\n" + " Default: false") << endl; + cout << _(" -Z, --force-sequential[=true|false] Fetch URIs in the command-line sequentially\n" + " and download each URI in a separate session, like\n" + " the usual command-line download utilities.\n" + " Default: false") << endl; + cout << _(" --auto-file-renaming[=true|false] Rename file name if the same file already\n" + " exists. This option works only in http(s)/ftp\n" + " download.\n" + " The new file name has a dot and a number(1..9999)\n" + " appended.\n" + " Default: true") << endl; + cout << _(" -P, --parameterized-uri[=true|false] Enable parameterized URI support.\n" + " You can specify set of parts:\n" + " http://{sv1,sv2,sv3}/foo.iso\n" + " Also you can specify numeric sequences with step\n" + " counter:\n" + " http://host/image[000-100:2].img\n" + " A step counter can be omitted.\n" + " If all URIs do not point to the same file, such\n" + " as the second example above, -Z option is\n" + " required.\n" + " Default: false") << endl; +#ifdef ENABLE_MESSAGE_DIGEST + cout << _(" --check-integrity=true|false Check file integrity by validating piece hash.\n" + " This option only affects in BitTorrent downloads\n" + " and Metalink downloads with chunk checksums.\n" + " Use this option to re-download a damaged portion\n" + " of a file.\n" + " You may need to specify --allow-overwrite=true\n" + " if the .aria2 file doesn't exist.\n" + " Default: false") << endl; + cout << _(" --realtime-chunk-checksum=true|false Validate chunk checksum while\n" + " downloading a file in Metalink mode. This option\n" + " on affects Metalink mode with chunk checksums.\n" + " Default: true") << endl; +#endif // ENABLE_MESSAGE_DIGEST + cout << _(" -c, --continue Continue downloading a partially downloaded\n" + " file. Use this option to resume a download\n" + " started by a web browser or another program\n" + " which downloads files sequentially from the\n" + " beginning. Currently this option is only\n" + " applicable to http(s)/ftp downloads.") << endl; + cout << _(" -U, --user-agent=USER_AGENT Set user agent for http(s) downloads.") << endl; + cout << _(" -n, --no-netrc Disables netrc support.") << endl; + cout << _(" -i, --input-file=FILE Downloads URIs found in FILE. You can specify\n" + " multiple URIs for a single entity: separate\n" + " URIs on a single line using the TAB character.\n" + " Reads input from stdin when '-' is specified.") << endl; + cout << _(" -j, --max-concurrent-downloads=N Set maximum number of concurrent downloads.\n" + " It should be used with the -i option.\n" + " Default: 5") << endl; + cout << _(" --load-cookies=FILE Load cookies from FILE. The format of FILE is\n" + " the same used by Netscape and Mozilla.") << endl; +#if defined ENABLE_BITTORRENT || ENABLE_METALINK + cout << _(" -S, --show-files Print file listing of .torrent or .metalink file\n" + " and exit.") << endl; + cout << _(" --select-file=INDEX... Set file to download by specifing its index.\n" + " You can find the file index using the\n" + " --show-files option. Multiple indexes can be\n" + " specified by using ',', for example: \"3,6\".\n" + " You can also use '-' to specify a range: \"1-5\".\n" + " ',' and '-' can be used together.\n" + " When used with the -M option, index may vary\n" + " depending on the query(see --metalink-* options).") << endl; +#endif // ENABLE_BITTORRENT || ENABLE_METALINK +#ifdef ENABLE_BITTORRENT + cout << _(" -T, --torrent-file=TORRENT_FILE The path to the .torrent file.") << endl; + cout << _(" --follow-torrent=true|false Set to false to prevent aria2 from\n" + " entering BitTorrent mode even if the filename of\n" + " the downloaded file ends with .torrent.\n" + " Default: true") << endl; + cout << _(" --direct-file-mapping=true|false Directly read from and write to each file\n" + " mentioned in .torrent file.\n" + " Default: true") << endl; + cout << _(" --listen-port=PORT Set TCP port number for BitTorrent downloads.\n" + " Default: 6881-6999") << endl; + cout << _(" --max-upload-limit=SPEED Set max upload speed in bytes per sec.\n" + " 0 means unrestricted.\n" + " You can append K or M(1K = 1024, 1M = 1024K).\n" + " Default: 0") << endl; + cout << _(" --seed-time=MINUTES Specify seeding time in minutes. Also see the\n" + " --seed-ratio option.") << endl; + cout << _(" --seed-ratio=RATIO Specify share ratio. Seed completed torrents\n" + " until share ratio reaches RATIO. 1.0 is\n" + " encouraged. If --seed-time option is specified\n" + " along with this option, seeding ends when at\n" + " least one of the conditions is satisfied.") << endl; + cout << _(" --peer-id-prefix=PEERI_ID_PREFIX Specify the prefix of peer ID. The peer ID in\n" + " in BitTorrent is 20 byte length. If more than 20\n" + " bytes are specified, only first 20\n" + " bytes are used. If less than 20 bytes are\n" + " specified, the random alphabet characters are\n" + " added to make it's length 20 bytes.\n" + " Default: -aria2-") << endl; +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + cout << _(" -M, --metalink-file=METALINK_FILE The file path to the .metalink file.") << endl; + cout << _(" -C, --metalink-servers=NUM_SERVERS The number of servers to connect to\n" + " simultaneously.\n" + " Default: 5") << endl; + cout << _(" --metalink-version=VERSION The version of the file to download.") << endl; + cout << _(" --metalink-language=LANGUAGE The language of the file to download.") << endl; + cout << _(" --metalink-os=OS The operating system of the file to download.") << endl; + cout << _(" --metalink-location=LOCATION The location of the prefered server.") << endl; + cout << _(" --follow-metalink=true|false Set to false to prevent aria2 from\n" + " entering Metalink mode even if the filename of\n" + " the downloaded file ends with .metalink.\n" + " Default: true") << endl; +#endif // ENABLE_METALINK + cout << _(" -v, --version Print the version number and exit.") << endl; + cout << _(" -h, --help Print this message and exit.") << endl; + cout << endl; + cout << "URL:" << endl; + cout << _(" You can specify multiple URLs. All URLs must point to the same file\n" + " or downloading will fail.") << endl; + cout << endl; + cout << _("Examples:") << endl; + cout << _(" Download a file using 1 connection:") << endl; + cout << " aria2c http://AAA.BBB.CCC/file.zip" << endl; + cout << _(" Download a file using 2 connections:") << endl; + cout << " aria2c -s 2 http://AAA.BBB.CCC/file.zip" << endl; + cout << _(" Download a file using 2 connections, each connects to a different server:") << endl; + cout << " aria2c http://AAA.BBB.CCC/file.zip http://DDD.EEE.FFF/GGG/file.zip" << endl; + cout << _(" You can mix up different protocols:") << endl; + cout << " aria2c http://AAA.BBB.CCC/file.zip ftp://DDD.EEE.FFF/GGG/file.zip" << endl; + cout << _(" Parameterized URI:") << endl; + cout << " aria2c -P http://{server1,server2,server3}/file.iso" << endl; + cout << _(" Parameterized URI. -Z option is required in this case:") << endl; + cout << " aria2c -P -Z http://host/file[001-100:2].img" << endl; +#ifdef ENABLE_BITTORRENT + cout << endl; + cout << _(" Download a torrent:") << endl; + cout << " aria2c -o test.torrent http://AAA.BBB.CCC/file.torrent" << endl; + cout << _(" Download a torrent using a local .torrent file:") << endl; + cout << " aria2c -T test.torrent" << endl; + cout << _(" Download only selected files:") << endl; + cout << " aria2c -T test.torrent dir/file1.zip dir/file2.zip" << endl; + cout << _(" Print file listing of .torrent file:") << endl; + cout << " aria2c -T test.torrent -S" << endl; +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + cout << endl; + cout << _(" Metalink downloading:") << endl; + cout << " aria2c http://AAA.BBB.CCC/file.metalink" << endl; + cout << _(" Download a file using local .metalink file:") << endl; + cout << " aria2c -M test.metalink" << endl; + cout << _(" Metalink downloading with preferences:") << endl; + cout << " aria2c -M test.metalink --metalink-version=1.1.1 --metalink-language=en-US" << endl; + cout << _(" Download only selected files:") << endl; + cout << " aria2c -M test.metalink --metalink-language=en-US dir/file1.zip dir/file2.zip" << endl; + cout << _(" Download only selected files using index:") << endl; + cout << " aria2c -M test.metalink --metalink-language=en-US --select-file 1,3-5" << endl; + cout << _(" Print file listing of .metalink file:") << endl; + cout << " aria2c -M test.metalink -S --metalink-language=en-US" << endl; +#endif // ENABLE_METALINK + cout << endl; + printf(_("Report bugs to %s"), ""); + cout << endl; +} diff --git a/test/AlphaNumberDecoratorTest.cc b/test/AlphaNumberDecoratorTest.cc index 593ebac2..5fd2501b 100644 --- a/test/AlphaNumberDecoratorTest.cc +++ b/test/AlphaNumberDecoratorTest.cc @@ -43,10 +43,10 @@ void AlphaNumberDecoratorTest::testDecorate_minus() try { AlphaNumberDecorator(1, true).decorate(-1); CPPUNIT_FAIL("exception must be thrown."); - } catch(FatalException* e) { + } catch(DlAbortEx* e) { cerr << e->getMsg() << endl; delete e; } catch(...) { - CPPUNIT_FAIL("FatalException must be thrown."); + CPPUNIT_FAIL("DlAbortEx must be thrown."); } } diff --git a/test/BtCancelMessageTest.cc b/test/BtCancelMessageTest.cc index 69d4fee2..58f4be7b 100644 --- a/test/BtCancelMessageTest.cc +++ b/test/BtCancelMessageTest.cc @@ -22,7 +22,7 @@ public: MockBtContextHandle btContext; void setUp() { - BtRegistry::clear(); + BtRegistry::unregisterAll(); peer = new Peer("host", 6969, 16*1024, 256*1024); btContext = new MockBtContext(); btContext->setInfoHash((const unsigned char*)"12345678901234567890"); diff --git a/test/BtChokeMessageTest.cc b/test/BtChokeMessageTest.cc index 4d1357f0..1917709e 100644 --- a/test/BtChokeMessageTest.cc +++ b/test/BtChokeMessageTest.cc @@ -25,7 +25,7 @@ public: MockBtContextHandle btContext; void setUp() { - BtRegistry::clear(); + BtRegistry::unregisterAll(); peer = new Peer("host", 6969, 16*1024, 256*1024); btContext = new MockBtContext(); btContext->setInfoHash((const unsigned char*)"12345678901234567890"); diff --git a/test/BtDependencyTest.cc b/test/BtDependencyTest.cc new file mode 100644 index 00000000..174ce4fb --- /dev/null +++ b/test/BtDependencyTest.cc @@ -0,0 +1,117 @@ +#include "BtDependency.h" +#include "SingleFileDownloadContext.h" +#include "DefaultPieceStorage.h" +#include "BtContext.h" +#include "RequestGroup.h" +#include "Option.h" +#include "Exception.h" +#include "SegmentMan.h" +#include + +class BtDependencyTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtDependencyTest); + CPPUNIT_TEST(testResolve); + CPPUNIT_TEST(testResolve_loadError); + CPPUNIT_TEST(testResolve_dependeeFailure); + CPPUNIT_TEST(testResolve_dependeeInProgress); + CPPUNIT_TEST_SUITE_END(); + + RequestGroupHandle createDependant(const Option* option) + { + RequestGroupHandle dependant = new RequestGroup(option, Strings()); + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(0, 0, ""); + dctx->setDir("/tmp"); + dependant->setDownloadContext(dctx); + return dependant; + } + + RequestGroupHandle createDependee(const Option* option, const string& torrentFile, int64_t length) + { + RequestGroupHandle dependee = new RequestGroup(option, Strings()); + SingleFileDownloadContextHandle dctx = + new SingleFileDownloadContext(1024*1024, length, torrentFile); + dctx->setDir("."); + dependee->setDownloadContext(dctx); + DefaultPieceStorageHandle ps = new DefaultPieceStorage(dctx, option); + dependee->setPieceStorage(ps); + ps->initStorage(); + dependee->initSegmentMan(); + return dependee; + } + +public: + void setUp() {} + + void testResolve(); + void testResolve_loadError(); + void testResolve_dependeeFailure(); + void testResolve_dependeeInProgress(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION( BtDependencyTest ); + +void BtDependencyTest::testResolve() +{ + string filename = "test.torrent"; + Option option; + RequestGroupHandle dependant = createDependant(&option); + RequestGroupHandle dependee = createDependee(&option, filename, File(filename).size()); + dependee->getPieceStorage()->markAllPiecesDone(); + + BtDependency dep(dependant, dependee, &option); + CPPUNIT_ASSERT(dep.resolve()); + + BtContextHandle btContext = dependant->getDownloadContext(); + CPPUNIT_ASSERT(!btContext.isNull()); + CPPUNIT_ASSERT_EQUAL(string("/tmp/aria2-test"), btContext->getActualBasePath()); +} + +void BtDependencyTest::testResolve_loadError() +{ + try { + Option option; + RequestGroupHandle dependant = createDependant(&option); + RequestGroupHandle dependee = createDependee(&option, "notExist", 40); + dependee->getPieceStorage()->markAllPiecesDone(); + + BtDependency dep(dependant, dependee, &option); + CPPUNIT_ASSERT(dep.resolve()); + + SingleFileDownloadContextHandle dctx = dependant->getDownloadContext(); + CPPUNIT_ASSERT(!dctx.isNull()); + CPPUNIT_ASSERT_EQUAL(string("/tmp/index.html"), dctx->getActualBasePath()); + } catch(Exception* e) { + cerr << e->getMsg() << endl; + delete e; + CPPUNIT_FAIL("an exception was thrown."); + } +} + +void BtDependencyTest::testResolve_dependeeFailure() +{ + Option option; + RequestGroupHandle dependant = createDependant(&option); + RequestGroupHandle dependee = createDependee(&option, "notExist", 40); + + BtDependency dep(dependant, dependee, &option); + CPPUNIT_ASSERT(dep.resolve()); + + SingleFileDownloadContextHandle dctx = dependant->getDownloadContext(); + CPPUNIT_ASSERT(!dctx.isNull()); + CPPUNIT_ASSERT_EQUAL(string("/tmp/index.html"), dctx->getActualBasePath()); +} + +void BtDependencyTest::testResolve_dependeeInProgress() +{ + string filename = "test.torrent"; + Option option; + RequestGroupHandle dependant = createDependant(&option); + RequestGroupHandle dependee = createDependee(&option, filename, File(filename).size()); + dependee->increaseNumCommand(); + + BtDependency dep(dependant, dependee, &option); + CPPUNIT_ASSERT(!dep.resolve()); +} diff --git a/test/BtPieceMessageTest.cc b/test/BtPieceMessageTest.cc index f151dda1..22f78b1b 100644 --- a/test/BtPieceMessageTest.cc +++ b/test/BtPieceMessageTest.cc @@ -73,7 +73,7 @@ public: BtPieceMessageHandle msg; void setUp() { - BtRegistry::clear(); + BtRegistry::unregisterAll(); MockBtContextHandle btContext; btContext->setInfoHash((const unsigned char*)"12345678901234567890"); diff --git a/test/BtPostDownloadHandlerTest.cc b/test/BtPostDownloadHandlerTest.cc new file mode 100644 index 00000000..b4228ee2 --- /dev/null +++ b/test/BtPostDownloadHandlerTest.cc @@ -0,0 +1,42 @@ +#include "BtPostDownloadHandler.h" +#include "BtContext.h" +#include "RequestGroup.h" +#include "Option.h" +#include + +class BtPostDownloadHandlerTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtPostDownloadHandlerTest); + CPPUNIT_TEST(testCanHandle); + CPPUNIT_TEST(testGetNextRequestGroups); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() {} + + void testCanHandle(); + void testGetNextRequestGroups(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION( BtPostDownloadHandlerTest ); + +void BtPostDownloadHandlerTest::testCanHandle() +{ + Option op; + BtPostDownloadHandler handler(&op); + CPPUNIT_ASSERT(!handler.canHandle(".torrent!!")); + CPPUNIT_ASSERT(handler.canHandle(".torrent")); +} + +void BtPostDownloadHandlerTest::testGetNextRequestGroups() +{ + Option op; + BtPostDownloadHandler handler(&op); + RequestGroups groups = handler.getNextRequestGroups("test.torrent"); + CPPUNIT_ASSERT_EQUAL((size_t)1, groups.size()); + BtContextHandle btctx = groups.front()->getDownloadContext(); + CPPUNIT_ASSERT(!btctx.isNull()); + CPPUNIT_ASSERT_EQUAL(string("aria2-test"), btctx->getName()); +} diff --git a/test/BtRegistryTest.cc b/test/BtRegistryTest.cc index 104bcd70..7cabb0dc 100644 --- a/test/BtRegistryTest.cc +++ b/test/BtRegistryTest.cc @@ -1,5 +1,6 @@ #include "BtRegistry.h" #include "Exception.h" +#include "MockBtContext.h" #include "MockPeerStorage.h" #include "MockPieceStorage.h" #include "MockBtAnnounce.h" @@ -11,6 +12,7 @@ using namespace std; class BtRegistryTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BtRegistryTest); + CPPUNIT_TEST(testGetBtContext); CPPUNIT_TEST(testGetPeerStorage); CPPUNIT_TEST(testGetPieceStorage); CPPUNIT_TEST(testGetBtRuntime); @@ -21,9 +23,17 @@ class BtRegistryTest:public CppUnit::TestFixture { private: public: - void setUp() { + void setUp() + { + BtRegistry::unregisterAll(); } + void tearDown() + { + BtRegistry::unregisterAll(); + } + + void testGetBtContext(); void testGetPeerStorage(); void testGetPieceStorage(); void testGetBtRuntime(); @@ -35,13 +45,21 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION( BtRegistryTest ); +void BtRegistryTest::testGetBtContext() +{ + CPPUNIT_ASSERT(BtRegistry::getBtContext("test").isNull()); + BtContextHandle btContext = new MockBtContext(); + BtRegistry::registerBtContext("test", btContext); + CPPUNIT_ASSERT_EQUAL(btContext.get(), + BtRegistry::getBtContext("test").get()); +} + void BtRegistryTest::testGetPeerStorage() { CPPUNIT_ASSERT(!BtRegistry::getPeerStorage("test").get()); PeerStorageHandle peerStorage(new MockPeerStorage()); - CPPUNIT_ASSERT(BtRegistry::registerPeerStorage("test", - peerStorage)); + BtRegistry::registerPeerStorage("test", peerStorage); CPPUNIT_ASSERT_EQUAL(peerStorage.get(), BtRegistry::getPeerStorage("test").get()); } @@ -51,8 +69,7 @@ void BtRegistryTest::testGetPieceStorage() { PieceStorageHandle pieceStorage(new MockPieceStorage()); - CPPUNIT_ASSERT(BtRegistry::registerPieceStorage("test", - pieceStorage)); + BtRegistry::registerPieceStorage("test", pieceStorage); CPPUNIT_ASSERT_EQUAL(pieceStorage.get(), BtRegistry::getPieceStorage("test").get()); } @@ -62,7 +79,7 @@ void BtRegistryTest::testGetBtRuntime() { BtRuntimeHandle runtime; - CPPUNIT_ASSERT(BtRegistry::registerBtRuntime("test", runtime)); + BtRegistry::registerBtRuntime("test", runtime); CPPUNIT_ASSERT_EQUAL(runtime.get(), BtRegistry::getBtRuntime("test").get()); } @@ -72,7 +89,7 @@ void BtRegistryTest::testGetBtAnnounce() { BtAnnounceHandle btAnnounce(new MockBtAnnounce()); - CPPUNIT_ASSERT(BtRegistry::registerBtAnnounce("test", btAnnounce)); + BtRegistry::registerBtAnnounce("test", btAnnounce); CPPUNIT_ASSERT_EQUAL(btAnnounce.get(), BtRegistry::getBtAnnounce("test").get()); } @@ -82,8 +99,7 @@ void BtRegistryTest::testGetBtProgressInfoFile() { BtProgressInfoFileHandle btProgressInfoFile(new MockBtProgressInfoFile()); - CPPUNIT_ASSERT(BtRegistry::registerBtProgressInfoFile("test", - btProgressInfoFile)); + BtRegistry::registerBtProgressInfoFile("test", btProgressInfoFile); CPPUNIT_ASSERT_EQUAL(btProgressInfoFile.get(), BtRegistry::getBtProgressInfoFile("test").get()); } diff --git a/test/BtRejectMessageTest.cc b/test/BtRejectMessageTest.cc index 145b47c3..ed46ea6f 100644 --- a/test/BtRejectMessageTest.cc +++ b/test/BtRejectMessageTest.cc @@ -65,7 +65,7 @@ public: BtRejectMessageTest():peer(0), dispatcher(0), msg(0) {} void setUp() { - BtRegistry::clear(); + BtRegistry::unregisterAll(); peer = new Peer("host", 6969, 16*1024, 256*1024); MockBtContextHandle btContext = new MockBtContext(); diff --git a/test/BtRequestMessageTest.cc b/test/BtRequestMessageTest.cc index 3242ad37..06925f5d 100644 --- a/test/BtRequestMessageTest.cc +++ b/test/BtRequestMessageTest.cc @@ -86,7 +86,7 @@ public: BtRequestMessageTest():peer(0), dispatcher(0), msg(0) {} void setUp() { - BtRegistry::clear(); + BtRegistry::unregisterAll(); MockBtContextHandle btContext = new MockBtContext(); btContext->setInfoHash((const unsigned char*)"12345678901234567890"); diff --git a/test/ByteArrayDiskWriterTest.cc b/test/ByteArrayDiskWriterTest.cc index ff90db61..18ea5e0d 100644 --- a/test/ByteArrayDiskWriterTest.cc +++ b/test/ByteArrayDiskWriterTest.cc @@ -27,10 +27,10 @@ void ByteArrayDiskWriterTest::testWriteAndRead() { ByteArrayDiskWriter bw; string msg1 = "Hello world!"; - bw.writeData(msg1.c_str(), msg1.size(), 0); + bw.writeData((const unsigned char*)msg1.c_str(), msg1.size(), 0); char buf[100]; - int32_t c = bw.readData(buf, sizeof(buf), 0); + int32_t c = bw.readData((unsigned char*)buf, sizeof(buf), 0); buf[c] = '\0'; CPPUNIT_ASSERT_EQUAL(msg1, string(buf)); @@ -38,7 +38,7 @@ void ByteArrayDiskWriterTest::testWriteAndRead() { // second call memset(buf, '\0', sizeof(buf)); - c = bw.readData(buf, sizeof(buf), 0); + c = bw.readData((unsigned char*)buf, sizeof(buf), 0); buf[c] = '\0'; CPPUNIT_ASSERT_EQUAL(msg1, string(buf)); @@ -48,10 +48,10 @@ void ByteArrayDiskWriterTest::testWriteAndRead2() { ByteArrayDiskWriter bw; string msg1 = "Hello world!"; - bw.writeData(msg1.c_str(), msg1.size(), 16); + bw.writeData((const unsigned char*)msg1.c_str(), msg1.size(), 16); char buf[100]; - int32_t c = bw.readData(buf, sizeof(buf), 16); + int32_t c = bw.readData((unsigned char*)buf, sizeof(buf), 16); buf[c] = '\0'; CPPUNIT_ASSERT_EQUAL(msg1, string(buf)); @@ -59,7 +59,7 @@ void ByteArrayDiskWriterTest::testWriteAndRead2() { // second call memset(buf, '\0', sizeof(buf)); - c = bw.readData(buf, sizeof(buf), 16); + c = bw.readData((unsigned char*)buf, sizeof(buf), 16); buf[c] = '\0'; CPPUNIT_ASSERT_EQUAL(msg1, string(buf)); diff --git a/test/DefaultBtContextTest.cc b/test/DefaultBtContextTest.cc index 1e563b63..78e1ea85 100644 --- a/test/DefaultBtContextTest.cc +++ b/test/DefaultBtContextTest.cc @@ -1,6 +1,7 @@ #include "DefaultBtContext.h" #include "Util.h" #include "Exception.h" +#include "AnnounceTier.h" #include using namespace std; diff --git a/test/DefaultBtMessageDispatcherTest.cc b/test/DefaultBtMessageDispatcherTest.cc index 893d1848..f21ae2e5 100644 --- a/test/DefaultBtMessageDispatcherTest.cc +++ b/test/DefaultBtMessageDispatcherTest.cc @@ -134,7 +134,7 @@ public: btContext->getTotalLength()); peerStorage = new MockPeerStorage(); pieceStorage = new MockPieceStorage(); - BtRegistry::clear(); + BtRegistry::unregisterAll(); BtRegistry::registerPeerStorage(btContext->getInfoHashAsString(), peerStorage); BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), @@ -281,8 +281,8 @@ void DefaultBtMessageDispatcherTest::testCheckRequestSlotAndDoNecessaryThing() { SharedHandle pieceStorage = new MockPieceStorage2(); pieceStorage->setPiece(piece); - CPPUNIT_ASSERT(BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), - pieceStorage)); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage); btMessageDispatcher = new DefaultBtMessageDispatcher(); btMessageDispatcher->setCuid(1); @@ -308,8 +308,8 @@ void DefaultBtMessageDispatcherTest::testCheckRequestSlotAndDoNecessaryThing_tim SharedHandle pieceStorage = new MockPieceStorage2(); pieceStorage->setPiece(piece); - CPPUNIT_ASSERT(BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), - pieceStorage)); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage); btMessageDispatcher = new DefaultBtMessageDispatcher(); btMessageDispatcher->setCuid(1); @@ -337,8 +337,8 @@ void DefaultBtMessageDispatcherTest::testCheckRequestSlotAndDoNecessaryThing_com SharedHandle pieceStorage = new MockPieceStorage2(); pieceStorage->setPiece(piece); - CPPUNIT_ASSERT(BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), - pieceStorage)); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage); btMessageDispatcher = new DefaultBtMessageDispatcher(); diff --git a/test/DefaultBtProgressInfoFileTest.cc b/test/DefaultBtProgressInfoFileTest.cc index 873a0e52..f18f64fb 100644 --- a/test/DefaultBtProgressInfoFileTest.cc +++ b/test/DefaultBtProgressInfoFileTest.cc @@ -1,13 +1,18 @@ -#include #include "DefaultBtProgressInfoFile.h" -#include "DefaultBtContext.h" #include "Option.h" #include "Util.h" #include "Exception.h" #include "MockBtContext.h" #include "MockPeerStorage.h" #include "MockPieceStorage.h" +#include "BtRuntime.h" +#include "BtRegistry.h" #include "prefs.h" +#include "SingleFileDownloadContext.h" +#include "Piece.h" +#include "AnnounceTier.h" +#include +#include #include using namespace std; @@ -16,79 +21,341 @@ class DefaultBtProgressInfoFileTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(DefaultBtProgressInfoFileTest); CPPUNIT_TEST(testSave); + CPPUNIT_TEST(testSave_nonBt); + CPPUNIT_TEST(testLoad); + CPPUNIT_TEST(testLoad_nonBt); CPPUNIT_TEST_SUITE_END(); private: - BtContextHandle btContext; - Option* option; + MockBtContextHandle _btContext; + MockPieceStorageHandle _pieceStorage; + SharedHandle