From 90471d68050ebd05439435330e4d0dbb19c6fd1e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> Date: Tue, 23 Jun 2009 15:35:45 +0000 Subject: [PATCH] 2009-06-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> Added experimental support of WEB-Seeding for multi-file torrent. Due to fundamental changes in file handling in HTTP/FTP code, many functions are not working: PeerStat, ServerHost, proxy..etc * src/AbstractCommand.cc * src/AbstractCommand.h * src/BitfieldMan.cc * src/BitfieldMan.h * src/CreateRequestCommand.cc * src/CreateRequestCommand.h * src/DefaultPieceStorage.cc * src/DefaultPieceStorage.h * src/DownloadCommand.cc * src/DownloadCommand.h * src/DownloadContext.cc * src/DownloadContext.h * src/FileEntry.cc * src/FileEntry.h * src/FtpDownloadCommand.cc * src/FtpDownloadCommand.h * src/FtpFinishDownloadCommand.cc * src/FtpFinishDownloadCommand.h * src/FtpInitiateConnectionCommand.cc * src/FtpInitiateConnectionCommand.h * src/FtpNegotiationCommand.cc * src/FtpNegotiationCommand.h * src/FtpTunnelResponseCommand.cc * src/HttpDownloadCommand.cc * src/HttpDownloadCommand.h * src/HttpInitiateConnectionCommand.cc * src/HttpInitiateConnectionCommand.h * src/HttpProxyResponseCommand.cc * src/HttpRequest.cc * src/HttpRequest.h * src/HttpRequestCommand.cc * src/HttpRequestCommand.h * src/HttpResponseCommand.cc * src/HttpResponseCommand.h * src/HttpSkipResponseCommand.cc * src/HttpSkipResponseCommand.h * src/InitiateConnectionCommand.cc * src/InitiateConnectionCommand.h * src/InitiateConnectionCommandFactory.cc * src/InitiateConnectionCommandFactory.h * src/Makefile.am * src/PieceStorage.h * src/RequestGroup.cc * src/RequestGroup.h * src/RequestGroupMan.cc * src/SegmentMan.cc * src/SegmentMan.h * src/SingleFileDownloadContext.h * src/StreamFileAllocationEntry.cc * src/TrackerWatcherCommand.cc * src/UnknownLengthPieceStorage.cc * src/UnknownLengthPieceStorage.h * src/array_fun.h * src/bitfield.h * src/download_helper.cc * test/DownloadContextTest.cc * test/Makefile.am * test/MockDownloadContext.h --- ChangeLog | 64 +++++++++++++++++++ src/AbstractCommand.cc | 84 ++++++++++++++++++++---- src/AbstractCommand.h | 7 ++ src/BitfieldMan.cc | 65 +++++++++++++++---- src/BitfieldMan.h | 13 +++- src/CreateRequestCommand.cc | 85 +++++++++++++++++++++++++ src/CreateRequestCommand.h | 53 +++++++++++++++ src/DefaultPieceStorage.cc | 5 +- src/DefaultPieceStorage.h | 3 +- src/DownloadCommand.cc | 70 ++++++++++++-------- src/DownloadCommand.h | 1 + src/DownloadContext.cc | 24 +++++++ src/DownloadContext.h | 4 ++ src/FileEntry.cc | 67 ++++++++++++++++++- src/FileEntry.h | 47 ++++++++++++++ src/FtpDownloadCommand.cc | 8 ++- src/FtpDownloadCommand.h | 1 + src/FtpFinishDownloadCommand.cc | 3 +- src/FtpFinishDownloadCommand.h | 1 + src/FtpInitiateConnectionCommand.cc | 18 ++++-- src/FtpInitiateConnectionCommand.h | 1 + src/FtpNegotiationCommand.cc | 24 ++++--- src/FtpNegotiationCommand.h | 1 + src/FtpTunnelResponseCommand.cc | 3 +- src/HttpDownloadCommand.cc | 9 +-- src/HttpDownloadCommand.h | 1 + src/HttpInitiateConnectionCommand.cc | 15 +++-- src/HttpInitiateConnectionCommand.h | 1 + src/HttpProxyResponseCommand.cc | 3 +- src/HttpRequest.cc | 4 +- src/HttpRequest.h | 13 ++++ src/HttpRequestCommand.cc | 18 ++++-- src/HttpRequestCommand.h | 1 + src/HttpResponseCommand.cc | 28 ++++---- src/HttpResponseCommand.h | 1 + src/HttpSkipResponseCommand.cc | 3 +- src/HttpSkipResponseCommand.h | 1 + src/InitiateConnectionCommand.cc | 7 +- src/InitiateConnectionCommand.h | 1 + src/InitiateConnectionCommandFactory.cc | 14 +++- src/InitiateConnectionCommandFactory.h | 2 + src/Makefile.am | 3 +- src/Makefile.in | 25 ++++---- src/PieceStorage.h | 4 +- src/RequestGroup.cc | 68 ++++++++++++-------- src/RequestGroup.h | 11 +++- src/RequestGroupMan.cc | 1 + src/SegmentMan.cc | 44 ++++++++++++- src/SegmentMan.h | 14 ++++ src/SingleFileDownloadContext.h | 6 +- src/StreamFileAllocationEntry.cc | 12 +--- src/TrackerWatcherCommand.cc | 1 + src/UnknownLengthPieceStorage.cc | 5 +- src/UnknownLengthPieceStorage.h | 3 +- src/array_fun.h | 14 ++++ src/bitfield.h | 3 +- src/download_helper.cc | 1 + test/DownloadContextTest.cc | 44 +++++++++++++ test/Makefile.am | 4 +- test/Makefile.in | 14 ++-- test/MockDownloadContext.h | 67 +++++++++++++++++++ 61 files changed, 935 insertions(+), 183 deletions(-) create mode 100644 src/CreateRequestCommand.cc create mode 100644 src/CreateRequestCommand.h create mode 100644 test/DownloadContextTest.cc create mode 100644 test/MockDownloadContext.h diff --git a/ChangeLog b/ChangeLog index 0d459bcc..708dd7e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,67 @@ +2009-06-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> + + Added experimental support of WEB-Seeding for multi-file torrent. + Due to fundamental changes in file handling in HTTP/FTP code, many + functions are not working: PeerStat, ServerHost, proxy..etc + * src/AbstractCommand.cc + * src/AbstractCommand.h + * src/BitfieldMan.cc + * src/BitfieldMan.h + * src/CreateRequestCommand.cc + * src/CreateRequestCommand.h + * src/DefaultPieceStorage.cc + * src/DefaultPieceStorage.h + * src/DownloadCommand.cc + * src/DownloadCommand.h + * src/DownloadContext.cc + * src/DownloadContext.h + * src/FileEntry.cc + * src/FileEntry.h + * src/FtpDownloadCommand.cc + * src/FtpDownloadCommand.h + * src/FtpFinishDownloadCommand.cc + * src/FtpFinishDownloadCommand.h + * src/FtpInitiateConnectionCommand.cc + * src/FtpInitiateConnectionCommand.h + * src/FtpNegotiationCommand.cc + * src/FtpNegotiationCommand.h + * src/FtpTunnelResponseCommand.cc + * src/HttpDownloadCommand.cc + * src/HttpDownloadCommand.h + * src/HttpInitiateConnectionCommand.cc + * src/HttpInitiateConnectionCommand.h + * src/HttpProxyResponseCommand.cc + * src/HttpRequest.cc + * src/HttpRequest.h + * src/HttpRequestCommand.cc + * src/HttpRequestCommand.h + * src/HttpResponseCommand.cc + * src/HttpResponseCommand.h + * src/HttpSkipResponseCommand.cc + * src/HttpSkipResponseCommand.h + * src/InitiateConnectionCommand.cc + * src/InitiateConnectionCommand.h + * src/InitiateConnectionCommandFactory.cc + * src/InitiateConnectionCommandFactory.h + * src/Makefile.am + * src/PieceStorage.h + * src/RequestGroup.cc + * src/RequestGroup.h + * src/RequestGroupMan.cc + * src/SegmentMan.cc + * src/SegmentMan.h + * src/SingleFileDownloadContext.h + * src/StreamFileAllocationEntry.cc + * src/TrackerWatcherCommand.cc + * src/UnknownLengthPieceStorage.cc + * src/UnknownLengthPieceStorage.h + * src/array_fun.h + * src/bitfield.h + * src/download_helper.cc + * test/DownloadContextTest.cc + * test/Makefile.am + * test/MockDownloadContext.h + 2009-06-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> Added tellWaiting XML-RPC method. diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index 39aa7a9e..b1004a48 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -47,7 +47,7 @@ #include "DlAbortEx.h" #include "DlRetryEx.h" #include "DownloadFailureException.h" -#include "InitiateConnectionCommandFactory.h" +#include "CreateRequestCommand.h" #include "SleepCommand.h" #ifdef ENABLE_ASYNC_DNS #include "AsyncNameResolver.h" @@ -62,9 +62,12 @@ #include "RequestGroupMan.h" #include "A2STR.h" #include "Util.h" +#include "LogFactory.h" +#include "DownloadContext.h" namespace aria2 { +// TODO1.5 Remove this AbstractCommand::AbstractCommand(int32_t cuid, const SharedHandle<Request>& req, RequestGroup* requestGroup, @@ -83,6 +86,25 @@ AbstractCommand::AbstractCommand(int32_t cuid, _requestGroup->increaseNumCommand(); } +AbstractCommand::AbstractCommand(int32_t cuid, + const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, + RequestGroup* requestGroup, + DownloadEngine* e, + const SocketHandle& s): + Command(cuid), _requestGroup(requestGroup), + req(req), _fileEntry(fileEntry), e(e), socket(s), + checkSocketIsReadable(false), checkSocketIsWritable(false), + nameResolverCheck(false) +{ + if(!socket.isNull() && socket->isOpen()) { + setReadCheckSocket(socket); + } + timeout = _requestGroup->getTimeout(); + _requestGroup->increaseStreamConnection(); + _requestGroup->increaseNumCommand(); +} + AbstractCommand::~AbstractCommand() { disableReadCheckSocket(); disableWriteCheckSocket(); @@ -125,7 +147,8 @@ bool AbstractCommand::execute() { if(!_requestGroup->getPieceStorage().isNull()) { _segments.clear(); _requestGroup->getSegmentMan()->getInFlightSegment(_segments, cuid); - while(_segments.size() < req->getMaxPipelinedRequest()) { + size_t maxSegments = req.isNull()?1:req->getMaxPipelinedRequest(); + while(_segments.size() < maxSegments) { SegmentHandle segment = _requestGroup->getSegmentMan()->getSegment(cuid); if(segment.isNull()) { break; @@ -135,7 +158,7 @@ bool AbstractCommand::execute() { if(_segments.empty()) { // TODO socket could be pooled here if pipelining is enabled... logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid); - return prepareForRetry(1); + return true; } } return executeInternal(); @@ -146,6 +169,7 @@ bool AbstractCommand::execute() { } else { if(checkPoint.elapsed(timeout)) { // timeout triggers ServerStat error state. + SharedHandle<ServerStat> ss = e->_requestGroupMan->getOrCreateServerStat(req->getHost(), req->getProtocol()); @@ -157,13 +181,18 @@ bool AbstractCommand::execute() { return false; } } catch(DlAbortEx& err) { - logger->error(MSG_DOWNLOAD_ABORTED, - DL_ABORT_EX2(StringFormat - ("URI=%s", req->getCurrentUrl().c_str()).str(),err), - cuid, req->getUrl().c_str()); - _requestGroup->addURIResult(req->getUrl(), err.getCode()); + if(req.isNull()) { + logger->debug(EX_EXCEPTION_CAUGHT, err); + } else { + logger->error(MSG_DOWNLOAD_ABORTED, + DL_ABORT_EX2(StringFormat + ("URI=%s", req->getCurrentUrl().c_str()).str(),err), + cuid, req->getUrl().c_str()); + _requestGroup->addURIResult(req->getUrl(), err.getCode()); + } onAbort(); - req->resetUrl(); + // TODO Do we need this? + //req->resetUrl(); tryReserved(); return true; } catch(DlRetryEx& err) { @@ -202,6 +231,16 @@ bool AbstractCommand::execute() { void AbstractCommand::tryReserved() { _requestGroup->removeServerHost(cuid); + if(_requestGroup->getDownloadContext()->getFileMode() == DownloadContext::SINGLE) { + const SharedHandle<FileEntry>& entry = + _requestGroup->getDownloadContext()->getFileEntries().front(); + // Don't create new command if currently file length is unknown + // and there are no URI left. Because file length is unknown, we + // can assume that there are no in-flight request object. + if(entry->getLength() == 0 && entry->getRemainingUris().size() == 0) { + return; + } + } Commands commands; _requestGroup->createNextCommand(commands, e, 1); e->setNoWait(true); @@ -212,7 +251,18 @@ bool AbstractCommand::prepareForRetry(time_t wait) { if(!_requestGroup->getPieceStorage().isNull()) { _requestGroup->getSegmentMan()->cancelSegment(cuid); } - Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, _requestGroup, e); + if(!req.isNull()) { + _fileEntry->poolRequest(req); + } + if(!_segments.empty()) { + // TODO1.5 subtract 1 from getPositionToWrite() + SharedHandle<FileEntry> fileEntry = _requestGroup->getDownloadContext()->findFileEntryByOffset(_segments.front()->getPositionToWrite()-1); + logger->debug("CUID#%d - Pooling request URI=%s", + cuid, req->getUrl().c_str()); + _requestGroup->getSegmentMan()->recognizeSegmentFor(_fileEntry); + } + + Command* command = new CreateRequestCommand(cuid, _requestGroup, e); if(wait == 0) { e->setNoWait(true); e->commands.push_back(command); @@ -225,16 +275,22 @@ bool AbstractCommand::prepareForRetry(time_t wait) { } void AbstractCommand::onAbort() { - // TODO This might be a problem if the failure is caused by proxy. - e->_requestGroupMan->getOrCreateServerStat(req->getHost(), - req->getProtocol())->setError(); + if(!req.isNull()) { + logger->debug(req->getCurrentUrl().c_str()); + // TODO This might be a problem if the failure is caused by proxy. + e->_requestGroupMan->getOrCreateServerStat(req->getHost(), + req->getProtocol())->setError(); + _requestGroup->removeIdenticalURI(req->getUrl()); + _fileEntry->removeRequest(req); + } logger->debug(MSG_UNREGISTER_CUID, cuid); //_segmentMan->unregisterId(cuid); if(!_requestGroup->getPieceStorage().isNull()) { _requestGroup->getSegmentMan()->cancelSegment(cuid); } - _requestGroup->removeIdenticalURI(req->getUrl()); + // TODO1.5 Should be moved to FileEntry + // _requestGroup->removeIdenticalURI(req->getUrl()); } void AbstractCommand::disableReadCheckSocket() { diff --git a/src/AbstractCommand.h b/src/AbstractCommand.h index fa3781f0..ba7a7aa4 100644 --- a/src/AbstractCommand.h +++ b/src/AbstractCommand.h @@ -38,6 +38,7 @@ #include "Command.h" #include "SharedHandle.h" #include "TimeA2.h" +#include "FileEntry.h" namespace aria2 { @@ -59,6 +60,7 @@ private: protected: RequestGroup* _requestGroup; SharedHandle<Request> req; + SharedHandle<FileEntry> _fileEntry; DownloadEngine* e; SharedHandle<SocketCore> socket; std::deque<SharedHandle<Segment> > _segments; @@ -140,6 +142,11 @@ public: RequestGroup* requestGroup, DownloadEngine* e, const SharedHandle<SocketCore>& s = SharedHandle<SocketCore>()); + AbstractCommand(int32_t cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, + RequestGroup* requestGroup, DownloadEngine* e, + const SharedHandle<SocketCore>& s = SharedHandle<SocketCore>()); + virtual ~AbstractCommand(); bool execute(); }; diff --git a/src/BitfieldMan.cc b/src/BitfieldMan.cc index 1fbfcb8b..2569c691 100644 --- a/src/BitfieldMan.cc +++ b/src/BitfieldMan.cc @@ -308,9 +308,10 @@ bool BitfieldMan::getMissingUnusedIndex(size_t& index) const } } -size_t BitfieldMan::getStartIndex(size_t index) const { - while(index < blocks && (isUseBitSet(index) || isBitSet(index))) { - index++; +template<typename Array> +static size_t getStartIndex(size_t index, const Array& bitfield, const unsigned char* useBitfield, size_t blocks) { + while(index < blocks && (bitfield::test(bitfield, blocks, index) || bitfield::test(useBitfield, blocks, index))) { + ++index; } if(blocks <= index) { return blocks; @@ -319,24 +320,33 @@ size_t BitfieldMan::getStartIndex(size_t index) const { } } -size_t BitfieldMan::getEndIndex(size_t index) const { - while(index < blocks && (!isUseBitSet(index) && !isBitSet(index))) { - index++; +template<typename Array> +static size_t getEndIndex(size_t index, const Array& bitfield, const unsigned char* useBitfield, size_t blocks) { + while(index < blocks && (!bitfield::test(bitfield, blocks, index) && !bitfield::test(useBitfield, blocks, index))) { + ++index; } return index; } -bool BitfieldMan::getSparseMissingUnusedIndex(size_t& index) const { - Range maxRange; - Range currentRange; +template<typename Array> +static bool getSparseMissingUnusedIndex +(size_t& index, + const Array& bitfield, + const unsigned char* useBitfield, + size_t blocks) +{ + BitfieldMan::Range maxRange; + BitfieldMan::Range currentRange; { size_t nextIndex = 0; while(nextIndex < blocks) { - currentRange.startIndex = getStartIndex(nextIndex); + currentRange.startIndex = + getStartIndex(nextIndex, bitfield, useBitfield, blocks); if(currentRange.startIndex == blocks) { break; } - currentRange.endIndex = getEndIndex(currentRange.startIndex); + currentRange.endIndex = + getEndIndex(currentRange.startIndex, bitfield, useBitfield, blocks); if(maxRange < currentRange) { maxRange = currentRange; } @@ -346,7 +356,7 @@ bool BitfieldMan::getSparseMissingUnusedIndex(size_t& index) const { if(maxRange.getSize()) { if(maxRange.startIndex == 0) { index = 0; - } else if(isUseBitSet(maxRange.startIndex-1)) { + } else if(bitfield::test(useBitfield, blocks, maxRange.startIndex-1)) { index = maxRange.getMidIndex(); } else { index = maxRange.startIndex; @@ -357,6 +367,22 @@ bool BitfieldMan::getSparseMissingUnusedIndex(size_t& index) const { } } +bool BitfieldMan::getSparseMissingUnusedIndex +(size_t& index, + const unsigned char* ignoreBitfield, + size_t ignoreBitfieldLength) const +{ + if(filterEnabled) { + return aria2::getSparseMissingUnusedIndex + (index, array(ignoreBitfield)|~array(filterBitfield)|array(bitfield), + useBitfield, blocks); + } else { + return aria2::getSparseMissingUnusedIndex + (index, array(ignoreBitfield)|array(bitfield), + useBitfield, blocks); + } +} + template<typename Array> static bool copyBitfield(unsigned char* dst, const Array& src, size_t blocks) { @@ -571,6 +597,21 @@ void BitfieldMan::addFilter(uint64_t offset, uint64_t length) { updateCache(); } +void BitfieldMan::removeFilter(uint64_t offset, uint64_t length) { + if(!filterBitfield) { + filterBitfield = new unsigned char[bitfieldLength]; + memset(filterBitfield, 0, bitfieldLength); + } + if(length > 0) { + size_t startBlock = offset/blockLength; + size_t endBlock = (offset+length-1)/blockLength; + for(size_t i = startBlock; i <= endBlock && i < blocks; i++) { + setBitInternal(filterBitfield, i, false); + } + } + updateCache(); +} + void BitfieldMan::enableFilter() { if(!filterBitfield) { filterBitfield = new unsigned char[bitfieldLength]; diff --git a/src/BitfieldMan.h b/src/BitfieldMan.h index 3287e2c0..909d82c7 100644 --- a/src/BitfieldMan.h +++ b/src/BitfieldMan.h @@ -83,7 +83,7 @@ private: size_t getEndIndex(size_t index) const; uint64_t getCompletedLength(bool useFilter) const; - +public: // [startIndex, endIndex) class Range { public: @@ -160,7 +160,11 @@ public: /** * affected by filter */ - bool getSparseMissingUnusedIndex(size_t& index) const; + bool getSparseMissingUnusedIndex + (size_t& index, + const unsigned char* ignoreBitfield, + size_t ignoreBitfieldLength) const; + /** * affected by filter */ @@ -243,6 +247,7 @@ public: void setAllUseBit(); void addFilter(uint64_t offset, uint64_t length); + void removeFilter(uint64_t offset, uint64_t length); /** * Clears filter and disables filter */ @@ -306,6 +311,10 @@ public: uint64_t getMissingUnusedLength(size_t startingIndex) const; + const unsigned char* getFilterBitfield() const + { + return filterBitfield; + } }; } // namespace aria2 diff --git a/src/CreateRequestCommand.cc b/src/CreateRequestCommand.cc new file mode 100644 index 00000000..824d26c4 --- /dev/null +++ b/src/CreateRequestCommand.cc @@ -0,0 +1,85 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2009 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "CreateRequestCommand.h" + +#include "InitiateConnectionCommandFactory.h" +#include "RequestGroup.h" +#include "Segment.h" +#include "DownloadContext.h" +#include "DlAbortEx.h" +#include "DownloadEngine.h" +#include "SocketCore.h" +#include "SegmentMan.h" + +namespace aria2 { + +CreateRequestCommand::CreateRequestCommand(int32_t cuid, + RequestGroup* requestGroup, + DownloadEngine* e): + AbstractCommand(cuid, SharedHandle<Request>(), requestGroup, e) +{ + setStatus(Command::STATUS_ONESHOT_REALTIME); + disableReadCheckSocket(); + disableWriteCheckSocket(); +} + +bool CreateRequestCommand::executeInternal() +{ + if(_segments.empty()) { + _fileEntry = _requestGroup->getDownloadContext()->findFileEntryByOffset(0); + } else { + // We assume all segments belongs to same file. + _fileEntry = _requestGroup->getDownloadContext()->findFileEntryByOffset + (_segments.front()->getPositionToWrite()); + } + req = _fileEntry->getRequest(_requestGroup->getURISelector()); + if(req.isNull()) { + if(!_requestGroup->getSegmentMan().isNull()) { + _requestGroup->getSegmentMan()->ignoreSegmentFor(_fileEntry); + } + throw DL_ABORT_EX("No URI available."); + } + + Command* command = + InitiateConnectionCommandFactory::createInitiateConnectionCommand + (cuid, req, _fileEntry, _requestGroup, e); + //ServerHostHandle sv(new ServerHost(command->getCuid(), req->getHost())); + //registerServerHost(sv); + e->setNoWait(true); + e->commands.push_back(command); + return true; +} + +} // namespace aria2 diff --git a/src/CreateRequestCommand.h b/src/CreateRequestCommand.h new file mode 100644 index 00000000..d4f5fae3 --- /dev/null +++ b/src/CreateRequestCommand.h @@ -0,0 +1,53 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2009 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef _D_CREATE_REQUEST_COMMAND_H_ +#define _D_CREATE_REQUEST_COMMAND_H_ + +#include "AbstractCommand.h" + +namespace aria2 { + +class CreateRequestCommand:public AbstractCommand { +public: + CreateRequestCommand(int32_t cuid, + RequestGroup* requestGroup, + DownloadEngine* e); +protected: + virtual bool executeInternal(); +}; + +} // namespace aria2 + +#endif // _D_CREATE_REQUEST_COMMAND_H_ diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc index a47fd80e..3a707558 100644 --- a/src/DefaultPieceStorage.cc +++ b/src/DefaultPieceStorage.cc @@ -261,10 +261,11 @@ SharedHandle<Piece> DefaultPieceStorage::getMissingFastPiece #endif // ENABLE_BITTORRENT -PieceHandle DefaultPieceStorage::getMissingPiece() +PieceHandle DefaultPieceStorage::getSparseMissingUnusedPiece +(const unsigned char* ignoreBitfield, size_t length) { size_t index; - if(bitfieldMan->getSparseMissingUnusedIndex(index)) { + if(bitfieldMan->getSparseMissingUnusedIndex(index, ignoreBitfield, length)) { return checkOutPiece(index); } else { return SharedHandle<Piece>(); diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h index 1bf01f62..36e42728 100644 --- a/src/DefaultPieceStorage.h +++ b/src/DefaultPieceStorage.h @@ -133,7 +133,8 @@ public: #endif // ENABLE_BITTORRENT - virtual SharedHandle<Piece> getMissingPiece(); + virtual SharedHandle<Piece> getSparseMissingUnusedPiece + (const unsigned char* ignoreBitfield, size_t length); virtual SharedHandle<Piece> getMissingPiece(size_t index); diff --git a/src/DownloadCommand.cc b/src/DownloadCommand.cc index 7812d375..3c563984 100644 --- a/src/DownloadCommand.cc +++ b/src/DownloadCommand.cc @@ -66,10 +66,11 @@ namespace aria2 { DownloadCommand::DownloadCommand(int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e, const SocketHandle& s): - AbstractCommand(cuid, req, requestGroup, e, s) + AbstractCommand(cuid, req, fileEntry, requestGroup, e, s) #ifdef ENABLE_MESSAGE_DIGEST , _pieceHashValidationEnabled(false) #endif // ENABLE_MESSAGE_DIGEST @@ -114,8 +115,13 @@ bool DownloadCommand::executeInternal() { size_t BUFSIZE = 16*1024; unsigned char buf[BUFSIZE]; size_t bufSize; - if(segment->getLength() > 0 && segment->getLength()-segment->getWrittenLength() < BUFSIZE) { - bufSize = segment->getLength()-segment->getWrittenLength(); + if(segment->getLength() > 0) { + if(segment->getPosition()+segment->getLength() <= static_cast<uint64_t>(_fileEntry->getLastOffset())) { + bufSize = std::min(segment->getLength()-segment->getWrittenLength(), + BUFSIZE); + } else { + bufSize = std::min(static_cast<size_t>(_fileEntry->getLastOffset()-_fileEntry->gtoloff(segment->getPositionToWrite())), BUFSIZE); + } } else { bufSize = BUFSIZE; } @@ -167,13 +173,15 @@ bool DownloadCommand::executeInternal() { bool segmentComplete = false; // Note that GrowSegment::complete() always returns false. if(_transferEncodingDecoder.isNull() && _contentEncodingDecoder.isNull()) { - if(segment->complete()) { + if(segment->complete() || + segment->getPositionToWrite() == _fileEntry->getLastOffset()) { segmentComplete = true; } else if(segment->getLength() == 0 && bufSize == 0 && !socket->wantRead() && !socket->wantWrite()) { segmentComplete = true; } - } else if(!_transferEncodingDecoder.isNull() && segment->complete()) { + } else if(!_transferEncodingDecoder.isNull() && + (segment->complete() || segment->getPositionToWrite() == _fileEntry->getLastOffset())) { segmentComplete = true; } else if((_transferEncodingDecoder.isNull() || _transferEncodingDecoder->finished()) && @@ -188,36 +196,40 @@ bool DownloadCommand::executeInternal() { } if(segmentComplete) { - logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid); + if(segment->complete() || segment->getLength() == 0) { + // If segment->getLength() == 0, the server doesn't provide + // content length, but the client detected that download + // completed. + logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid); #ifdef ENABLE_MESSAGE_DIGEST - { - std::string expectedPieceHash = - _requestGroup->getDownloadContext()->getPieceHash(segment->getIndex()); - if(_pieceHashValidationEnabled && !expectedPieceHash.empty()) { - if(segment->isHashCalculated()) { - logger->debug("Hash is available! index=%lu", - static_cast<unsigned long>(segment->getIndex())); - validatePieceHash(segment, expectedPieceHash, segment->getHashString()); + { + std::string expectedPieceHash = + _requestGroup->getDownloadContext()->getPieceHash(segment->getIndex()); + if(_pieceHashValidationEnabled && !expectedPieceHash.empty()) { + if(segment->isHashCalculated()) { + logger->debug("Hash is available! index=%lu", + static_cast<unsigned long>(segment->getIndex())); + validatePieceHash(segment, expectedPieceHash, segment->getHashString()); + } else { + _messageDigestContext->digestReset(); + validatePieceHash(segment, expectedPieceHash, + MessageDigestHelper::digest + (_messageDigestContext.get(), + _requestGroup->getPieceStorage()->getDiskAdaptor(), + segment->getPosition(), + segment->getLength())); + } } else { - _messageDigestContext->digestReset(); - validatePieceHash(segment, expectedPieceHash, - MessageDigestHelper::digest - (_messageDigestContext.get(), - _requestGroup->getPieceStorage()->getDiskAdaptor(), - segment->getPosition(), - segment->getLength())); + _requestGroup->getSegmentMan()->completeSegment(cuid, segment); } - } else { - _requestGroup->getSegmentMan()->completeSegment(cuid, segment); } - } #else // !ENABLE_MESSAGE_DIGEST - - _requestGroup->getSegmentMan()->completeSegment(cuid, segment); - + _requestGroup->getSegmentMan()->completeSegment(cuid, segment); #endif // !ENABLE_MESSAGE_DIGEST + } + checkLowestDownloadSpeed(); // this unit is going to download another segment. @@ -263,6 +275,10 @@ bool DownloadCommand::prepareForNextSegment() { // segment. if(_segments.size() == 1) { SegmentHandle tempSegment = _segments.front(); + if(!tempSegment->complete()) { + return prepareForRetry(0); + } + // TODO1.5 get segment for the same file only SegmentHandle nextSegment = _requestGroup->getSegmentMan()->getSegment(cuid, tempSegment->getIndex()+1); diff --git a/src/DownloadCommand.h b/src/DownloadCommand.h index 05d3b670..ad078746 100644 --- a/src/DownloadCommand.h +++ b/src/DownloadCommand.h @@ -76,6 +76,7 @@ protected: public: DownloadCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e, const SharedHandle<SocketCore>& s); diff --git a/src/DownloadContext.cc b/src/DownloadContext.cc index 2d3b888a..a5dda4d2 100644 --- a/src/DownloadContext.cc +++ b/src/DownloadContext.cc @@ -33,6 +33,9 @@ */ /* copyright --> */ #include "DownloadContext.h" + +#include <algorithm> + #include "FileEntry.h" namespace aria2 { @@ -79,4 +82,25 @@ int64_t DownloadContext::calculateSessionTime() const } } +SharedHandle<FileEntry> +DownloadContext::findFileEntryByOffset(off_t offset) const +{ + if(_fileEntries.empty() || + (offset > 0 && + _fileEntries.back()->getOffset()+_fileEntries.back()->getLength() <= + static_cast<uint64_t>(offset))){ + return SharedHandle<FileEntry>(); + } + + SharedHandle<FileEntry> obj(new FileEntry()); + obj->setOffset(offset); + std::deque<SharedHandle<FileEntry> >::const_iterator i = + std::upper_bound(_fileEntries.begin(), _fileEntries.end(), obj); + if(i != _fileEntries.end() && (*i)->getOffset() == offset) { + return *i; + } else { + return *(--i); + } +} + } // namespace aria2 diff --git a/src/DownloadContext.h b/src/DownloadContext.h index e40c9a18..f1aed08e 100644 --- a/src/DownloadContext.h +++ b/src/DownloadContext.h @@ -117,6 +117,10 @@ public: void resetDownloadStopTime(); int64_t calculateSessionTime() const; + + // Returns FileEntry at given offset. SharedHandle<FileEntry>() is + // returned if no such FileEntry is found. + SharedHandle<FileEntry> findFileEntryByOffset(off_t offset) const; }; typedef SharedHandle<DownloadContext> DownloadContextHandle; diff --git a/src/FileEntry.cc b/src/FileEntry.cc index 8abc1a5d..4e23f5d4 100644 --- a/src/FileEntry.cc +++ b/src/FileEntry.cc @@ -33,8 +33,11 @@ */ /* copyright --> */ #include "FileEntry.h" -#include "File.h" + +#include <cassert> + #include "Util.h" +#include "URISelector.h" namespace aria2 { @@ -74,4 +77,66 @@ bool FileEntry::exists() const return File(getPath()).exists(); } +off_t FileEntry::gtoloff(off_t goff) const +{ + assert(offset <= goff); + return goff-offset; +} + +void FileEntry::getUris(std::deque<std::string>& uris) const +{ + uris.insert(uris.end(), _spentUris.begin(), _spentUris.end()); + uris.insert(uris.end(), _uris.begin(), _uris.end()); +} + +std::string FileEntry::selectUri(const SharedHandle<URISelector>& uriSelector) +{ + return uriSelector->select(_uris); +} + +SharedHandle<Request> +FileEntry::getRequest(const SharedHandle<URISelector>& selector) +{ + SharedHandle<Request> req; + if(_requestPool.empty()) { + while(1) { + std::string uri = selector->select(_uris); + if(uri.empty()) { + return req; + } + req.reset(new Request()); + if(req->setUrl(uri)) { + _spentUris.push_back(uri); + _inFlightRequests.push_back(req); + return req; + } else { + req.reset(); + } + } + } else { + req = _requestPool.back(); + _requestPool.pop_back(); + _inFlightRequests.push_back(req); + return req; + } +} + +void FileEntry::poolRequest(const SharedHandle<Request>& request) +{ + removeRequest(request); + _requestPool.push_back(request); +} + +bool FileEntry::removeRequest(const SharedHandle<Request>& request) +{ + for(std::deque<SharedHandle<Request> >::iterator i = + _inFlightRequests.begin(); i != _inFlightRequests.end(); ++i) { + if((*i).get() == request.get()) { + _inFlightRequests.erase(i); + return true; + } + } + return false; +} + } // namespace aria2 diff --git a/src/FileEntry.h b/src/FileEntry.h index 7cc27619..05ba6067 100644 --- a/src/FileEntry.h +++ b/src/FileEntry.h @@ -43,17 +43,23 @@ #include "SharedHandle.h" #include "File.h" +#include "Request.h" namespace aria2 { +class URISelector; + class FileEntry { private: std::string path; std::deque<std::string> _uris; + std::deque<std::string> _spentUris; uint64_t length; off_t offset; bool extracted; bool requested; + std::deque<SharedHandle<Request> > _requestPool; + std::deque<SharedHandle<Request> > _inFlightRequests; public: FileEntry():length(0), offset(0), extracted(false), requested(false) {} @@ -86,6 +92,8 @@ public: void setOffset(off_t offset) { this->offset = offset; } + off_t getLastOffset() { return offset+length; } + bool isExtracted() const { return extracted; } void setExtracted(bool flag) { this->extracted = flag; } @@ -96,14 +104,53 @@ public: void setupDir(); + // TODO1.5 remove this in favor of getRemainingUris() const std::deque<std::string>& getAssociatedUris() const { return _uris; } + const std::deque<std::string>& getRemainingUris() const + { + return _uris; + } + + const std::deque<std::string>& getSpentUris() const + { + return _spentUris; + } + + void setUris(const std::deque<std::string>& uris) + { + _uris = uris; + } + + // Inserts _uris and _spentUris into uris. + void getUris(std::deque<std::string>& uris) const; + + std::string selectUri(const SharedHandle<URISelector>& uriSelector); + + // If pooled Request object is available, one of them is removed + // from the pool and returned. If pool is empty, then select URI + // using selectUri(selector) and construct Request object using it + // and return the Request object. + SharedHandle<Request> getRequest(const SharedHandle<URISelector>& selector); + + void poolRequest(const SharedHandle<Request>& request); + + bool removeRequest(const SharedHandle<Request>& request); + + size_t countInFlightRequest() const + { + return _inFlightRequests.size(); + } + bool operator<(const FileEntry& fileEntry) const; bool exists() const; + + // Translate global offset goff to file local offset. + off_t gtoloff(off_t goff) const; }; typedef SharedHandle<FileEntry> FileEntryHandle; diff --git a/src/FtpDownloadCommand.cc b/src/FtpDownloadCommand.cc index 64929662..49a62b5c 100644 --- a/src/FtpDownloadCommand.cc +++ b/src/FtpDownloadCommand.cc @@ -49,12 +49,13 @@ namespace aria2 { FtpDownloadCommand::FtpDownloadCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<FtpConnection>& ftpConnection, DownloadEngine* e, const SocketHandle& dataSocket, const SocketHandle& ctrlSocket) - :DownloadCommand(cuid, req, requestGroup, e, dataSocket), + :DownloadCommand(cuid, req, fileEntry, requestGroup, e, dataSocket), _ftpConnection(ftpConnection), ctrlSocket(ctrlSocket) {} @@ -64,8 +65,9 @@ FtpDownloadCommand::~FtpDownloadCommand() {} bool FtpDownloadCommand::prepareForNextSegment() { if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION) && - (uint64_t)_segments.front()->getPositionToWrite() == _requestGroup->getTotalLength()) { - Command* command = new FtpFinishDownloadCommand(cuid, req, _requestGroup, _ftpConnection, e, ctrlSocket); + static_cast<uint64_t>(_fileEntry->gtoloff(_segments.front()->getPositionToWrite())) == _fileEntry->getLength()) { + Command* command = new FtpFinishDownloadCommand + (cuid, req, _fileEntry, _requestGroup, _ftpConnection, e, ctrlSocket); e->commands.push_back(command); if(_requestGroup->downloadFinished()) { diff --git a/src/FtpDownloadCommand.h b/src/FtpDownloadCommand.h index c4b2829e..1a2b3139 100644 --- a/src/FtpDownloadCommand.h +++ b/src/FtpDownloadCommand.h @@ -51,6 +51,7 @@ protected: public: FtpDownloadCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<FtpConnection>& ftpConnection, DownloadEngine* e, diff --git a/src/FtpFinishDownloadCommand.cc b/src/FtpFinishDownloadCommand.cc index ae2009d1..bf8af2a2 100644 --- a/src/FtpFinishDownloadCommand.cc +++ b/src/FtpFinishDownloadCommand.cc @@ -53,11 +53,12 @@ namespace aria2 { FtpFinishDownloadCommand::FtpFinishDownloadCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<FtpConnection>& ftpConnection, DownloadEngine* e, const SharedHandle<SocketCore>& socket) - :AbstractCommand(cuid, req, requestGroup, e, socket), + :AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket), _ftpConnection(ftpConnection) { e->addSocketForReadCheck(socket, this); diff --git a/src/FtpFinishDownloadCommand.h b/src/FtpFinishDownloadCommand.h index 2edc6d5b..81adf934 100644 --- a/src/FtpFinishDownloadCommand.h +++ b/src/FtpFinishDownloadCommand.h @@ -51,6 +51,7 @@ protected: public: FtpFinishDownloadCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<FtpConnection>& ftpConnection, DownloadEngine* e, diff --git a/src/FtpInitiateConnectionCommand.cc b/src/FtpInitiateConnectionCommand.cc index b6c15423..7453337a 100644 --- a/src/FtpInitiateConnectionCommand.cc +++ b/src/FtpInitiateConnectionCommand.cc @@ -56,9 +56,10 @@ namespace aria2 { FtpInitiateConnectionCommand::FtpInitiateConnectionCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e) - :InitiateConnectionCommand(cuid, req, requestGroup, e) {} + :InitiateConnectionCommand(cuid, req, fileEntry, requestGroup, e) {} FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {} @@ -86,7 +87,8 @@ Command* FtpInitiateConnectionCommand::createNextCommand (new HttpConnection(cuid, socket, getOption().get())); HttpRequestCommand* c = - new HttpRequestCommand(cuid, req, _requestGroup, hc, e, socket); + new HttpRequestCommand(cuid, req, _fileEntry, + _requestGroup, hc, e, socket); c->setProxyRequest(proxyRequest); command = c; } else if(proxyMethod == V_TUNNEL) { @@ -99,7 +101,8 @@ Command* FtpInitiateConnectionCommand::createNextCommand } else { if(proxyMethod == V_TUNNEL) { command = - new FtpNegotiationCommand(cuid, req, _requestGroup, e, pooledSocket, + new FtpNegotiationCommand(cuid, req, _fileEntry, + _requestGroup, e, pooledSocket, FtpNegotiationCommand::SEQ_SEND_CWD, options["baseWorkingDir"]); } else if(proxyMethod == V_GET) { @@ -109,7 +112,8 @@ Command* FtpInitiateConnectionCommand::createNextCommand (new HttpConnection(cuid, pooledSocket, getOption().get())); HttpRequestCommand* c = - new HttpRequestCommand(cuid, req, _requestGroup, hc, e, pooledSocket); + new HttpRequestCommand(cuid, req, _fileEntry, + _requestGroup, hc, e, pooledSocket); c->setProxyRequest(proxyRequest); command = c; } else { @@ -126,10 +130,12 @@ Command* FtpInitiateConnectionCommand::createNextCommand req->getPort()); socket.reset(new SocketCore()); socket->establishConnection(resolvedAddresses.front(), req->getPort()); - command = new FtpNegotiationCommand(cuid, req, _requestGroup, e, socket); + command = new FtpNegotiationCommand(cuid, req, _fileEntry, + _requestGroup, e, socket); } else { command = - new FtpNegotiationCommand(cuid, req, _requestGroup, e, pooledSocket, + new FtpNegotiationCommand(cuid, req, _fileEntry, + _requestGroup, e, pooledSocket, FtpNegotiationCommand::SEQ_SEND_CWD, options["baseWorkingDir"]); } diff --git a/src/FtpInitiateConnectionCommand.h b/src/FtpInitiateConnectionCommand.h index e915753d..6a6cded7 100644 --- a/src/FtpInitiateConnectionCommand.h +++ b/src/FtpInitiateConnectionCommand.h @@ -46,6 +46,7 @@ protected: const SharedHandle<Request>& proxyRequest); public: FtpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e); virtual ~FtpInitiateConnectionCommand(); diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc index 1a857c03..cbdea101 100644 --- a/src/FtpNegotiationCommand.cc +++ b/src/FtpNegotiationCommand.cc @@ -68,14 +68,16 @@ namespace aria2 { -FtpNegotiationCommand::FtpNegotiationCommand(int32_t cuid, - const RequestHandle& req, - RequestGroup* requestGroup, - DownloadEngine* e, - const SocketHandle& s, - Seq seq, - const std::string& baseWorkingDir): - AbstractCommand(cuid, req, requestGroup, e, s), sequence(seq), +FtpNegotiationCommand::FtpNegotiationCommand +(int32_t cuid, + const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, + RequestGroup* requestGroup, + DownloadEngine* e, + const SocketHandle& s, + Seq seq, + const std::string& baseWorkingDir): + AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), sequence(seq), ftp(new FtpConnection(cuid, socket, req, e->getAuthConfigFactory()->createAuthConfig(req), getOption().get())) @@ -96,7 +98,8 @@ bool FtpNegotiationCommand::executeInternal() { return prepareForRetry(0); } else if(sequence == SEQ_NEGOTIATION_COMPLETED) { FtpDownloadCommand* command = - new FtpDownloadCommand(cuid, req, _requestGroup, ftp, e, dataSocket, socket); + new FtpDownloadCommand + (cuid, req, _fileEntry, _requestGroup, ftp, e, dataSocket, socket); command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setLowestDownloadSpeedLimit(getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT)); if(!_requestGroup->isSingleHostMultiConnectionEnabled()) { @@ -328,6 +331,7 @@ bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength) SingleFileDownloadContextHandle dctx = dynamic_pointer_cast<SingleFileDownloadContext>(_requestGroup->getDownloadContext()); dctx->setTotalLength(totalLength); + _fileEntry->setLength(totalLength); dctx->setFilename (strconcat(dctx->getDir(), "/", Util::urldecode(req->getFile()))); _requestGroup->preDownloadProcessing(); @@ -429,7 +433,7 @@ bool FtpNegotiationCommand::recvSize() { return onFileSizeDetermined(size); } else { - _requestGroup->validateTotalLength(size); + _requestGroup->validateTotalLength(_fileEntry->getLength(), size); } } else { diff --git a/src/FtpNegotiationCommand.h b/src/FtpNegotiationCommand.h index 18487033..bdbc2c15 100644 --- a/src/FtpNegotiationCommand.h +++ b/src/FtpNegotiationCommand.h @@ -123,6 +123,7 @@ protected: public: FtpNegotiationCommand(int32_t cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e, const SharedHandle<SocketCore>& s, diff --git a/src/FtpTunnelResponseCommand.cc b/src/FtpTunnelResponseCommand.cc index 121bd24a..293b88c8 100644 --- a/src/FtpTunnelResponseCommand.cc +++ b/src/FtpTunnelResponseCommand.cc @@ -54,7 +54,8 @@ FtpTunnelResponseCommand::~FtpTunnelResponseCommand() {} Command* FtpTunnelResponseCommand::getNextCommand() { - return new FtpNegotiationCommand(cuid, req, _requestGroup, e, socket); + return new FtpNegotiationCommand(cuid, req, _fileEntry, + _requestGroup, e, socket); } } // namespace aria2 diff --git a/src/HttpDownloadCommand.cc b/src/HttpDownloadCommand.cc index 69b09be1..9819efea 100644 --- a/src/HttpDownloadCommand.cc +++ b/src/HttpDownloadCommand.cc @@ -52,12 +52,13 @@ namespace aria2 { HttpDownloadCommand::HttpDownloadCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<HttpResponse>& httpResponse, const HttpConnectionHandle& httpConnection, DownloadEngine* e, const SocketHandle& socket) - :DownloadCommand(cuid, req, requestGroup, e, socket), + :DownloadCommand(cuid, req, fileEntry, requestGroup, e, socket), _httpResponse(httpResponse), _httpConnection(httpConnection) {} @@ -67,7 +68,8 @@ bool HttpDownloadCommand::prepareForNextSegment() { bool downloadFinished = _requestGroup->downloadFinished(); if(req->isPipeliningEnabled() && !downloadFinished) { HttpRequestCommand* command = - new HttpRequestCommand(cuid, req, _requestGroup, _httpConnection, e, + new HttpRequestCommand(cuid, req, _fileEntry, + _requestGroup, _httpConnection, e, socket); // Set proxy request here. aria2 sends the HTTP request specialized for // proxy. @@ -81,8 +83,7 @@ bool HttpDownloadCommand::prepareForNextSegment() { (req->isKeepAliveEnabled() && ((!_transferEncodingDecoder.isNull() && _requestGroup->downloadFinished()) || - (uint64_t)_segments.front()->getPositionToWrite() == - _requestGroup->getTotalLength()))) { + static_cast<uint64_t>(_fileEntry->gtoloff(_segments.front()->getPositionToWrite())) == _fileEntry->getLength()))) { e->poolSocket(req, isProxyDefined(), socket); } // The request was sent assuming that server supported pipelining, but diff --git a/src/HttpDownloadCommand.h b/src/HttpDownloadCommand.h index c4343e31..e1e995da 100644 --- a/src/HttpDownloadCommand.h +++ b/src/HttpDownloadCommand.h @@ -51,6 +51,7 @@ protected: public: HttpDownloadCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<HttpResponse>& httpResponse, const SharedHandle<HttpConnection>& httpConnection, diff --git a/src/HttpInitiateConnectionCommand.cc b/src/HttpInitiateConnectionCommand.cc index 797b2632..b9552db5 100644 --- a/src/HttpInitiateConnectionCommand.cc +++ b/src/HttpInitiateConnectionCommand.cc @@ -53,9 +53,10 @@ namespace aria2 { HttpInitiateConnectionCommand::HttpInitiateConnectionCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e): - InitiateConnectionCommand(cuid, req, requestGroup, e) {} + InitiateConnectionCommand(cuid, req, fileEntry, requestGroup, e) {} HttpInitiateConnectionCommand::~HttpInitiateConnectionCommand() {} @@ -81,7 +82,9 @@ Command* HttpInitiateConnectionCommand::createNextCommand } else if(proxyMethod == V_GET) { SharedHandle<HttpConnection> httpConnection (new HttpConnection(cuid, socket, getOption().get())); - HttpRequestCommand* c = new HttpRequestCommand(cuid, req, _requestGroup, + HttpRequestCommand* c = new HttpRequestCommand(cuid, req, + _fileEntry, + _requestGroup, httpConnection, e, socket); c->setProxyRequest(proxyRequest); @@ -93,7 +96,9 @@ Command* HttpInitiateConnectionCommand::createNextCommand } else { SharedHandle<HttpConnection> httpConnection (new HttpConnection(cuid, pooledSocket, getOption().get())); - HttpRequestCommand* c = new HttpRequestCommand(cuid, req, _requestGroup, + HttpRequestCommand* c = new HttpRequestCommand(cuid, req, + _fileEntry, + _requestGroup, httpConnection, e, pooledSocket); if(proxyMethod == V_GET) { @@ -113,8 +118,8 @@ Command* HttpInitiateConnectionCommand::createNextCommand socket = pooledSocket; } SharedHandle<HttpConnection> httpConnection(new HttpConnection(cuid, socket, getOption().get())); - command = new HttpRequestCommand(cuid, req, _requestGroup, httpConnection, - e, socket); + command = new HttpRequestCommand(cuid, req, _fileEntry, _requestGroup, + httpConnection, e, socket); } return command; } diff --git a/src/HttpInitiateConnectionCommand.h b/src/HttpInitiateConnectionCommand.h index cd7ec83c..54f76523 100644 --- a/src/HttpInitiateConnectionCommand.h +++ b/src/HttpInitiateConnectionCommand.h @@ -46,6 +46,7 @@ protected: const SharedHandle<Request>& proxyRequest); public: HttpInitiateConnectionCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e); diff --git a/src/HttpProxyResponseCommand.cc b/src/HttpProxyResponseCommand.cc index 65bdff2d..0054d6d9 100644 --- a/src/HttpProxyResponseCommand.cc +++ b/src/HttpProxyResponseCommand.cc @@ -54,7 +54,8 @@ HttpProxyResponseCommand::~HttpProxyResponseCommand() {} Command* HttpProxyResponseCommand::getNextCommand() { - return new HttpRequestCommand(cuid, req, _requestGroup, httpConnection, e, socket); + return new HttpRequestCommand(cuid, req, _fileEntry, + _requestGroup, httpConnection, e, socket); } } // namespace aria2 diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 10f243e7..d46f68ac 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -73,7 +73,7 @@ off_t HttpRequest::getStartByte() const if(segment.isNull()) { return 0; } else { - return segment->getPositionToWrite(); + return _fileEntry->gtoloff(segment->getPositionToWrite()); } } @@ -83,7 +83,7 @@ off_t HttpRequest::getEndByte() const return 0; } else { if(request->isPipeliningEnabled()) { - return segment->getPosition()+segment->getLength()-1; + return _fileEntry->gtoloff(segment->getPosition()+segment->getLength()-1); } else { return 0; } diff --git a/src/HttpRequest.h b/src/HttpRequest.h index f84596a5..9ec32171 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -42,6 +42,7 @@ #include "SharedHandle.h" #include "Request.h" +#include "FileEntry.h" namespace aria2 { @@ -59,6 +60,8 @@ private: SharedHandle<Request> request; + SharedHandle<FileEntry> _fileEntry; + SharedHandle<Segment> segment; uint64_t entityLength; @@ -232,6 +235,16 @@ public: // Returns AuthConfig used in the last invocation of // createRequest(). const SharedHandle<AuthConfig>& getAuthConfig() const; + + void setFileEntry(const SharedHandle<FileEntry>& fileEntry) + { + _fileEntry = fileEntry; + } + + const SharedHandle<FileEntry>& getFileEntry() const + { + return _fileEntry; + } }; typedef SharedHandle<HttpRequest> HttpRequestHandle; diff --git a/src/HttpRequestCommand.cc b/src/HttpRequestCommand.cc index 7acd3fdf..d95e616b 100644 --- a/src/HttpRequestCommand.cc +++ b/src/HttpRequestCommand.cc @@ -58,11 +58,12 @@ namespace aria2 { HttpRequestCommand::HttpRequestCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const HttpConnectionHandle& httpConnection, DownloadEngine* e, const SocketHandle& s) - :AbstractCommand(cuid, req, requestGroup, e, s), + :AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), _httpConnection(httpConnection) { setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT)); @@ -74,6 +75,7 @@ HttpRequestCommand::~HttpRequestCommand() {} static SharedHandle<HttpRequest> createHttpRequest(const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, const SharedHandle<Segment>& segment, uint64_t totalLength, const SharedHandle<Option>& option, @@ -85,8 +87,9 @@ createHttpRequest(const SharedHandle<Request>& req, HttpRequestHandle httpRequest(new HttpRequest()); httpRequest->setUserAgent(option->get(PREF_USER_AGENT)); httpRequest->setRequest(req); + httpRequest->setFileEntry(fileEntry); httpRequest->setSegment(segment); - httpRequest->setEntityLength(totalLength); + httpRequest->setEntityLength(fileEntry->getLength()); httpRequest->addHeader(option->get(PREF_HEADER)); httpRequest->setCookieStorage(cookieStorage); httpRequest->setAuthConfigFactory(authConfigFactory); @@ -113,7 +116,9 @@ bool HttpRequestCommand::executeInternal() { if(_segments.empty()) { HttpRequestHandle httpRequest - (createHttpRequest(req, SharedHandle<Segment>(), + (createHttpRequest(req, + _fileEntry, + SharedHandle<Segment>(), _requestGroup->getTotalLength(), getOption(), _requestGroup, @@ -126,7 +131,9 @@ bool HttpRequestCommand::executeInternal() { const SegmentHandle& segment = *itr; if(!_httpConnection->isIssued(segment)) { HttpRequestHandle httpRequest - (createHttpRequest(req, segment, + (createHttpRequest(req, + _fileEntry, + segment, _requestGroup->getTotalLength(), getOption(), _requestGroup, @@ -141,7 +148,8 @@ bool HttpRequestCommand::executeInternal() { _httpConnection->sendPendingData(); } if(_httpConnection->sendBufferIsEmpty()) { - Command* command = new HttpResponseCommand(cuid, req, _requestGroup, + Command* command = new HttpResponseCommand(cuid, req, _fileEntry, + _requestGroup, _httpConnection, e, socket); e->commands.push_back(command); return true; diff --git a/src/HttpRequestCommand.h b/src/HttpRequestCommand.h index 33ec8c6f..fe0a34de 100644 --- a/src/HttpRequestCommand.h +++ b/src/HttpRequestCommand.h @@ -52,6 +52,7 @@ protected: public: HttpRequestCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<HttpConnection>& httpConnection, DownloadEngine* e, diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index b337d9cf..30de2641 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -75,14 +75,17 @@ static SharedHandle<Decoder> getTransferEncodingDecoder static SharedHandle<Decoder> getContentEncodingDecoder (const SharedHandle<HttpResponse>& httpResponse); -HttpResponseCommand::HttpResponseCommand(int32_t cuid, - const RequestHandle& req, - RequestGroup* requestGroup, - const HttpConnectionHandle& httpConnection, - DownloadEngine* e, - const SocketHandle& s) - :AbstractCommand(cuid, req, requestGroup, e, s), - httpConnection(httpConnection) {} +HttpResponseCommand::HttpResponseCommand +(int32_t cuid, + const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, + RequestGroup* requestGroup, + const HttpConnectionHandle& httpConnection, + DownloadEngine* e, + const SocketHandle& s) + :AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), + httpConnection(httpConnection) +{} HttpResponseCommand::~HttpResponseCommand() {} @@ -136,6 +139,7 @@ bool HttpResponseCommand::executeInternal() SingleFileDownloadContextHandle dctx = dynamic_pointer_cast<SingleFileDownloadContext>(_requestGroup->getDownloadContext()); dctx->setTotalLength(totalLength); + _fileEntry->setLength(totalLength); dctx->setFilename (strconcat(dctx->getDir(), "/", httpResponse->determinFilename())); dctx->setContentType(httpResponse->getContentType()); @@ -166,7 +170,8 @@ bool HttpResponseCommand::executeInternal() } } else { // validate totalsize - _requestGroup->validateTotalLength(httpResponse->getEntityLength()); + _requestGroup->validateTotalLength(_fileEntry->getLength(), + httpResponse->getEntityLength()); // update last modified time updateLastModifiedTime(httpResponse->getLastModifiedTime()); if(_requestGroup->getTotalLength() == 0) { @@ -258,6 +263,7 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpRe command = createHttpDownloadCommand(httpResponse); } else { _requestGroup->getSegmentMan()->cancelSegment(cuid); + _fileEntry->poolRequest(req); } prepareForNextAction(command); if(req->getMethod() == Request::METHOD_HEAD) { @@ -361,7 +367,7 @@ bool HttpResponseCommand::skipResponseBody // thrown away. HttpSkipResponseCommand* command = new HttpSkipResponseCommand - (cuid, req, _requestGroup, httpConnection, httpResponse, e, socket); + (cuid, req, _fileEntry, _requestGroup, httpConnection, httpResponse, e, socket); command->setTransferEncodingDecoder(decoder); // If request method is HEAD or the response body is zero-length, @@ -386,7 +392,7 @@ HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand { HttpDownloadCommand* command = - new HttpDownloadCommand(cuid, req, _requestGroup, + new HttpDownloadCommand(cuid, req, _fileEntry, _requestGroup, httpResponse, httpConnection, e, socket); command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setLowestDownloadSpeedLimit diff --git a/src/HttpResponseCommand.h b/src/HttpResponseCommand.h index be773d2b..ad35dafb 100644 --- a/src/HttpResponseCommand.h +++ b/src/HttpResponseCommand.h @@ -75,6 +75,7 @@ protected: public: HttpResponseCommand(int32_t cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<HttpConnection>& httpConnection, DownloadEngine* e, diff --git a/src/HttpSkipResponseCommand.cc b/src/HttpSkipResponseCommand.cc index 224a5e9d..b9edb717 100644 --- a/src/HttpSkipResponseCommand.cc +++ b/src/HttpSkipResponseCommand.cc @@ -59,12 +59,13 @@ namespace aria2 { HttpSkipResponseCommand::HttpSkipResponseCommand (int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<HttpConnection>& httpConnection, const SharedHandle<HttpResponse>& httpResponse, DownloadEngine* e, const SharedHandle<SocketCore>& s): - AbstractCommand(cuid, req, requestGroup, e, s), + AbstractCommand(cuid, req, fileEntry, requestGroup, e, s), _httpConnection(httpConnection), _httpResponse(httpResponse), _totalLength(_httpResponse->getEntityLength()), diff --git a/src/HttpSkipResponseCommand.h b/src/HttpSkipResponseCommand.h index 7ec1a511..d3cbe7bb 100644 --- a/src/HttpSkipResponseCommand.h +++ b/src/HttpSkipResponseCommand.h @@ -63,6 +63,7 @@ protected: public: HttpSkipResponseCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, const SharedHandle<HttpConnection>& httpConnection, const SharedHandle<HttpResponse>& httpResponse, diff --git a/src/InitiateConnectionCommand.cc b/src/InitiateConnectionCommand.cc index c5924e76..05c2f9a9 100644 --- a/src/InitiateConnectionCommand.cc +++ b/src/InitiateConnectionCommand.cc @@ -42,15 +42,20 @@ #include "NameResolver.h" #include "DNSCache.h" #include "SocketCore.h" +#include "FileEntry.h" +#include "RequestGroup.h" +#include "DownloadContext.h" +#include "Segment.h" namespace aria2 { InitiateConnectionCommand::InitiateConnectionCommand (int cuid, const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e): - AbstractCommand(cuid, req, requestGroup, e) + AbstractCommand(cuid, req, fileEntry, requestGroup, e) { setTimeout(getOption()->getAsInt(PREF_DNS_TIMEOUT)); // give a chance to be executed in the next loop in DownloadEngine diff --git a/src/InitiateConnectionCommand.h b/src/InitiateConnectionCommand.h index e7d1c901..ed206581 100644 --- a/src/InitiateConnectionCommand.h +++ b/src/InitiateConnectionCommand.h @@ -54,6 +54,7 @@ protected: const SharedHandle<Request>& proxyRequest) = 0; public: InitiateConnectionCommand(int cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e); diff --git a/src/InitiateConnectionCommandFactory.cc b/src/InitiateConnectionCommandFactory.cc index 2a8ba853..2ad3dbda 100644 --- a/src/InitiateConnectionCommandFactory.cc +++ b/src/InitiateConnectionCommandFactory.cc @@ -47,7 +47,13 @@ namespace aria2 { Command* -InitiateConnectionCommandFactory::createInitiateConnectionCommand(int32_t cuid, const RequestHandle& req, RequestGroup* requestGroup, DownloadEngine* e) { +InitiateConnectionCommandFactory::createInitiateConnectionCommand +(int32_t cuid, + const RequestHandle& req, + const SharedHandle<FileEntry>& fileEntry, + RequestGroup* requestGroup, + DownloadEngine* e) +{ if(req->getProtocol() == Request::PROTO_HTTP #ifdef ENABLE_SSL // for SSL @@ -62,9 +68,11 @@ InitiateConnectionCommandFactory::createInitiateConnectionCommand(int32_t cuid, req->setPipeliningHint(true); } - return new HttpInitiateConnectionCommand(cuid, req, requestGroup, e); + return + new HttpInitiateConnectionCommand(cuid, req, fileEntry, requestGroup, e); } else if(req->getProtocol() == Request::PROTO_FTP) { - return new FtpInitiateConnectionCommand(cuid, req, requestGroup, e); + return + new FtpInitiateConnectionCommand(cuid, req, fileEntry, requestGroup, e); } else { // these protocols are not supported yet throw DL_ABORT_EX diff --git a/src/InitiateConnectionCommandFactory.h b/src/InitiateConnectionCommandFactory.h index 01368001..5ba88e90 100644 --- a/src/InitiateConnectionCommandFactory.h +++ b/src/InitiateConnectionCommandFactory.h @@ -44,12 +44,14 @@ class Request; class RequestGroup; class DownloadEngine; class Command; +class FileEntry; class InitiateConnectionCommandFactory { public: static Command* createInitiateConnectionCommand(int32_t cuid, const SharedHandle<Request>& req, + const SharedHandle<FileEntry>& fileEntry, RequestGroup* requestGroup, DownloadEngine* e); }; diff --git a/src/Makefile.am b/src/Makefile.am index 455c3ce3..5951269f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -201,7 +201,8 @@ SRCS = Socket.h\ PieceSelector.h\ LongestSequencePieceSelector.cc LongestSequencePieceSelector.h\ bitfield.h\ - BDE.cc BDE.h + BDE.cc BDE.h\ + CreateRequestCommand.cc CreateRequestCommand.h if ENABLE_XML_RPC SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\ diff --git a/src/Makefile.in b/src/Makefile.in index 90776177..f46e2465 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -425,7 +425,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ SelectEventPoll.cc SelectEventPoll.h SequentialPicker.h \ SequentialDispatcherCommand.h PieceSelector.h \ LongestSequencePieceSelector.cc LongestSequencePieceSelector.h \ - bitfield.h BDE.cc BDE.h XmlRpcRequestParserController.cc \ + bitfield.h BDE.cc BDE.h CreateRequestCommand.cc \ + CreateRequestCommand.h XmlRpcRequestParserController.cc \ XmlRpcRequestParserController.h \ XmlRpcRequestParserStateMachine.cc \ XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \ @@ -846,15 +847,15 @@ am__objects_26 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ SocketBuffer.$(OBJEXT) OptionHandlerException.$(OBJEXT) \ URIResult.$(OBJEXT) SelectEventPoll.$(OBJEXT) \ LongestSequencePieceSelector.$(OBJEXT) BDE.$(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) $(am__objects_12) \ - $(am__objects_13) $(am__objects_14) $(am__objects_15) \ - $(am__objects_16) $(am__objects_17) $(am__objects_18) \ - $(am__objects_19) $(am__objects_20) $(am__objects_21) \ - $(am__objects_22) $(am__objects_23) $(am__objects_24) \ - $(am__objects_25) + CreateRequestCommand.$(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) $(am__objects_12) $(am__objects_13) \ + $(am__objects_14) $(am__objects_15) $(am__objects_16) \ + $(am__objects_17) $(am__objects_18) $(am__objects_19) \ + $(am__objects_20) $(am__objects_21) $(am__objects_22) \ + $(am__objects_23) $(am__objects_24) $(am__objects_25) am_libaria2c_a_OBJECTS = $(am__objects_26) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" @@ -1181,7 +1182,8 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \ SelectEventPoll.cc SelectEventPoll.h SequentialPicker.h \ SequentialDispatcherCommand.h PieceSelector.h \ LongestSequencePieceSelector.cc LongestSequencePieceSelector.h \ - bitfield.h BDE.cc BDE.h $(am__append_1) $(am__append_2) \ + bitfield.h BDE.cc BDE.h CreateRequestCommand.cc \ + CreateRequestCommand.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) \ @@ -1339,6 +1341,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cookie.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieParser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieStorage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CreateRequestCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTAbstractMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTAbstractNodeLookupTask.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTAbstractTask.Po@am__quote@ diff --git a/src/PieceStorage.h b/src/PieceStorage.h index dc3a72f1..17dd2872 100644 --- a/src/PieceStorage.h +++ b/src/PieceStorage.h @@ -101,8 +101,10 @@ public: /** * Returns a missing piece if available. Otherwise returns 0; + * If ignoreBitfield is set, indexes of true bit are excluded. */ - virtual SharedHandle<Piece> getMissingPiece() = 0; + virtual SharedHandle<Piece> getSparseMissingUnusedPiece + (const unsigned char* ignoreBitfield, size_t length) = 0; /** * Returns a missing piece whose index is index. diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 7035e987..0da471b9 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -44,7 +44,7 @@ #include "NullProgressInfoFile.h" #include "Dependency.h" #include "prefs.h" -#include "InitiateConnectionCommandFactory.h" +#include "CreateRequestCommand.h" #include "File.h" #include "message.h" #include "Util.h" @@ -78,6 +78,7 @@ #include "InOrderURISelector.h" #include "PieceSelector.h" #include "a2functional.h" +#include "SocketCore.h" #ifdef ENABLE_MESSAGE_DIGEST # include "CheckIntegrityCommand.h" #endif // ENABLE_MESSAGE_DIGEST @@ -604,6 +605,7 @@ void RequestGroup::createNextCommand(std::deque<Command*>& commands, unsigned int numCommand, const std::string& method) { + // TODO1.5 The following block should be moved into FileEntry if(_option->getAsBool(PREF_REUSE_URI) && _uris.empty()) { std::deque<std::string> uris = _spentUris; std::sort(uris.begin(), uris.end()); @@ -639,35 +641,45 @@ void RequestGroup::createNextCommand(std::deque<Command*>& commands, } std::deque<std::string> pendingURIs; - for(; numCommand--; ) { - std::string uri = _uriSelector->select(_uris); - if(uri.empty()) - continue; - RequestHandle req(new Request()); - if(req->setUrl(uri)) { - ServerHostHandle sv; - if(!_singleHostMultiConnectionEnabled){ - sv = searchServerHost(req->getHost()); - } - if(sv.isNull()) { - _spentUris.push_back(uri); - req->setReferer(_option->get(PREF_REFERER)); - req->setMethod(method); + for(; numCommand--; ) { + Command* command = new CreateRequestCommand(e->newCUID(), this, e); + _logger->debug("filePath=%s", _downloadContext->getFileEntries().front()->getPath().c_str()); + commands.push_back(command); - Command* command = - InitiateConnectionCommandFactory::createInitiateConnectionCommand - (e->newCUID(), req, this, e); - ServerHostHandle sv(new ServerHost(command->getCuid(), req->getHost())); - registerServerHost(sv); - commands.push_back(command); - } else { - pendingURIs.push_back(uri); - } - } else { - _logger->error(MSG_UNRECOGNIZED_URI, req->getUrl().c_str()); - } + // TODO1.5 ServerHost stuff should be moved into FileEntry or + // CreateRequestCommand + +// std::string uri = _uriSelector->select(_uris); +// if(uri.empty()) +// continue; +// RequestHandle req(new Request()); +// if(req->setUrl(uri)) { +// ServerHostHandle sv; +// if(!_singleHostMultiConnectionEnabled){ +// sv = searchServerHost(req->getHost()); +// } +// if(sv.isNull()) { +// _spentUris.push_back(uri); +// req->setReferer(_option->get(PREF_REFERER)); +// req->setMethod(method); + +// Command* command = +// InitiateConnectionCommandFactory::createInitiateConnectionCommand +// (e->newCUID(), req, this, e); +// ServerHostHandle sv(new ServerHost(command->getCuid(), req->getHost())); +// registerServerHost(sv); +// // give a chance to be executed in the next loop in DownloadEngine +// command->setStatus(Command::STATUS_ONESHOT_REALTIME); +// commands.push_back(command); +// } else { +// pendingURIs.push_back(uri); +// } +// } else { +// _logger->error(MSG_UNRECOGNIZED_URI, req->getUrl().c_str()); +// } +// } } - _uris.insert(_uris.begin(), pendingURIs.begin(), pendingURIs.end()); +// _uris.insert(_uris.begin(), pendingURIs.begin(), pendingURIs.end()); if(!commands.empty()) { e->setNoWait(true); } diff --git a/src/RequestGroup.h b/src/RequestGroup.h index 34db9dde..a8c4c388 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -164,9 +164,6 @@ private: void validateFilename(const std::string& expectedFilename, const std::string& actualFilename) const; - void validateTotalLength(uint64_t expectedTotalLength, - uint64_t actualTotalLength) const; - void initializePreDownloadHandler(); void initializePostDownloadHandler(); @@ -249,6 +246,9 @@ public: */ void validateFilename(const std::string& actualFilename) const; + void validateTotalLength(uint64_t expectedTotalLength, + uint64_t actualTotalLength) const; + void validateTotalLength(uint64_t actualTotalLength) const; void setSegmentManFactory(const SharedHandle<SegmentManFactory>& segmentManFactory); @@ -449,6 +449,11 @@ public: void setURISelector(const SharedHandle<URISelector>& uriSelector); + const SharedHandle<URISelector>& getURISelector() const + { + return _uriSelector; + } + void applyLastModifiedTimeToLocalFiles(); void updateLastModifiedTime(const Time& time); diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index 68d029c6..41a0f515 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -486,6 +486,7 @@ void RequestGroupMan::getInitialCommands(std::deque<Command*>& commands, if((*itr)->isDependencyResolved()) { configureRequestGroup(*itr); createInitialCommand(*itr, commands, e, + // TODO1.5 We need PREF_DRY_RUN here? _option->getAsBool(PREF_USE_HEAD)); executeStartHook(*itr, e->option); ++itr; diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 33ed1709..4598e3d3 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -50,6 +50,7 @@ #include "Option.h" #include "DownloadContext.h" #include "Piece.h" +#include "FileEntry.h" namespace aria2 { @@ -66,8 +67,12 @@ SegmentMan::SegmentMan(const Option* option, _downloadContext(downloadContext), _pieceStorage(pieceStorage), _lastPeerStatDlspdMapUpdated(0), - _cachedDlspd(0) -{} + _cachedDlspd(0), + _ignoreBitfield(downloadContext->getPieceLength(), + downloadContext->getTotalLength()) +{ + _ignoreBitfield.enableFilter(); +} SegmentMan::~SegmentMan() {} @@ -126,6 +131,22 @@ SegmentHandle SegmentMan::checkoutSegment(cuid_t cuid, segment->getLength(), segment->getSegmentLength(), segment->getWrittenLength()); + if(piece->getLength() > 0) { + std::map<size_t, size_t>::iterator positr = + _segmentWrittenLengthMemo.find(segment->getIndex()); + if(positr != _segmentWrittenLengthMemo.end()) { + const size_t writtenLength = (*positr).second; + logger->debug("writtenLength(in memo)=%d, writtenLength=%d", + writtenLength, segment->getWrittenLength()); + // If the difference between cached writtenLength and segment's + // writtenLength is less than one block, we assume that these + // missing bytes are already downloaded. + if(segment->getWrittenLength() < writtenLength && + writtenLength-segment->getWrittenLength() < piece->getBlockLength()) { + segment->updateWrittenLength(writtenLength-segment->getWrittenLength()); + } + } + } return segment; } @@ -178,7 +199,9 @@ void SegmentMan::getInFlightSegment(std::deque<SharedHandle<Segment> >& segments } SegmentHandle SegmentMan::getSegment(cuid_t cuid) { - PieceHandle piece = _pieceStorage->getMissingPiece(); + PieceHandle piece = + _pieceStorage->getSparseMissingUnusedPiece + (_ignoreBitfield.getFilterBitfield(),_ignoreBitfield.getBitfieldLength()); if(piece.isNull()) { PeerStatHandle myPeerStat = getPeerStat(cuid); if(myPeerStat.isNull()) { @@ -219,6 +242,11 @@ void SegmentMan::cancelSegment(cuid_t cuid) { itr != usedSegmentEntries.end();) { if((*itr)->cuid == cuid) { _pieceStorage->cancelPiece((*itr)->segment->getPiece()); + _segmentWrittenLengthMemo[(*itr)->segment->getIndex()] = + (*itr)->segment->getWrittenLength(); + logger->debug("Memorized segment index=%u, writtenLength=%u", + (*itr)->segment->getIndex(), + (*itr)->segment->getWrittenLength()); itr = usedSegmentEntries.erase(itr); } else { ++itr; @@ -356,4 +384,14 @@ size_t SegmentMan::countFreePieceFrom(size_t index) const return _downloadContext->getNumPieces()-index; } +void SegmentMan::ignoreSegmentFor(const SharedHandle<FileEntry>& fileEntry) +{ + _ignoreBitfield.addFilter(fileEntry->getOffset(), fileEntry->getLength()); +} + +void SegmentMan::recognizeSegmentFor(const SharedHandle<FileEntry>& fileEntry) +{ + _ignoreBitfield.removeFilter(fileEntry->getOffset(), fileEntry->getLength()); +} + } // namespace aria2 diff --git a/src/SegmentMan.h b/src/SegmentMan.h index db9f68e9..ccf77d50 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -43,6 +43,7 @@ #include "SharedHandle.h" #include "TimeA2.h" #include "Command.h" +#include "BitfieldMan.h" namespace aria2 { @@ -53,6 +54,7 @@ class PeerStat; class DownloadContext; class PieceStorage; class Piece; +class FileEntry; class SegmentEntry { public: @@ -82,6 +84,10 @@ private: SegmentEntries usedSegmentEntries; + // Remember writtenLength for each segment. The key is an index of a + // segment. The value is writtenLength for that segment. + std::map<size_t, size_t> _segmentWrittenLengthMemo; + std::deque<SharedHandle<PeerStat> > peerStats; // key: PeerStat's cuid, value: its download speed @@ -91,6 +97,8 @@ private: unsigned int _cachedDlspd; + BitfieldMan _ignoreBitfield; + SharedHandle<Segment> checkoutSegment(cuid_t cuid, const SharedHandle<Piece>& piece); @@ -201,6 +209,12 @@ public: uint64_t calculateSessionDownloadLength() const; size_t countFreePieceFrom(size_t index) const; + + // Excludes segments that fileEntry covers from segment selection. + void ignoreSegmentFor(const SharedHandle<FileEntry>& fileEntry); + + // Includes segments that fileEntry covers in segment selection. + void recognizeSegmentFor(const SharedHandle<FileEntry>& fileEntry); }; typedef SharedHandle<SegmentMan> SegmentManHandle; diff --git a/src/SingleFileDownloadContext.h b/src/SingleFileDownloadContext.h index 1375ba5c..7f07d9a9 100644 --- a/src/SingleFileDownloadContext.h +++ b/src/SingleFileDownloadContext.h @@ -93,7 +93,11 @@ public: virtual FILE_MODE getFileMode() const { - return SINGLE; + if(_fileEntries.size() == 1) { + return SINGLE; + } else { + return MULTI; + } } virtual size_t getPieceLength() const diff --git a/src/StreamFileAllocationEntry.cc b/src/StreamFileAllocationEntry.cc index e514457b..5caf81d5 100644 --- a/src/StreamFileAllocationEntry.cc +++ b/src/StreamFileAllocationEntry.cc @@ -41,7 +41,6 @@ #include "Request.h" #include "prefs.h" #include "RequestGroup.h" -#include "InitiateConnectionCommandFactory.h" #include "DownloadContext.h" #include "Command.h" @@ -68,16 +67,7 @@ void StreamFileAllocationEntry::prepareForNextAction(std::deque<Command*>& comma // try remaining uris _requestGroup->createNextCommandWithAdj(commands, e, -1); } else { - if(_currentRequest.isNull()) { - _requestGroup->createNextCommandWithAdj(commands, e, 0); - } else { - Command* command = - InitiateConnectionCommandFactory::createInitiateConnectionCommand - (e->newCUID(), _currentRequest, _requestGroup, e); - e->setNoWait(true); - commands.push_back(command); - _requestGroup->createNextCommandWithAdj(commands, e, -1); - } + _requestGroup->createNextCommandWithAdj(commands, e, 0); } } diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index 701bb108..87a51c58 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -223,6 +223,7 @@ TrackerWatcherCommand::createRequestGroup(const std::string& uri) A2STR::NIL, TRACKER_ANNOUNCE_FILE)); dctx->setDir(A2STR::NIL); + dctx->getFileEntries().front()->setUris(uris); rg->setDownloadContext(dctx); SharedHandle<DiskWriterFactory> dwf(new ByteArrayDiskWriterFactory()); rg->setDiskWriterFactory(dwf); diff --git a/src/UnknownLengthPieceStorage.cc b/src/UnknownLengthPieceStorage.cc index 2bbc2061..369767c7 100644 --- a/src/UnknownLengthPieceStorage.cc +++ b/src/UnknownLengthPieceStorage.cc @@ -100,7 +100,8 @@ SharedHandle<Piece> UnknownLengthPieceStorage::getMissingFastPiece #endif // ENABLE_BITTORRENT -PieceHandle UnknownLengthPieceStorage::getMissingPiece() +SharedHandle<Piece> UnknownLengthPieceStorage::getSparseMissingUnusedPiece +(const unsigned char* ignoreBitfield, size_t length) { if(_downloadFinished) { return SharedHandle<Piece>(); @@ -116,7 +117,7 @@ PieceHandle UnknownLengthPieceStorage::getMissingPiece() PieceHandle UnknownLengthPieceStorage::getMissingPiece(size_t index) { if(index == 0) { - return getMissingPiece(); + return getSparseMissingUnusedPiece(0, 0); } else { return SharedHandle<Piece>(); } diff --git a/src/UnknownLengthPieceStorage.h b/src/UnknownLengthPieceStorage.h index f71e195b..dcf05130 100644 --- a/src/UnknownLengthPieceStorage.h +++ b/src/UnknownLengthPieceStorage.h @@ -101,7 +101,8 @@ public: /** * Returns a missing piece if available. Otherwise returns 0; */ - virtual SharedHandle<Piece> getMissingPiece(); + virtual SharedHandle<Piece> getSparseMissingUnusedPiece + (const unsigned char* ignoreBitfield, size_t length); /** * Returns a missing piece whose index is index. diff --git a/src/array_fun.h b/src/array_fun.h index a8990b9d..c6d53475 100644 --- a/src/array_fun.h +++ b/src/array_fun.h @@ -154,6 +154,13 @@ struct And static inline returnType apply(T lhs, T rhs) { return lhs&rhs; } }; +template<typename T> +struct Or +{ + typedef T returnType; + static inline returnType apply(T lhs, T rhs) { return lhs|rhs; } +}; + template<typename T> struct Negate { @@ -184,6 +191,13 @@ operator&(const L& l, const R& r) return BinExpr<L, And<typename L::returnType>, R>(l, r); } +template<typename L, typename R> +BinExpr<L, Or<typename L::returnType>, R> +operator|(const L& l, const R& r) +{ + return BinExpr<L, Or<typename L::returnType>, R>(l, r); +} + template<typename A> UnExpr<Negate<typename A::returnType>, A> operator~(const A& a) diff --git a/src/bitfield.h b/src/bitfield.h index e1b0cfaa..23eb6bb9 100644 --- a/src/bitfield.h +++ b/src/bitfield.h @@ -54,7 +54,8 @@ inline unsigned char lastByteMask(size_t nbits) } // Returns true if index-th bits is set. Otherwise returns false. -inline bool test(const unsigned char* bitfield, size_t nbits, size_t index) +template<typename Array> +inline bool test(const Array& bitfield, size_t nbits, size_t index) { assert(index < nbits); unsigned char mask = 128 >> (index%8); diff --git a/src/download_helper.cc b/src/download_helper.cc index d3612662..b232f33d 100644 --- a/src/download_helper.cc +++ b/src/download_helper.cc @@ -187,6 +187,7 @@ static SharedHandle<RequestGroup> createRequestGroup strconcat(option->get(PREF_DIR), "/", option->get(PREF_OUT)):A2STR::NIL)); dctx->setDir(option->get(PREF_DIR)); + dctx->getFileEntries().front()->setUris(uris); rg->setDownloadContext(dctx); return rg; } diff --git a/test/DownloadContextTest.cc b/test/DownloadContextTest.cc new file mode 100644 index 00000000..bfe88400 --- /dev/null +++ b/test/DownloadContextTest.cc @@ -0,0 +1,44 @@ +#include "DownloadContext.h" + +#include <cppunit/extensions/HelperMacros.h> + +#include "FileEntry.h" +#include "MockDownloadContext.h" + +namespace aria2 { + +class DownloadContextTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DownloadContextTest); + CPPUNIT_TEST(testFindFileEntryByOffset); + CPPUNIT_TEST_SUITE_END(); +public: + void testFindFileEntryByOffset(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DownloadContextTest); + +void DownloadContextTest::testFindFileEntryByOffset() +{ + MockDownloadContext ctx; + + CPPUNIT_ASSERT(ctx.findFileEntryByOffset(0).isNull()); + + ctx.addFileEntry(SharedHandle<FileEntry>(new FileEntry("file1",1000,0))); + ctx.addFileEntry(SharedHandle<FileEntry>(new FileEntry("file2",0,1000))); + ctx.addFileEntry(SharedHandle<FileEntry>(new FileEntry("file3",0,1000))); + ctx.addFileEntry(SharedHandle<FileEntry>(new FileEntry("file4",2000,1000))); + ctx.addFileEntry(SharedHandle<FileEntry>(new FileEntry("file5",3000,3000))); + ctx.addFileEntry(SharedHandle<FileEntry>(new FileEntry("file6",0,6000))); + + CPPUNIT_ASSERT_EQUAL(std::string("file1"), + ctx.findFileEntryByOffset(0)->getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("file4"), + ctx.findFileEntryByOffset(1500)->getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("file5"), + ctx.findFileEntryByOffset(5999)->getPath()); + CPPUNIT_ASSERT(ctx.findFileEntryByOffset(6000).isNull()); +} + +} // namespace aria2 diff --git a/test/Makefile.am b/test/Makefile.am index a9805744..18e03245 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -70,7 +70,9 @@ aria2c_SOURCES = AllTest.cc\ LongestSequencePieceSelectorTest.cc\ a2algoTest.cc\ bitfieldTest.cc\ - BDETest.cc + BDETest.cc\ + DownloadContextTest.cc\ + MockDownloadContext.h if ENABLE_XML_RPC aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index 142c96eb..a11a66bb 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -200,8 +200,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ SequentialPickerTest.cc RarestPieceSelectorTest.cc \ PieceStatManTest.cc InOrderPieceSelector.h \ LongestSequencePieceSelectorTest.cc a2algoTest.cc \ - bitfieldTest.cc BDETest.cc \ - XmlRpcRequestParserControllerTest.cc \ + bitfieldTest.cc BDETest.cc DownloadContextTest.cc \ + MockDownloadContext.h XmlRpcRequestParserControllerTest.cc \ XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \ FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \ Sqlite3MozCookieParserTest.cc MessageDigestHelperTest.cc \ @@ -377,9 +377,9 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \ RarestPieceSelectorTest.$(OBJEXT) PieceStatManTest.$(OBJEXT) \ LongestSequencePieceSelectorTest.$(OBJEXT) \ a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) BDETest.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_4) $(am__objects_5) $(am__objects_6) \ - $(am__objects_7) + DownloadContextTest.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) $(am__objects_3) $(am__objects_4) \ + $(am__objects_5) $(am__objects_6) $(am__objects_7) aria2c_OBJECTS = $(am_aria2c_OBJECTS) am__DEPENDENCIES_1 = aria2c_DEPENDENCIES = ../src/libaria2c.a ../src/download_helper.o \ @@ -607,7 +607,8 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \ SequentialPickerTest.cc RarestPieceSelectorTest.cc \ PieceStatManTest.cc InOrderPieceSelector.h \ LongestSequencePieceSelectorTest.cc a2algoTest.cc \ - bitfieldTest.cc BDETest.cc $(am__append_1) $(am__append_2) \ + bitfieldTest.cc BDETest.cc DownloadContextTest.cc \ + MockDownloadContext.h $(am__append_1) $(am__append_2) \ $(am__append_3) $(am__append_4) $(am__append_5) \ $(am__append_6) $(am__append_7) @@ -773,6 +774,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerStorageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectDiskAdaptorTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadContextTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadHandlerFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadHelperTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ExceptionTest.Po@am__quote@ diff --git a/test/MockDownloadContext.h b/test/MockDownloadContext.h new file mode 100644 index 00000000..b01fc8c0 --- /dev/null +++ b/test/MockDownloadContext.h @@ -0,0 +1,67 @@ +#ifndef _D_MOCK_DOWNLOAD_CONTEXT_H_ +#define _D_MOCK_DOWNLOAD_CONTEXT_H_ + +#include "DownloadContext.h" +#include "A2STR.h" + +namespace aria2 { + +class MockDownloadContext:public DownloadContext +{ +private: + std::deque<std::string> _pieceHashes; +public: + virtual const std::string& getPieceHash(size_t index) const + { + return A2STR::NIL; + } + + virtual const std::deque<std::string>& getPieceHashes() const + { + return _pieceHashes; + } + + virtual uint64_t getTotalLength() const + { + return 0; + } + + virtual bool knowsTotalLength() const + { + return false; + } + + virtual FILE_MODE getFileMode() const + { + return MULTI; + } + + virtual size_t getPieceLength() const + { + return 0; + } + + virtual size_t getNumPieces() const + { + return 0; + } + + virtual const std::string& getPieceHashAlgo() const + { + return A2STR::NIL; + } + + virtual std::string getActualBasePath() const + { + return A2STR::NIL; + } + + void addFileEntry(const SharedHandle<FileEntry>& fileEntry) + { + _fileEntries.push_back(fileEntry); + } +}; + +} // namespace aria2 + +#endif // _D_MOCK_DOWNLOAD_CONTEXT_H_