diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2009-11-23 13:17:48 +0000 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2009-11-23 13:17:48 +0000 |
| commit | 6e8074c0876fa97e1ba868e5053fc50cd8f487f5 (patch) | |
| tree | 9cc95e0d2df514dbb9280de586d0451b98a66229 | |
| parent | 95370fc11f82d3f351e3c4e7a5d462d360c2ac65 (diff) | |
2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added BitTorrent Magnet Link support. Base32 encoded link is not
supported yet. Fixed typo in method name in RequestGroup. In
metadataGetMode, don't show "Your share ratio was ..." message.
* src/DefaultBtInteractive.cc
* src/DefaultBtInteractive.h
* src/DownloadHandlerFactory.cc
* src/DownloadHandlerFactory.h
* src/HandshakeExtensionMessage.cc
* src/Makefile.am
* src/Metalink2RequestGroup.cc
* src/PeerInteractionCommand.cc
* src/RequestGroup.cc
* src/RequestGroup.h
* src/UTMetadataPostDownloadHandler.cc
* src/UTMetadataPostDownloadHandler.h
* src/download_helper.cc
* test/HandshakeExtensionMessageTest.cc
* test/Makefile.am
* test/UTMetadataPostDownloadHandlerTest.cc
* test/UTMetadataRejectExtensionMessageTest.cc
| -rw-r--r-- | ChangeLog | 23 | ||||
| -rw-r--r-- | src/DefaultBtInteractive.cc | 86 | ||||
| -rw-r--r-- | src/DefaultBtInteractive.h | 23 | ||||
| -rw-r--r-- | src/DownloadHandlerFactory.cc | 12 | ||||
| -rw-r--r-- | src/DownloadHandlerFactory.h | 31 | ||||
| -rw-r--r-- | src/HandshakeExtensionMessage.cc | 12 | ||||
| -rw-r--r-- | src/Makefile.am | 3 | ||||
| -rw-r--r-- | src/Makefile.in | 14 | ||||
| -rw-r--r-- | src/Metalink2RequestGroup.cc | 4 | ||||
| -rw-r--r-- | src/PeerInteractionCommand.cc | 36 | ||||
| -rw-r--r-- | src/RequestGroup.cc | 81 | ||||
| -rw-r--r-- | src/RequestGroup.h | 5 | ||||
| -rw-r--r-- | src/UTMetadataPostDownloadHandler.cc | 109 | ||||
| -rw-r--r-- | src/UTMetadataPostDownloadHandler.h | 61 | ||||
| -rw-r--r-- | src/download_helper.cc | 42 | ||||
| -rw-r--r-- | test/HandshakeExtensionMessageTest.cc | 1 | ||||
| -rw-r--r-- | test/Makefile.am | 3 | ||||
| -rw-r--r-- | test/Makefile.in | 12 | ||||
| -rw-r--r-- | test/UTMetadataPostDownloadHandlerTest.cc | 111 | ||||
| -rw-r--r-- | test/UTMetadataRejectExtensionMessageTest.cc | 9 |
20 files changed, 619 insertions, 59 deletions
@@ -1,5 +1,28 @@ 2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> + Added BitTorrent Magnet Link support. Base32 encoded link is not + supported yet. Fixed typo in method name in RequestGroup. In + metadataGetMode, don't show "Your share ratio was ..." message. + * src/DefaultBtInteractive.cc + * src/DefaultBtInteractive.h + * src/DownloadHandlerFactory.cc + * src/DownloadHandlerFactory.h + * src/HandshakeExtensionMessage.cc + * src/Makefile.am + * src/Metalink2RequestGroup.cc + * src/PeerInteractionCommand.cc + * src/RequestGroup.cc + * src/RequestGroup.h + * src/UTMetadataPostDownloadHandler.cc + * src/UTMetadataPostDownloadHandler.h + * src/download_helper.cc + * test/HandshakeExtensionMessageTest.cc + * test/Makefile.am + * test/UTMetadataPostDownloadHandlerTest.cc + * test/UTMetadataRejectExtensionMessageTest.cc + +2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> + In metadataGetMode, don't show SEEDING. * src/ConsoleStatCalc.cc diff --git a/src/DefaultBtInteractive.cc b/src/DefaultBtInteractive.cc index 3dd62096..df70e063 100644 --- a/src/DefaultBtInteractive.cc +++ b/src/DefaultBtInteractive.cc @@ -69,6 +69,8 @@ #include "RequestGroup.h" #include "RequestGroupMan.h" #include "bittorrent_helper.h" +#include "UTMetadataRequestFactory.h" +#include "UTMetadataRequestTracker.h" namespace aria2 { @@ -78,6 +80,7 @@ DefaultBtInteractive::DefaultBtInteractive : _downloadContext(downloadContext), peer(peer), + _metadataGetMode(false), logger(LogFactory::getInstance()), allowedFastSetSize(10), keepAliveInterval(120), @@ -146,11 +149,15 @@ void DefaultBtInteractive::doPostHandshakeProcessing() { if(peer->isExtendedMessagingEnabled()) { addHandshakeExtendedMessageToQueue(); } - addBitfieldMessageToQueue(); + if(!_metadataGetMode) { + addBitfieldMessageToQueue(); + } if(peer->isDHTEnabled() && _dhtEnabled) { addPortMessageToQueue(); } - addAllowedFastMessageToQueue(); + if(!_metadataGetMode) { + addAllowedFastMessageToQueue(); + } sendPendingMessage(); } @@ -365,6 +372,16 @@ void DefaultBtInteractive::addRequests() { void DefaultBtInteractive::cancelAllPiece() { btRequestFactory->removeAllTargetPiece(); + if(_metadataGetMode && _downloadContext->getTotalLength() > 0) { + std::vector<size_t> metadataRequests = + _utMetadataRequestTracker->getAllTrackedIndex(); + for(std::vector<size_t>::const_iterator i = metadataRequests.begin(); + i != metadataRequests.end(); ++i) { + logger->debug("Cancel metadata: piece=%lu", + static_cast<unsigned long>(*i)); + _pieceStorage->cancelPiece(_pieceStorage->getPiece(*i)); + } + } } void DefaultBtInteractive::sendPendingMessage() { @@ -439,29 +456,58 @@ void DefaultBtInteractive::addPeerExchangeMessage() } void DefaultBtInteractive::doInteractionProcessing() { - checkActiveInteraction(); + if(_metadataGetMode) { + sendKeepAlive(); + _numReceivedMessage = receiveMessages(); + // PieceStorage is re-initialized with metadata_size in + // HandshakeExtensionMessage::doReceivedAction(). + _pieceStorage = + _downloadContext->getOwnerRequestGroup()->getPieceStorage(); + + if(peer->getExtensionMessageID("ut_metadata") && + _downloadContext->getTotalLength() > 0) { + size_t num = _utMetadataRequestTracker->avail(); + if(num > 0) { + std::deque<SharedHandle<BtMessage> > requests; + _utMetadataRequestFactory->create(requests, num, _pieceStorage); + dispatcher->addMessageToQueue(requests); + } + if(_perSecCheckPoint.elapsed(1)) { + _perSecCheckPoint.reset(); + // Drop timeout request after queuing message to give a chance + // to other connection to request piece. + std::vector<size_t> indexes = + _utMetadataRequestTracker->removeTimeoutEntry(); + for(std::vector<size_t>::const_iterator i = indexes.begin(); + i != indexes.end(); ++i) { + _pieceStorage->cancelPiece(_pieceStorage->getPiece(*i)); + } + } + } + } else { + checkActiveInteraction(); - decideChoking(); + decideChoking(); - detectMessageFlooding(); + detectMessageFlooding(); - if(_perSecCheckPoint.elapsed(1)) { - _perSecCheckPoint.reset(); - dispatcher->checkRequestSlotAndDoNecessaryThing(); - } - checkHave(); + if(_perSecCheckPoint.elapsed(1)) { + _perSecCheckPoint.reset(); + dispatcher->checkRequestSlotAndDoNecessaryThing(); + } + checkHave(); - sendKeepAlive(); + sendKeepAlive(); - _numReceivedMessage = receiveMessages(); + _numReceivedMessage = receiveMessages(); - btRequestFactory->removeCompletedPiece(); + btRequestFactory->removeCompletedPiece(); - decideInterest(); - if(!_pieceStorage->downloadFinished()) { - addRequests(); + decideInterest(); + if(!_pieceStorage->downloadFinished()) { + addRequests(); + } } - if(peer->getExtensionMessageID("ut_pex") && _utPexEnabled) { addPeerExchangeMessage(); } @@ -491,7 +537,11 @@ size_t DefaultBtInteractive::countReceivedMessageInIteration() const size_t DefaultBtInteractive::countOutstandingRequest() { - return dispatcher->countOutstandingRequest(); + if(_metadataGetMode) { + return _utMetadataRequestTracker->count(); + } else { + return dispatcher->countOutstandingRequest(); + } } void DefaultBtInteractive::setBtRuntime diff --git a/src/DefaultBtInteractive.h b/src/DefaultBtInteractive.h index 2f5d1b4b..923e5d07 100644 --- a/src/DefaultBtInteractive.h +++ b/src/DefaultBtInteractive.h @@ -59,6 +59,8 @@ class ExtensionMessageRegistry; class DHTNode; class Logger; class RequestGroupMan; +class UTMetadataRequestFactory; +class UTMetadataRequestTracker; class FloodingStat { private: @@ -114,6 +116,10 @@ private: SharedHandle<BtMessageFactory> messageFactory; SharedHandle<ExtensionMessageFactory> _extensionMessageFactory; SharedHandle<ExtensionMessageRegistry> _extensionMessageRegistry; + SharedHandle<UTMetadataRequestFactory> _utMetadataRequestFactory; + SharedHandle<UTMetadataRequestTracker> _utMetadataRequestTracker; + + bool _metadataGetMode; WeakHandle<DHTNode> _localNode; @@ -230,6 +236,23 @@ public: } void setRequestGroupMan(const WeakHandle<RequestGroupMan>& rgman); + + void setUTMetadataRequestTracker + (const SharedHandle<UTMetadataRequestTracker>& tracker) + { + _utMetadataRequestTracker = tracker; + } + + void setUTMetadataRequestFactory + (const SharedHandle<UTMetadataRequestFactory>& factory) + { + _utMetadataRequestFactory = factory; + } + + void enableMetadataGetMode() + { + _metadataGetMode = true; + } }; typedef SharedHandle<DefaultBtInteractive> DefaultBtInteractiveHandle; diff --git a/src/DownloadHandlerFactory.cc b/src/DownloadHandlerFactory.cc index 15a8cd98..128372a5 100644 --- a/src/DownloadHandlerFactory.cc +++ b/src/DownloadHandlerFactory.cc @@ -38,6 +38,7 @@ #include "BtPostDownloadHandler.h" #include "DownloadHandlerConstants.h" #include "ContentTypeRequestGroupCriteria.h" +#include "UTMetadataPostDownloadHandler.h" namespace aria2 { @@ -59,6 +60,8 @@ DownloadHandlerFactory::_btPreDownloadHandler; BtPostDownloadHandlerHandle DownloadHandlerFactory::_btPostDownloadHandler; +SharedHandle<UTMetadataPostDownloadHandler> +DownloadHandlerFactory::_btMetadataPostDownloadHandler; #endif // ENABLE_BITTORRENT #ifdef ENABLE_METALINK @@ -118,6 +121,15 @@ BtPostDownloadHandlerHandle DownloadHandlerFactory::getBtPostDownloadHandler() return _btPostDownloadHandler; } +SharedHandle<UTMetadataPostDownloadHandler> +DownloadHandlerFactory::getUTMetadataPostDownloadHandler() +{ + if(_btMetadataPostDownloadHandler.isNull()) { + _btMetadataPostDownloadHandler.reset(new UTMetadataPostDownloadHandler()); + } + return _btMetadataPostDownloadHandler; +} + #endif // ENABLE_BITTORRENT } // namespace aria2 diff --git a/src/DownloadHandlerFactory.h b/src/DownloadHandlerFactory.h index dd3247c0..0b3b7816 100644 --- a/src/DownloadHandlerFactory.h +++ b/src/DownloadHandlerFactory.h @@ -46,33 +46,48 @@ class MetalinkPostDownloadHandler; #endif // ENABLE_METALINK #ifdef ENABLE_BITTORRENT class BtPostDownloadHandler; +class UTMetadataPostDownloadHandler; #endif // ENABLE_BITTORRENT class DownloadHandlerFactory { private: #ifdef ENABLE_METALINK - static SharedHandle<MemoryBufferPreDownloadHandler> _metalinkPreDownloadHandler; + static SharedHandle<MemoryBufferPreDownloadHandler> + _metalinkPreDownloadHandler; - static SharedHandle<MetalinkPostDownloadHandler> _metalinkPostDownloadHandler; + static SharedHandle<MetalinkPostDownloadHandler> + _metalinkPostDownloadHandler; #endif // ENABLE_METALINK #ifdef ENABLE_BITTORRENT - static SharedHandle<MemoryBufferPreDownloadHandler> _btPreDownloadHandler; + static SharedHandle<MemoryBufferPreDownloadHandler> + _btPreDownloadHandler; - static SharedHandle<BtPostDownloadHandler> _btPostDownloadHandler; + static SharedHandle<BtPostDownloadHandler> + _btPostDownloadHandler; + + static SharedHandle<UTMetadataPostDownloadHandler> + _btMetadataPostDownloadHandler; #endif // ENABLE_BITTORRENT public: #ifdef ENABLE_METALINK - static SharedHandle<MemoryBufferPreDownloadHandler> getMetalinkPreDownloadHandler(); + static SharedHandle<MemoryBufferPreDownloadHandler> + getMetalinkPreDownloadHandler(); - static SharedHandle<MetalinkPostDownloadHandler> getMetalinkPostDownloadHandler(); + static SharedHandle<MetalinkPostDownloadHandler> + getMetalinkPostDownloadHandler(); #endif // ENABLE_METALINK #ifdef ENABLE_BITTORRENT - static SharedHandle<MemoryBufferPreDownloadHandler> getBtPreDownloadHandler(); + static SharedHandle<MemoryBufferPreDownloadHandler> + getBtPreDownloadHandler(); + + static SharedHandle<BtPostDownloadHandler> + getBtPostDownloadHandler(); - static SharedHandle<BtPostDownloadHandler> getBtPostDownloadHandler(); + static SharedHandle<UTMetadataPostDownloadHandler> + getUTMetadataPostDownloadHandler(); #endif // ENABLE_BITTORRENT }; diff --git a/src/HandshakeExtensionMessage.cc b/src/HandshakeExtensionMessage.cc index fd722e78..74c713be 100644 --- a/src/HandshakeExtensionMessage.cc +++ b/src/HandshakeExtensionMessage.cc @@ -110,8 +110,15 @@ void HandshakeExtensionMessage::doReceivedAction() const std::map<std::string, uint8_t>::value_type& vt = *itr; _peer->setExtension(vt.first, vt.second); } + BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); + if(!attrs.containsKey(bittorrent::METADATA) && + !_peer->getExtensionMessageID("ut_metadata")) { + // TODO In metadataGetMode, if peer dont' support metadata + // transfer, should we drop connection? There is a possibility + // that peer can still tell us peers using PEX. + throw DL_ABORT_EX("Peer doesn't support ut_metadata extension. Goodbye."); + } if(_metadataSize > 0) { - BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); if(attrs.containsKey(bittorrent::METADATA_SIZE)) { if(_metadataSize != (size_t)attrs[bittorrent::METADATA_SIZE].i()) { throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?"); @@ -126,6 +133,9 @@ void HandshakeExtensionMessage::doReceivedAction() _dctx->getOwnerRequestGroup()->getPieceStorage(); pieceStorage->setEndGamePieceNum(0); } + } else { + throw DL_ABORT_EX("Peer didn't provide metadata_size." + " It seems that it doesn't have whole metadata."); } } diff --git a/src/Makefile.am b/src/Makefile.am index 1cfe5221..2f06976e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -351,6 +351,9 @@ SRCS += PeerAbstractCommand.cc PeerAbstractCommand.h\ UTMetadataRequestExtensionMessage.h\ UTMetadataRejectExtensionMessage.cc UTMetadataRejectExtensionMessage.h\ UTMetadataDataExtensionMessage.cc UTMetadataDataExtensionMessage.h\ + UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\ + UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\ + UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\ DHTNode.cc DHTNode.h\ DHTBucket.cc DHTBucket.h\ DHTRoutingTable.cc DHTRoutingTable.h\ diff --git a/src/Makefile.in b/src/Makefile.in index 1bb60b99..eb3a5bcb 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -150,6 +150,9 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ UTMetadataRequestExtensionMessage.h\ @ENABLE_BITTORRENT_TRUE@ UTMetadataRejectExtensionMessage.cc UTMetadataRejectExtensionMessage.h\ @ENABLE_BITTORRENT_TRUE@ UTMetadataDataExtensionMessage.cc UTMetadataDataExtensionMessage.h\ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTracker.cc UTMetadataRequestTracker.h\ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactory.cc UTMetadataRequestFactory.h\ +@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandler.cc UTMetadataPostDownloadHandler.h\ @ENABLE_BITTORRENT_TRUE@ DHTNode.cc DHTNode.h\ @ENABLE_BITTORRENT_TRUE@ DHTBucket.cc DHTBucket.h\ @ENABLE_BITTORRENT_TRUE@ DHTRoutingTable.cc DHTRoutingTable.h\ @@ -501,7 +504,10 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ UTMetadataRejectExtensionMessage.cc \ UTMetadataRejectExtensionMessage.h \ UTMetadataDataExtensionMessage.cc \ - UTMetadataDataExtensionMessage.h DHTNode.cc DHTNode.h \ + UTMetadataDataExtensionMessage.h UTMetadataRequestTracker.cc \ + UTMetadataRequestTracker.h UTMetadataRequestFactory.cc \ + UTMetadataRequestFactory.h UTMetadataPostDownloadHandler.cc \ + UTMetadataPostDownloadHandler.h DHTNode.cc DHTNode.h \ DHTBucket.cc DHTBucket.h DHTRoutingTable.cc DHTRoutingTable.h \ DHTMessageEntry.cc DHTMessageEntry.h DHTMessageDispatcher.h \ DHTMessageDispatcherImpl.cc DHTMessageDispatcherImpl.h \ @@ -660,6 +666,9 @@ am__objects_6 = @ENABLE_BITTORRENT_TRUE@ UTMetadataRequestExtensionMessage.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ UTMetadataRejectExtensionMessage.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ UTMetadataDataExtensionMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTracker.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactory.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandler.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DHTNode.$(OBJEXT) DHTBucket.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DHTRoutingTable.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DHTMessageEntry.$(OBJEXT) \ @@ -1529,8 +1538,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/URIResult.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataDataExtensionMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataExtensionMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataPostDownloadHandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRejectExtensionMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRequestExtensionMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRequestFactory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRequestTracker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.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@ diff --git a/src/Metalink2RequestGroup.cc b/src/Metalink2RequestGroup.cc index 8e74871c..78718341 100644 --- a/src/Metalink2RequestGroup.cc +++ b/src/Metalink2RequestGroup.cc @@ -179,8 +179,8 @@ Metalink2RequestGroup::createRequestGroup //dctx->setDir(_option->get(PREF_DIR)); dctx->getFirstFileEntry()->setUris(uris); torrentRg->setDownloadContext(dctx); - torrentRg->clearPreDowloadHandler(); - torrentRg->clearPostDowloadHandler(); + torrentRg->clearPreDownloadHandler(); + torrentRg->clearPostDownloadHandler(); // remove "metalink" from Accept Type list to avoid loop in tranparent // metalink torrentRg->removeAcceptType(RequestGroup::ACCEPT_METALINK); diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 7507be30..5cbf025f 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -71,6 +71,8 @@ #include "RequestGroupMan.h" #include "ExtensionMessageRegistry.h" #include "bittorrent_helper.h" +#include "UTMetadataRequestFactory.h" +#include "UTMetadataRequestTracker.h" namespace aria2 { @@ -103,14 +105,27 @@ PeerInteractionCommand::PeerInteractionCommand SharedHandle<PeerStorage> peerStorage = btRegistry->get(torrentAttrs[bittorrent::INFO_HASH].s())._peerStorage; + bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA); + SharedHandle<ExtensionMessageRegistry> exMsgRegistry (new ExtensionMessageRegistry()); + SharedHandle<UTMetadataRequestFactory> utMetadataRequestFactory; + SharedHandle<UTMetadataRequestTracker> utMetadataRequestTracker; + if(metadataGetMode) { + utMetadataRequestFactory.reset(new UTMetadataRequestFactory()); + utMetadataRequestTracker.reset(new UTMetadataRequestTracker()); + } + SharedHandle<DefaultExtensionMessageFactory> extensionMessageFactory (new DefaultExtensionMessageFactory(peer, exMsgRegistry)); extensionMessageFactory->setPeerStorage(peerStorage); extensionMessageFactory->setDownloadContext (_requestGroup->getDownloadContext()); + extensionMessageFactory->setUTMetadataRequestTracker + (utMetadataRequestTracker); + extensionMessageFactory->setBtRuntime(_btRuntime); + // PieceStorage will be set later. SharedHandle<DefaultBtMessageFactory> factory(new DefaultBtMessageFactory()); factory->setCuid(cuid); @@ -123,6 +138,9 @@ PeerInteractionCommand::PeerInteractionCommand factory->setRoutingTable(DHTRegistry::_routingTable); factory->setTaskQueue(DHTRegistry::_taskQueue); factory->setTaskFactory(DHTRegistry::_taskFactory); + if(metadataGetMode) { + factory->enableMetadataGetMode(); + } PeerConnectionHandle peerConnection; if(passedPeerConnection.isNull()) { @@ -174,7 +192,7 @@ PeerInteractionCommand::PeerInteractionCommand (getOption()->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL)); btInteractive->setRequestGroupMan(e->_requestGroupMan); btInteractive->setBtMessageFactory(factory); - if(torrentAttrs[bittorrent::PRIVATE].i() == 0) { + if(metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) { if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) { btInteractive->setUTPexEnabled(true); } @@ -184,6 +202,12 @@ PeerInteractionCommand::PeerInteractionCommand factory->setDHTEnabled(true); } } + btInteractive->setUTMetadataRequestFactory(utMetadataRequestFactory); + btInteractive->setUTMetadataRequestTracker(utMetadataRequestTracker); + if(metadataGetMode) { + btInteractive->enableMetadataGetMode(); + } + this->btInteractive = btInteractive; // reverse depends @@ -194,6 +218,16 @@ PeerInteractionCommand::PeerInteractionCommand extensionMessageFactory->setBtMessageDispatcher(dispatcher); extensionMessageFactory->setBtMessageFactory(factory); + if(metadataGetMode) { + utMetadataRequestFactory->setDownloadContext + (_requestGroup->getDownloadContext()); + utMetadataRequestFactory->setBtMessageDispatcher(dispatcher); + utMetadataRequestFactory->setBtMessageFactory(factory); + utMetadataRequestFactory->setPeer(peer); + utMetadataRequestFactory->setUTMetadataRequestTracker + (utMetadataRequestTracker); + } + peer->allocateSessionResource (_requestGroup->getDownloadContext()->getPieceLength(), _requestGroup->getDownloadContext()->getTotalLength()); diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index 8317592c..a07bd8ff 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -196,14 +196,15 @@ void RequestGroup::closeFile() } } -void RequestGroup::createInitialCommand(std::deque<Command*>& commands, - DownloadEngine* e) +void RequestGroup::createInitialCommand +(std::deque<Command*>& commands, DownloadEngine* e) { #ifdef ENABLE_BITTORRENT { if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) { const BDE& torrentAttrs = _downloadContext->getAttribute(bittorrent::BITTORRENT); + bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA); if(_option->getAsBool(PREF_DRY_RUN)) { throw DOWNLOAD_FAILURE_EXCEPTION ("Cancel BitTorrent download in dry-run context."); @@ -214,35 +215,45 @@ void RequestGroup::createInitialCommand(std::deque<Command*>& commands, throw DOWNLOAD_FAILURE_EXCEPTION (StringFormat ("InfoHash %s is already registered.", - util::toHex(torrentAttrs[bittorrent::INFO_HASH].s()).c_str()).str()); + bittorrent::getInfoHashString(_downloadContext).c_str()).str()); } - - if(e->_requestGroupMan->isSameFileBeingDownloaded(this)) { - throw DOWNLOAD_FAILURE_EXCEPTION - (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD, - _downloadContext->getBasePath().c_str()).str()); - } - initPieceStorage(); - if(_downloadContext->getFileEntries().size() > 1) { - _pieceStorage->setupFileFilter(); + if(metadataGetMode) { + // Use UnknownLengthPieceStorage. + initPieceStorage(); + } else { + if(e->_requestGroupMan->isSameFileBeingDownloaded(this)) { + throw DOWNLOAD_FAILURE_EXCEPTION + (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD, + _downloadContext->getBasePath().c_str()).str()); + } + initPieceStorage(); + if(_downloadContext->getFileEntries().size() > 1) { + _pieceStorage->setupFileFilter(); + } } - SharedHandle<DefaultBtProgressInfoFile> - progressInfoFile(new DefaultBtProgressInfoFile(_downloadContext, - _pieceStorage, - _option.get())); + SharedHandle<DefaultBtProgressInfoFile> progressInfoFile; + if(!metadataGetMode) { + progressInfoFile.reset(new DefaultBtProgressInfoFile(_downloadContext, + _pieceStorage, + _option.get())); + } BtRuntimeHandle btRuntime(new BtRuntime()); btRuntime->setMaxPeers(_option->getAsInt(PREF_BT_MAX_PEERS)); _btRuntime = btRuntime; - progressInfoFile->setBtRuntime(btRuntime); + if(!progressInfoFile.isNull()) { + progressInfoFile->setBtRuntime(btRuntime); + } SharedHandle<DefaultPeerStorage> peerStorage (new DefaultPeerStorage(_option.get())); peerStorage->setBtRuntime(btRuntime); peerStorage->setPieceStorage(_pieceStorage); _peerStorage = peerStorage; - progressInfoFile->setPeerStorage(peerStorage); + if(!progressInfoFile.isNull()) { + progressInfoFile->setPeerStorage(peerStorage); + } SharedHandle<DefaultBtAnnounce> btAnnounce (new DefaultBtAnnounce(_downloadContext, _option.get())); @@ -259,7 +270,21 @@ void RequestGroup::createInitialCommand(std::deque<Command*>& commands, peerStorage, btAnnounce, btRuntime, - progressInfoFile)); + (progressInfoFile.isNull()? + _progressInfoFile: + SharedHandle<BtProgressInfoFile> + (progressInfoFile)))); + if(metadataGetMode) { + std::deque<Command*> dhtCommands; + DHTSetup().setup(dhtCommands, e, _option.get()); + e->addCommand(dhtCommands); + + SharedHandle<CheckIntegrityEntry> entry + (new BtCheckIntegrityEntry(this)); + entry->onDownloadIncomplete(commands, e); + + return; + } // Remove the control file if download file doesn't exist if(progressInfoFile->exists() && !_pieceStorage->getDiskAdaptor()->fileExists()) { @@ -875,12 +900,12 @@ void RequestGroup::addPreDownloadHandler(const PreDownloadHandlerHandle& handler _preDownloadHandlers.push_back(handler); } -void RequestGroup::clearPostDowloadHandler() +void RequestGroup::clearPostDownloadHandler() { _postDownloadHandlers.clear(); } -void RequestGroup::clearPreDowloadHandler() +void RequestGroup::clearPreDownloadHandler() { _preDownloadHandlers.clear(); } @@ -934,11 +959,15 @@ void RequestGroup::reportDownloadFinished() #ifdef ENABLE_BITTORRENT if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) { TransferStat stat = calculateStat(); - double shareRatio = ((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0; - _logger->notice(MSG_SHARE_RATIO_REPORT, - shareRatio, - util::abbrevSize(stat.getAllTimeUploadLength()).c_str(), - util::abbrevSize(getCompletedLength()).c_str()); + double shareRatio = + ((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0; + const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT); + if(attrs.containsKey(bittorrent::METADATA)) { + _logger->notice(MSG_SHARE_RATIO_REPORT, + shareRatio, + util::abbrevSize(stat.getAllTimeUploadLength()).c_str(), + util::abbrevSize(getCompletedLength()).c_str()); + } } #endif // ENABLE_BITTORRENT } diff --git a/src/RequestGroup.h b/src/RequestGroup.h index 4f499be1..f390d1ae 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -169,6 +169,7 @@ private: // returns downloadresultcode::UNKNOWN_ERROR. downloadresultcode::RESULT downloadResult() const; public: + // The copy of option is stored in RequestGroup object. RequestGroup(const SharedHandle<Option>& option); ~RequestGroup(); @@ -334,13 +335,13 @@ public: void addPostDownloadHandler(const SharedHandle<PostDownloadHandler>& handler); - void clearPostDowloadHandler(); + void clearPostDownloadHandler(); void preDownloadProcessing(); void addPreDownloadHandler(const SharedHandle<PreDownloadHandler>& handler); - void clearPreDowloadHandler(); + void clearPreDownloadHandler(); void processCheckIntegrityEntry(std::deque<Command*>& commands, const SharedHandle<CheckIntegrityEntry>& entry, diff --git a/src/UTMetadataPostDownloadHandler.cc b/src/UTMetadataPostDownloadHandler.cc new file mode 100644 index 00000000..14f8ce6e --- /dev/null +++ b/src/UTMetadataPostDownloadHandler.cc @@ -0,0 +1,109 @@ +/* <!-- 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 "UTMetadataPostDownloadHandler.h" +#include "BDE.h" +#include "bittorrent_helper.h" +#include "RequestGroup.h" +#include "download_helper.h" +#include "RecoverableException.h" +#include "A2STR.h" +#include "DownloadContext.h" +#include "Logger.h" +#include "util.h" +#include "a2functional.h" +#include "DiskAdaptor.h" +#include "PieceStorage.h" + +namespace aria2 { + +bool UTMetadataPostDownloadHandler::Criteria::match +(const RequestGroup* requestGroup) const +{ + SharedHandle<DownloadContext> dctx = + requestGroup->getDownloadContext(); + if(dctx->hasAttribute(bittorrent::BITTORRENT)) { + const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT); + if(!attrs.containsKey(bittorrent::METADATA)) { + return true; + } + } + return false; +} + +UTMetadataPostDownloadHandler::UTMetadataPostDownloadHandler() +{ + setCriteria(SharedHandle<Criteria>(new Criteria())); +} + +void UTMetadataPostDownloadHandler::getNextRequestGroups +(std::deque<SharedHandle<RequestGroup> >& groups, RequestGroup* requestGroup) +{ + SharedHandle<DownloadContext> dctx = requestGroup->getDownloadContext(); + const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT); + std::string torrent = + strconcat("d4:info", + util::toString(requestGroup->getPieceStorage()->getDiskAdaptor()), + "e"); + try { + std::deque<SharedHandle<RequestGroup> > newRgs; + createRequestGroupForBitTorrent(newRgs, requestGroup->getOption(), + std::deque<std::string>(), torrent); + if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) { + for(std::deque<SharedHandle<RequestGroup> >::const_iterator i = + newRgs.begin(); i != newRgs.end(); ++i) { + SharedHandle<DownloadContext> newDctx = (*i)->getDownloadContext(); + if(!newDctx->hasAttribute(bittorrent::BITTORRENT)) { + continue; + } + BDE& newAttrs = newDctx->getAttribute(bittorrent::BITTORRENT); + if(attrs[bittorrent::INFO_HASH].s() != + newAttrs[bittorrent::INFO_HASH].s()) { + continue; + } + if(!newAttrs.containsKey(bittorrent::ANNOUNCE_LIST)) { + newAttrs[bittorrent::ANNOUNCE_LIST] = + attrs[bittorrent::ANNOUNCE_LIST]; + } + break; + } + } + + groups.insert(groups.end(), newRgs.begin(), newRgs.end()); + } catch(RecoverableException& e) { + _logger->error("Failed to parse BitTorrent metadata.", e); + } +} + +} // namespace aria2 diff --git a/src/UTMetadataPostDownloadHandler.h b/src/UTMetadataPostDownloadHandler.h new file mode 100644 index 00000000..3e566d32 --- /dev/null +++ b/src/UTMetadataPostDownloadHandler.h @@ -0,0 +1,61 @@ +/* <!-- 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_UT_METADATA_POST_DOWNLOAD_HANDLER_H_ +#define _D_UT_METADATA_POST_DOWNLOAD_HANDLER_H_ + +#include "PostDownloadHandler.h" +#include "RequestGroupCriteria.h" + +namespace aria2 { + +class UTMetadataPostDownloadHandler:public PostDownloadHandler +{ +private: + class Criteria:public RequestGroupCriteria + { + public: + virtual bool match(const RequestGroup* requestGroup) const; + }; +public: + UTMetadataPostDownloadHandler(); + + virtual void + getNextRequestGroups(std::deque<SharedHandle<RequestGroup> >& groups, + RequestGroup* requestGroup); +}; + +} // namespace aria2 + +#endif // _D_UT_METADATA_POST_DOWNLOAD_HANDLER_H_ diff --git a/src/download_helper.cc b/src/download_helper.cc index 900604ac..ee7c5bdf 100644 --- a/src/download_helper.cc +++ b/src/download_helper.cc @@ -61,8 +61,11 @@ #include "OptionHandler.h" #include "ByteArrayDiskWriter.h" #include "a2functional.h" +#include "ByteArrayDiskWriterFactory.h" #ifdef ENABLE_BITTORRENT # include "bittorrent_helper.h" +# include "BtConstants.h" +# include "UTMetadataPostDownloadHandler.h" #endif // ENABLE_BITTORRENT namespace aria2 { @@ -224,6 +227,35 @@ createBtRequestGroup(const std::string& torrentFilePath, return rg; } +static +SharedHandle<RequestGroup> +createBtMagnetRequestGroup(const std::string& magnetLink, + const SharedHandle<Option>& option, + const std::deque<std::string>& auxUris) +{ + SharedHandle<RequestGroup> rg(new RequestGroup(option)); + SharedHandle<DownloadContext> dctx + (new DownloadContext(METADATA_PIECE_SIZE, 0, + A2STR::NIL)); + dctx->setDir(A2STR::NIL); + // We only know info hash. Total Length is unknown at this moment. + dctx->markTotalLengthIsUnknown(); + rg->setFileAllocationEnabled(false); + rg->setPreLocalFileCheckEnabled(false); + bittorrent::parseMagnetLink(magnetLink, dctx); + dctx->getFirstFileEntry()->setPath + (dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s()); + rg->setDownloadContext(dctx); + dctx->setOwnerRequestGroup(rg.get()); + rg->clearPostDownloadHandler(); + rg->addPostDownloadHandler + (SharedHandle<UTMetadataPostDownloadHandler> + (new UTMetadataPostDownloadHandler())); + rg->setDiskWriterFactory + (SharedHandle<DiskWriterFactory>(new ByteArrayDiskWriterFactory())); + return rg; +} + void createRequestGroupForBitTorrent (std::deque<SharedHandle<RequestGroup> >& result, const SharedHandle<Option>& option, @@ -304,6 +336,16 @@ public: // We simply ignore it. LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e); } + } else if(_detector.guessTorrentMagnet(uri)) { + try { + SharedHandle<RequestGroup> group = + createBtMagnetRequestGroup(uri, _option, std::deque<std::string>()); + _requestGroups.push_back(group); + } catch(RecoverableException& e) { + // error occurred while parsing torrent file. + // We simply ignore it. + LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e); + } } #endif // ENABLE_BITTORRENT #ifdef ENABLE_METALINK diff --git a/test/HandshakeExtensionMessageTest.cc b/test/HandshakeExtensionMessageTest.cc index 03818f6e..69494674 100644 --- a/test/HandshakeExtensionMessageTest.cc +++ b/test/HandshakeExtensionMessageTest.cc @@ -108,6 +108,7 @@ void HandshakeExtensionMessageTest::testDoReceivedAction() msg.setTCPPort(6889); msg.setExtension("ut_pex", 1); msg.setExtension("a2_dht", 2); + msg.setExtension("ut_metadata", 3); msg.setMetadataSize(1024); msg.setPeer(peer); msg.setDownloadContext(dctx); diff --git a/test/Makefile.am b/test/Makefile.am index 9198d007..3485ae5a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -139,6 +139,9 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\ UTMetadataRequestExtensionMessageTest.cc\ UTMetadataDataExtensionMessageTest.cc\ UTMetadataRejectExtensionMessageTest.cc\ + UTMetadataRequestTrackerTest.cc\ + UTMetadataRequestFactoryTest.cc\ + UTMetadataPostDownloadHandlerTest.cc\ DefaultBtMessageFactoryTest.cc\ DefaultExtensionMessageFactoryTest.cc\ DHTNodeTest.cc\ diff --git a/test/Makefile.in b/test/Makefile.in index c8559c7e..b0659278 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -89,6 +89,9 @@ check_PROGRAMS = $(am__EXEEXT_1) @ENABLE_BITTORRENT_TRUE@ UTMetadataRequestExtensionMessageTest.cc\ @ENABLE_BITTORRENT_TRUE@ UTMetadataDataExtensionMessageTest.cc\ @ENABLE_BITTORRENT_TRUE@ UTMetadataRejectExtensionMessageTest.cc\ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTrackerTest.cc\ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactoryTest.cc\ +@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandlerTest.cc\ @ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.cc\ @ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.cc\ @ENABLE_BITTORRENT_TRUE@ DHTNodeTest.cc\ @@ -231,6 +234,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ UTMetadataRequestExtensionMessageTest.cc \ UTMetadataDataExtensionMessageTest.cc \ UTMetadataRejectExtensionMessageTest.cc \ + UTMetadataRequestTrackerTest.cc \ + UTMetadataRequestFactoryTest.cc \ + UTMetadataPostDownloadHandlerTest.cc \ DefaultBtMessageFactoryTest.cc \ DefaultExtensionMessageFactoryTest.cc DHTNodeTest.cc \ DHTBucketTest.cc DHTRoutingTableTest.cc \ @@ -306,6 +312,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ @ENABLE_BITTORRENT_TRUE@ UTMetadataRequestExtensionMessageTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ UTMetadataDataExtensionMessageTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ UTMetadataRejectExtensionMessageTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestTrackerTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTMetadataRequestFactoryTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTMetadataPostDownloadHandlerTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DHTNodeTest.$(OBJEXT) \ @@ -851,8 +860,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataDataExtensionMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataPostDownloadHandlerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRejectExtensionMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRequestExtensionMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRequestFactoryTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTMetadataRequestTrackerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@ diff --git a/test/UTMetadataPostDownloadHandlerTest.cc b/test/UTMetadataPostDownloadHandlerTest.cc new file mode 100644 index 00000000..30578005 --- /dev/null +++ b/test/UTMetadataPostDownloadHandlerTest.cc @@ -0,0 +1,111 @@ +#include "UTMetadataPostDownloadHandler.h" + +#include <cppunit/extensions/HelperMacros.h> + +#include "DownloadContext.h" +#include "RequestGroup.h" +#include "Option.h" +#include "FileEntry.h" +#include "bittorrent_helper.h" +#include "A2STR.h" +#include "ByteArrayDiskWriterFactory.h" +#include "PieceStorage.h" +#include "DiskAdaptor.h" +#include "util.h" +#include "MessageDigestHelper.h" + +namespace aria2 { + +class UTMetadataPostDownloadHandlerTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(UTMetadataPostDownloadHandlerTest); + CPPUNIT_TEST(testCanHandle); + CPPUNIT_TEST(testGetNextRequestGroups); + CPPUNIT_TEST_SUITE_END(); +private: + SharedHandle<Option> _option; + SharedHandle<DownloadContext> _dctx; + SharedHandle<RequestGroup> _requestGroup; +public: + void setUp() + { + _option.reset(new Option()); + _option->put("HELLO", "WORLD"); + _dctx.reset(new DownloadContext(0, 0, "something")); + _requestGroup.reset(new RequestGroup(_option)); + _requestGroup->setDownloadContext(_dctx); + } + + void testCanHandle(); + void testGetNextRequestGroups(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION( UTMetadataPostDownloadHandlerTest ); + +void UTMetadataPostDownloadHandlerTest::testCanHandle() +{ + UTMetadataPostDownloadHandler handler; + + CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get())); + + BDE attrs = BDE::dict(); + _dctx->setAttribute(bittorrent::BITTORRENT, attrs); + + CPPUNIT_ASSERT(handler.canHandle(_requestGroup.get())); + + // Only checks existence of METADATA key + attrs[bittorrent::METADATA] = A2STR::NIL; + + CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get())); +} + +void UTMetadataPostDownloadHandlerTest::testGetNextRequestGroups() +{ + std::string metadata = + "d6:lengthi384e4:name19:aria2-0.8.2.tar.bz212:piece lengthi128e" + "6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCe"; + unsigned char infoHash[20]; + MessageDigestHelper::digest + (infoHash, sizeof(infoHash), MessageDigestContext::SHA1, + reinterpret_cast<const unsigned char*>(metadata.data()), metadata.size()); + _dctx->getFirstFileEntry()->setLength(metadata.size()); + BDE attrs = BDE::dict(); + attrs[bittorrent::INFO_HASH] = std::string(&infoHash[0], &infoHash[20]); + BDE announceList = BDE::list(); + attrs[bittorrent::ANNOUNCE_LIST] = announceList; + _dctx->setAttribute(bittorrent::BITTORRENT, attrs); + _requestGroup->setDiskWriterFactory + (SharedHandle<DiskWriterFactory>(new ByteArrayDiskWriterFactory())); + _requestGroup->initPieceStorage(); + _requestGroup->getPieceStorage()->getDiskAdaptor()->writeData + (reinterpret_cast<const unsigned char*>(metadata.data()), metadata.size(), + 0); + + UTMetadataPostDownloadHandler handler; + std::deque<SharedHandle<RequestGroup> > results; + handler.getNextRequestGroups(results, _requestGroup.get()); + + CPPUNIT_ASSERT_EQUAL((size_t)1, results.size()); + SharedHandle<RequestGroup> newRg = results.front(); + SharedHandle<DownloadContext> newDctx = newRg->getDownloadContext(); + const BDE& newAttrs = newDctx->getAttribute(bittorrent::BITTORRENT); + CPPUNIT_ASSERT_EQUAL(util::toHex(attrs[bittorrent::INFO_HASH].s()), + util::toHex(newAttrs[bittorrent::INFO_HASH].s())); + CPPUNIT_ASSERT(newAttrs.containsKey(bittorrent::ANNOUNCE_LIST)); + CPPUNIT_ASSERT_EQUAL(_option->get("Hello"), + newRg->getOption()->get("Hello")); + + results.clear(); + + // See failure with bad metadata + metadata = "d6:lengthi384e4:name19:aria2-0.8.2.tar.bz212:piece lengthi128e"; + _requestGroup->initPieceStorage(); + _requestGroup->getPieceStorage()->getDiskAdaptor()->writeData + (reinterpret_cast<const unsigned char*>(metadata.data()), metadata.size(), + 0); + handler.getNextRequestGroups(results, _requestGroup.get()); + CPPUNIT_ASSERT(results.empty()); +} + +} // namespace aria2 diff --git a/test/UTMetadataRejectExtensionMessageTest.cc b/test/UTMetadataRejectExtensionMessageTest.cc index 831ccdf5..f80b8711 100644 --- a/test/UTMetadataRejectExtensionMessageTest.cc +++ b/test/UTMetadataRejectExtensionMessageTest.cc @@ -5,6 +5,7 @@ #include <cppunit/extensions/HelperMacros.h> #include "BtConstants.h" +#include "DlAbortEx.h" namespace aria2 { @@ -50,6 +51,14 @@ void UTMetadataRejectExtensionMessageTest::testToString() void UTMetadataRejectExtensionMessageTest::testDoReceivedAction() { + UTMetadataRejectExtensionMessage msg(1); + msg.setIndex(0); + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("exception must be thrown."); + } catch(DlAbortEx& e) { + // success + } } } // namespace aria2 |
