diff --git a/ChangeLog b/ChangeLog index d5f6f315..b83e335c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,201 @@ +2006-11-05 Tatsuhiro Tsujikawa + + To divide TorrentMan into 6 classes: BtContext, BtRuntime, + PeerStorage, PieceStorage, BtAnnounce and BtProgressInfoFile + + * src/TrackerWatcherComand.h: Made subclass of BtContextAwareCommand. + * src/SeedCheckCommand.cc: Use pieceStorage, btRuntime + * src/PeerAbstractCommand.h: Made subclass of BtContextAwareCommand. + * src/PeerAbstractCommand.cc: Use btRuntime. + * src/BtContextAwareCommand.h: New class. + * src/FileEntry.h: Added accessor methods for following variables. + (path): Made private. + (length): Made private. + (offset): Made private. + (extracted): Made private. + (requested): Made private. + (FileEntries): New definition. + (FileEntryHandle): New definition. + * src/FileEntry.cc: New file. + * src/HaveEraseCommand.h: Made subclass of BtContextAwareCommand. + * src/HaveEraseCommand.cc: Use btRuntime, pieceStorage. + * src/PeerChokeCommand.h: Made subclass of BtContextAwareCommand. + * src/PeerChokeCommand.cc: Use btRuntime, peerStorage, pieceStorage. + * src/PieceStorage.h: New file. + * src/PeerInteractionCommand.h: Use btContext. + * src/PeerInteractionCommand.cc: Use pieceStorage, peerStorage, + btRuntime. + * src/DefaultBtProgressInfoFile.h: New file. + * src/DefaultBtProgressInfoFile.cc: New file. + * src/File.cc + (Util.h): New include. + (mkdirs): New function. + * src/MultiDiskAdaptor.h + (mkdir): New function. + * src/PeerListProcessor.h + (Peers): Removed. + * src/PeerInteraction.h + (torrentMan): Removed. + (btContext): New variable. + (peerStorage): New variable. + (pieceStorage): New variable. + (btAnnounce): New variable. + (getTorrentMan): Removed. + (getBtContext): New function. + * src/PeerInteraction.cc: Use btContext, peerStorage, pieceStorage, + btAnnounce. + * src/HandshakeMessage.h + (TorrentMan.h): Removed. + * src/HandshakeMessage.cc: Use btContext. + * src/DefaultBtAnnounce.cc: New file. + * src/MultiDiskWriter.cc: Use the accessor methods of FileEntry. + * src/DefaultPieceStorage.cc: New file. + * src/DefaultBtContext.h: New file. + * src/TorrentRequestInfo.cc: Use btContext, pieceStorage. + Use the accessor methods of FileEntry. + * src/CookieBox.cc: Updated to use Util::slice(). + * src/PieceMessage.cc: Use btContext, pieceStorage. + * src/common.h (SharedHandle.h): New include. + * src/PeerMessage.cc (PeerMessage): Added btContext, peerStorage, + pieceStorage. + * src/TorrentAutoSaveCommand.h: Made subclass of BtContextAwareCommand. + * src/DiskAdaptor.h + (topDir): Removed. + (getFileEntryFromPath): Changed the return type to FileEntryHandle. + (setTopDir): Removed. + (getTopDir): Removed. + * src/BtContext.h: New file. + * src/DefaultPeerStorage.h: New file. + * src/PieceMessage.h (TorrentMan.h): Removed. + * src/RequestMessage.h (TorrentMan.h): Removed. + * src/TorrentDownloadEngine.h + (uploadLength): New variable. + (btContext): New variable. + (btRuntime): New variable. + (pieceStorage): New variable. + (peerStorage): New variable. + (btAnnounce): New variable. + (btProgressInfoFile): New variable. + (torrentMan): Removed. + (setBtContext): New function. + * src/TorrentDownloadEngine.cc: Use BtContext, BtRuntime, pieceStorage, + peerStorage, btAnnounce, btProgressInfoFile. + * src/Piece.h + (toString): New function. + (Pieces): New type definition. + * src/Peer.h + (active): New variable. + (Peer): Added active. + (activate): Set active to true. + (deactivate): Set active to false. + (isActive): New function. + (Peers): New type definition. + * src/DirectDiskAdaptor.cc + (getFilePath): Use the accessor methods of FileEntry. + * src/TorrentConsoleDownloadEngine.h + (afterEachIteration): New function. + * src/TorrentConsoleDownloadEngine.cc + (haltRequested): New variable. + (sendStatistics): Use pieceStorage, btRuntime. + (afterEachIteration): New function. + * src/AnnounceList: AnnounceTier->AnnounceTierHandle. + * src/Directry.h + (Directory): New function. + (DirectoryHandle): New type definition. + * src/BtProgressInfoFile.h: New file. + * src/RequestMessage.cc: Use pieceStorage. + * src/BtRuntime.h: New file. + * src/DefaultBtContext.cc: New file. + * src/BitfieldMan.h + (getCompletedLength): New function(private). + (getCompletedLength): New function. + (getFilteredCompletedLength): New function. + * src/BitfieldMan.h + (getCompletedLength): New function(private). + (getCompletedLength): New function. + (getFilteredCompletedLength): New function. + * src/MultiDiskAdaptor.cc + (mkdir): New function. + (openFile): Call mkdir(). + (initAndOpenFile): Call mkdir(). + * src/CancelMessage.h + (TorrentMan.h): Removed. + * src/RejectMessage.h + (TorrentMan.h): Removed. + * src/DownloadEngineFactory.cc + (DefaultPieceStorage.h): New include. + (DefaultPeerStorage.h): New include. + (DefaultBtAnnounce.h): New include. + (DefaultBtProgressInfoFile.h): New include. + (newTorrentConsoleEngine): Rewritten. + * src/ShareRatioSeedCriteria.h + (torrentMan): Removed. + (btContext): New variable. + (peerStorage): New variable. + (btRuntime): New variable. + (evaluate): Use btContext, btRuntime, peerStorage. + * src/AnnounceTier.h: New file. + * src/BtAnnounce.h: New file. + * src/BtRegistry.h: New file. + * src/PeerInitiateConnectionCommand.h: Added btContext. + * src/PeerConnection.h (TorrentMan.h): Removed. + * src/PeerMessageFactory.cc: Use btContext, pieceStorage. + * src/Util.h + (slice): Added an argument. + * src/Util.cc + (slice): Added an argument to control whether trim is made or not. + * src/PeerStorage.h: New file. + * src/BtRegistry.cc: New file. + * src/TrackerUpdateCommand.h: Made subclass of BtContextAwareCommand. + * src/CopyDiskAdaptor.cc: Use the accessor methods of FileEntry. + * src/MultiDiskWriter.h: FileEntry -> FileEntryHandle + * src/PeerListenCommand.cc: Use btRuntime, peerStorage, btContext. + * src/TorrentRequestInfo.h + (e): Removed. + (showFileEntry): Added an argument. + (getDownloadEngine): Return 0. + * src/DefaultBtAnnounce.h: New file. + * src/TorrentAutoSaveCommand.cc: Use btRuntime, btProgressInfoFile. + * src/TrackerWatcherComand.cc: Use btRuntime, btAnnounce, + * src/PeerMessageFactory.h + (btContext): New variable. + (pieceStorage): New variable. + * src/TrackerUpdateCommand.cc: Use btRuntime, peerStorage, btContext, + btAnnounce. + * src/DiskAdaptor.cc + (DiskAdaptor): Removed topDir. + (~DiskAdaptor): Removed topDir. + * src/PeerListenCommand.h: Made subclass of BtContextAwareCommand. + * src/SeedCheckCommand.h: Made subclass of BtContextAwareCommand. + * src/File.h (mkdirs): New function. + * src/DefaultPeerStorage): New file. + * src/DownloadEngineFactory.h + (newTorrentConsoleEngine): Use btContext. + * src/BtContextAwareCommand.cc: New file. + * src/PeerInitiateConnectionCommand.cc: Use btRuntime, peerStorage. + * src/PeerMessage.h + (btContext): New variable. + (peerStorage): New variable. + (pieceStorage): New variable. + (setBtContext): New function. + * src/Directry.cc + (Directory): New function. + (createDir): Do nothing if name.size() == 0. + * src/AnnounceList.h + (AnnounceTier): Removed. + (AnnounceTiers): Removed. + * src/DefaultPieceStorage.h: New file. + * src/Piece.cc (toString): New function. + + To fix typo: + + * src/main.cc (showVersion): Fixed typo. + + To fix compile warning: + + * src/DelegatingPeerListProcessor.cc + (canHandle): Added "return false". + 2006-10-20 Tatsuhiro Tsujikawa To simplify TrackerWatherCommand, TrackerUpdateCommand and diff --git a/TODO b/TODO index a2a02ce6..f3516a8a 100644 --- a/TODO +++ b/TODO @@ -19,4 +19,5 @@ * Use SharedHandle where it is useful. * Add support for "announce-list". * Rewrite Util::countBit -* Add the ability to display filename or URL to be downloaded in metalink mode. \ No newline at end of file +* Add the ability to display filename or URL to be downloaded in metalink mode. +* Add Turkish translation. diff --git a/src/AnnounceList.cc b/src/AnnounceList.cc index 43d0daa7..fbe8025a 100644 --- a/src/AnnounceList.cc +++ b/src/AnnounceList.cc @@ -59,7 +59,7 @@ void AnnounceList::reconfigure(const MetaEntry* announceListEntry) { urls.push_back(data->toString()); } if(urls.size()) { - AnnounceTier tier(urls); + AnnounceTierHandle tier(new AnnounceTier(urls)); tiers.push_back(tier); } } @@ -70,14 +70,14 @@ void AnnounceList::reconfigure(const MetaEntry* announceListEntry) { void AnnounceList::reconfigure(const string& url) { Strings urls; urls.push_back(url); - tiers.push_back(AnnounceTier(urls)); + tiers.push_back(AnnounceTierHandle(new AnnounceTier(urls))); resetIterator(); } void AnnounceList::resetIterator() { currentTier = tiers.begin(); - if(currentTier != tiers.end() && currentTier->urls.size()) { - currentTracker = currentTier->urls.begin(); + if(currentTier != tiers.end() && (*currentTier)->urls.size()) { + currentTracker = (*currentTier)->urls.begin(); currentTrackerInitialized = true; } else { currentTrackerInitialized = false; @@ -94,31 +94,31 @@ string AnnounceList::getAnnounce() const { void AnnounceList::announceSuccess() { if(currentTrackerInitialized) { - currentTier->nextEvent(); + (*currentTier)->nextEvent(); string url = *currentTracker; - currentTier->urls.erase(currentTracker); - currentTier->urls.push_front(url); + (*currentTier)->urls.erase(currentTracker); + (*currentTier)->urls.push_front(url); currentTier = tiers.begin(); - currentTracker = currentTier->urls.begin(); + currentTracker = (*currentTier)->urls.begin(); } } void AnnounceList::announceFailure() { if(currentTrackerInitialized) { currentTracker++; - if(currentTracker == currentTier->urls.end()) { + if(currentTracker == (*currentTier)->urls.end()) { currentTier++; if(currentTier == tiers.end()) { currentTier = tiers.begin(); } - currentTracker = currentTier->urls.begin(); + currentTracker = (*currentTier)->urls.begin(); } } } AnnounceTier::AnnounceEvent AnnounceList::getEvent() const { if(currentTrackerInitialized) { - return currentTier->event; + return (*currentTier)->event; } else { return AnnounceTier::STARTED; } @@ -126,13 +126,13 @@ AnnounceTier::AnnounceEvent AnnounceList::getEvent() const { void AnnounceList::setEvent(AnnounceTier::AnnounceEvent event) { if(currentTrackerInitialized) { - currentTier->event = event; + (*currentTier)->event = event; } } string AnnounceList::getEventString() const { if(currentTrackerInitialized) { - switch(currentTier->event) { + switch((*currentTier)->event) { case AnnounceTier::STARTED: case AnnounceTier::STARTED_AFTER_COMPLETION: return "started"; @@ -150,8 +150,8 @@ string AnnounceList::getEventString() const { class FindStoppedAllowedTier { public: - bool operator()(const AnnounceTier& tier) const { - switch(tier.event) { + bool operator()(const AnnounceTierHandle& tier) const { + switch(tier->event) { case AnnounceTier::DOWNLOADING: case AnnounceTier::STOPPED: case AnnounceTier::COMPLETED: @@ -165,8 +165,8 @@ public: class FindCompletedAllowedTier { public: - bool operator()(const AnnounceTier& tier) const { - switch(tier.event) { + bool operator()(const AnnounceTierHandle& tier) const { + switch(tier->event) { case AnnounceTier::DOWNLOADING: case AnnounceTier::COMPLETED: return true; @@ -187,7 +187,7 @@ int AnnounceList::countCompletedAllowedTier() const { void AnnounceList::setCurrentTier(const AnnounceTiers::iterator& itr) { if(itr != tiers.end()) { currentTier = itr; - currentTracker = currentTier->urls.begin(); + currentTracker = (*currentTier)->urls.begin(); } } @@ -220,6 +220,7 @@ void AnnounceList::moveToCompletedAllowedTier() { void AnnounceList::shuffle() { for(AnnounceTiers::iterator itr = tiers.begin(); itr != tiers.end(); itr++) { - random_shuffle(itr->urls.begin(), itr->urls.end()); + Strings& urls = (*itr)->urls; + random_shuffle(urls.begin(), urls.end()); } } diff --git a/src/AnnounceList.h b/src/AnnounceList.h index d2ecb3d8..fdd19a49 100644 --- a/src/AnnounceList.h +++ b/src/AnnounceList.h @@ -37,45 +37,7 @@ #include "common.h" #include "MetaEntry.h" - -class AnnounceTier { -public: - enum AnnounceEvent { - STARTED, - STARTED_AFTER_COMPLETION, - DOWNLOADING, - STOPPED, - COMPLETED, - SEEDING, - HALTED - }; - - AnnounceEvent event; - Strings urls; - - AnnounceTier(const Strings& urls):event(STARTED), urls(urls) {} - - void nextEvent() { - switch(event) { - case STARTED: - event = DOWNLOADING; - break; - case STARTED_AFTER_COMPLETION: - event = SEEDING; - break; - case STOPPED: - event = HALTED; - break; - case COMPLETED: - event = SEEDING; - break; - default: - break; - } - } -}; - -typedef deque AnnounceTiers; +#include "AnnounceTier.h" class AnnounceList { public: diff --git a/src/AnnounceTier.h b/src/AnnounceTier.h new file mode 100644 index 00000000..85fdc27b --- /dev/null +++ b/src/AnnounceTier.h @@ -0,0 +1,80 @@ +/* */ +#ifndef _D_ANNOUNCE_TIER_H_ +#define _D_ANNOUNCE_TIER_H_ + +#include "common.h" + +class AnnounceTier { +public: + enum AnnounceEvent { + STARTED, + STARTED_AFTER_COMPLETION, + DOWNLOADING, + STOPPED, + COMPLETED, + SEEDING, + HALTED + }; + + AnnounceEvent event; + Strings urls; + + AnnounceTier(const Strings& urls):event(STARTED), urls(urls) {} + + void nextEvent() { + switch(event) { + case STARTED: + event = DOWNLOADING; + break; + case STARTED_AFTER_COMPLETION: + event = SEEDING; + break; + case STOPPED: + event = HALTED; + break; + case COMPLETED: + event = SEEDING; + break; + default: + break; + } + } +}; + +typedef SharedHandle AnnounceTierHandle; +typedef deque AnnounceTiers; + +#endif // _D_ANNOUNCE_TIER_H_ diff --git a/src/BitfieldMan.cc b/src/BitfieldMan.cc index c05f2826..736bc5b8 100644 --- a/src/BitfieldMan.cc +++ b/src/BitfieldMan.cc @@ -510,13 +510,17 @@ long long int BitfieldMan::getFilteredTotalLength() const { } } -long long int BitfieldMan::getCompletedLength() const { +long long int BitfieldMan::getCompletedLength(bool useFilter) const { unsigned char* temp = new unsigned char[bitfieldLength]; - for(int i = 0; i < bitfieldLength; i++) { - temp[i] = bitfield[i]; - if(filterEnabled) { - temp[i] &= filterBitfield[i]; + if(useFilter) { + for(int i = 0; i < bitfieldLength; i++) { + temp[i] = bitfield[i]; + if(filterEnabled) { + temp[i] &= filterBitfield[i]; + } } + } else { + memcpy(temp, bitfield, bitfieldLength); } int completedBlocks = countSetBit(temp, bitfieldLength); long long int completedLength = 0; @@ -532,3 +536,11 @@ long long int BitfieldMan::getCompletedLength() const { delete [] temp; return completedLength; } + +long long int BitfieldMan::getCompletedLength() const { + return getCompletedLength(false); +} + +long long int BitfieldMan::getFilteredCompletedLength() const { + return getCompletedLength(true); +} diff --git a/src/BitfieldMan.h b/src/BitfieldMan.h index 2760c382..53758601 100644 --- a/src/BitfieldMan.h +++ b/src/BitfieldMan.h @@ -59,6 +59,8 @@ private: int getStartIndex(int index) const; int getEndIndex(int index) const; + + long long int getCompletedLength(bool useFilter) const; public: BitfieldMan(int blockLength, long long int totalLength); BitfieldMan(const BitfieldMan& bitfieldMan); @@ -191,11 +193,15 @@ public: void enableFilter(); void disableFilter(); bool isFilterEnabled() const; - long long int getFilteredTotalLength() const; /** * affected by filter */ + long long int getFilteredTotalLength() const; long long int getCompletedLength() const; + /** + * affected by filter + */ + long long int getFilteredCompletedLength() const; }; #endif // _D_BITFIELD_MAN_H_ diff --git a/src/BtAnnounce.h b/src/BtAnnounce.h new file mode 100644 index 00000000..3b9e735f --- /dev/null +++ b/src/BtAnnounce.h @@ -0,0 +1,111 @@ +/* */ +#ifndef _D_BT_ANNOUNCE_H_ +#define _D_BT_ANNOUNCE_H_ + +#include "common.h" + +class BtAnnounce { +public: + virtual ~BtAnnounce() {} + + /** + * Returns true if announce is required. + * Otherwise returns false. + * + * There are 4 announce timings: + * 1) started: when a download just started. + * 2) stopped: when the client quits. + * 3) completed: when a download just completed. + * 4) When a certain amount of time, aka announce interval, specified by + * a tracker, is elapsed. + */ + virtual bool isAnnounceReady() = 0; + + /** + * Returns announe URL with all necessary parameters included. + */ + virtual string getAnnounceUrl() = 0; + + /** + * Tells that the announce process has just started. + */ + virtual void announceStart() = 0; + + /** + * Tells that the announce succeeded. + */ + virtual void announceSuccess() = 0; + + /** + * Tells that the announce failed. + */ + virtual void announceFailure() = 0; + + /** + * Returns true if all announce attempt failed. + */ + virtual bool isAllAnnounceFailed() = 0; + + /** + * Resets announce status. + */ + virtual void resetAnnounce() = 0; + + /** + * Processes the repsponse from the tracker. + */ + virtual void processAnnounceResponse(const char* trackerResponse, + size_t trackerResponseLength) = 0; + + /** + * Returns true if no more announce is needed. + */ + virtual bool noMoreAnnounce() = 0; + + /** + * Shuffles the URLs in each announce tier. + */ + virtual void shuffleAnnounce() = 0; + + /** + * Returns the peer id of the client. + */ + virtual string getPeerId() = 0; +}; + +typedef SharedHandle BtAnnounceHandle; + +#endif // _D_BT_ANNOUNCE_H_ diff --git a/src/BtContext.h b/src/BtContext.h new file mode 100644 index 00000000..ad05c4f8 --- /dev/null +++ b/src/BtContext.h @@ -0,0 +1,84 @@ +/* */ +#ifndef _D_BT_CONTEXT_H_ +#define _D_BT_CONTEXT_H_ + +#include "common.h" +#include "FileEntry.h" +#include "AnnounceTier.h" + +#define INFO_HASH_LENGTH 20 +#define MAX_PEER_ERROR 5 +#define MAX_PEERS 55 + +typedef deque AnnounceTiers; + +class BtContext { +public: + virtual ~BtContext() {} + + enum FILE_MODE { + SINGLE, + MULTI + }; + + virtual const unsigned char* getInfoHash() const = 0; + + virtual int getInfoHashLength() const = 0; + + virtual string getInfoHashAsString() const = 0; + + virtual string getPieceHash(int index) const = 0; + + virtual long long int getTotalLength() const = 0; + + virtual FILE_MODE getFileMode() const = 0; + + virtual FileEntries getFileEntries() const = 0; + + virtual AnnounceTiers getAnnounceTiers() const = 0; + + virtual void load(const string& torrentFile) = 0; + + virtual string getName() const = 0; + + virtual int getPieceLength() const = 0; + + virtual int getNumPieces() const = 0; +}; + +typedef SharedHandle BtContextHandle; + +#endif // _D_BT_CONTEXT_H_ diff --git a/src/BtContextAwareCommand.cc b/src/BtContextAwareCommand.cc new file mode 100644 index 00000000..b45d6ddc --- /dev/null +++ b/src/BtContextAwareCommand.cc @@ -0,0 +1,48 @@ +/* */ +#include "BtContextAwareCommand.h" +#include "BtRegistry.h" + +BtContextAwareCommand::BtContextAwareCommand(int cuid, + const BtContextHandle& btContext): + Command(cuid), + btContext(btContext), + btRuntime(BT_RUNTIME(btContext)), + pieceStorage(PIECE_STORAGE(btContext)), + peerStorage(PEER_STORAGE(btContext)), + btAnnounce(BT_ANNOUNCE(btContext)), + btProgressInfoFile(BT_PROGRESS_INFO_FILE(btContext)) {} + +BtContextAwareCommand::~BtContextAwareCommand() {} diff --git a/src/BtContextAwareCommand.h b/src/BtContextAwareCommand.h new file mode 100644 index 00000000..44bbd9b6 --- /dev/null +++ b/src/BtContextAwareCommand.h @@ -0,0 +1,60 @@ +/* */ +#ifndef _D_BT_CONTEXT_AWARE_COMMAND_H_ +#define _D_BT_CONTEXT_AWARE_COMMAND_H_ + +#include "Command.h" +#include "BtContext.h" +#include "BtRuntime.h" +#include "PieceStorage.h" +#include "PeerStorage.h" +#include "BtAnnounce.h" +#include "BtProgressInfoFile.h" + +class BtContextAwareCommand : public Command { +protected: + BtContextHandle btContext; + BtRuntimeHandle btRuntime; + PieceStorageHandle pieceStorage; + PeerStorageHandle peerStorage; + BtAnnounceHandle btAnnounce; + BtProgressInfoFileHandle btProgressInfoFile; +public: + BtContextAwareCommand(int cuid, const BtContextHandle& btContext); + + virtual ~BtContextAwareCommand(); +}; + +#endif // _D_BT_CONTEXT_AWARE_COMMAND_H_ diff --git a/src/BtProgressInfoFile.h b/src/BtProgressInfoFile.h new file mode 100644 index 00000000..e4d8f2ff --- /dev/null +++ b/src/BtProgressInfoFile.h @@ -0,0 +1,59 @@ +/* */ +#ifndef _D_BT_PROGRESS_INFO_FILE_H_ +#define _D_BT_PROGRESS_INFO_FILE_H_ + +#include "common.h" + +class BtProgressInfoFile { +public: + virtual ~BtProgressInfoFile() {} + + virtual string getFilename() = 0; + + virtual void setFilename(const string& filename) = 0; + + virtual bool exists() = 0; + + virtual void save() = 0; + + virtual void load() = 0; + + virtual void removeFile() = 0; +}; + +typedef SharedHandle BtProgressInfoFileHandle; + +#endif // _D_BT_PROGRESS_INFO_FILE_H_ diff --git a/src/BtRegistry.cc b/src/BtRegistry.cc new file mode 100644 index 00000000..cdd9c6e6 --- /dev/null +++ b/src/BtRegistry.cc @@ -0,0 +1,130 @@ +/* */ +#include "BtRegistry.h" +#include "DlAbortEx.h" + +PeerStorageMap BtRegistry::peerStorageMap; +PieceStorageMap BtRegistry::pieceStorageMap; +BtAnnounceMap BtRegistry::btAnnounceMap; +BtRuntimeMap BtRegistry::btRuntimeMap; +BtProgressInfoFileMap BtRegistry::btProgressInfoFileMap; + +PeerStorageHandle BtRegistry::getPeerStorage(const string& key) { + PeerStorageMap::iterator itr = peerStorageMap.find(key); + if(itr == peerStorageMap.end()) { + return PeerStorageHandle(0); + } else { + return itr->second; + } +} + +bool BtRegistry::registerPeerStorage(const string& key, + const PeerStorageHandle& peerStorage) { + PeerStorageMap::value_type p(key, peerStorage); + pair retval = peerStorageMap.insert(p); + return retval.second; +} + +PieceStorageHandle +BtRegistry::getPieceStorage(const string& key) { + PieceStorageMap::iterator itr = pieceStorageMap.find(key); + if(itr == pieceStorageMap.end()) { + return PieceStorageHandle(0); + } else { + return itr->second; + } +} + +bool +BtRegistry::registerPieceStorage(const string& key, + const PieceStorageHandle& pieceStorage) { + PieceStorageMap::value_type p(key, pieceStorage); + pair retval = pieceStorageMap.insert(p); + return retval.second; +} + +BtRuntimeHandle BtRegistry::getBtRuntime(const string& key) { + BtRuntimeMap::iterator itr = btRuntimeMap.find(key); + if(itr == btRuntimeMap.end()) { + return BtRuntimeHandle(0); + } else { + return itr->second; + } +} + +bool +BtRegistry::registerBtRuntime(const string& key, + const BtRuntimeHandle& btRuntime) { + BtRuntimeMap::value_type p(key, btRuntime); + pair retval = + btRuntimeMap.insert(p); + return retval.second; +} + +BtAnnounceHandle BtRegistry::getBtAnnounce(const string& key) { + BtAnnounceMap::iterator itr = btAnnounceMap.find(key); + if(itr == btAnnounceMap.end()) { + return BtAnnounceHandle(0); + } else { + return itr->second; + } +} + +bool +BtRegistry::registerBtAnnounce(const string& key, + const BtAnnounceHandle& btAnnounce) { + BtAnnounceMap::value_type p(key, btAnnounce); + pair retval = + btAnnounceMap.insert(p); + return retval.second; +} + +BtProgressInfoFileHandle BtRegistry::getBtProgressInfoFile(const string& key) { + BtProgressInfoFileMap::iterator itr = btProgressInfoFileMap.find(key); + if(itr == btProgressInfoFileMap.end()) { + return BtProgressInfoFileHandle(0); + } else { + return itr->second; + } +} + +bool +BtRegistry::registerBtProgressInfoFile(const string& key, + const BtProgressInfoFileHandle& btProgressInfoFile) { + BtProgressInfoFileMap::value_type p(key, btProgressInfoFile); + pair retval = + btProgressInfoFileMap.insert(p); + return retval.second; +} diff --git a/src/BtRegistry.h b/src/BtRegistry.h new file mode 100644 index 00000000..f8356a23 --- /dev/null +++ b/src/BtRegistry.h @@ -0,0 +1,98 @@ +/* */ +#ifndef _D_BT_REGISTRY_H_ +#define _D_BT_REGISTRY_H_ + +#include "common.h" +#include "PeerStorage.h" +#include "PieceStorage.h" +#include "BtAnnounce.h" +#include "BtRuntime.h" +#include "BtProgressInfoFile.h" +#include + +typedef map PeerStorageMap; +typedef map PieceStorageMap; +typedef map BtAnnounceMap; +typedef map BtRuntimeMap; +typedef map BtProgressInfoFileMap; + +class BtRegistry { +private: + BtRegistry() {} + + static PeerStorageMap peerStorageMap; + static PieceStorageMap pieceStorageMap; + static BtAnnounceMap btAnnounceMap; + static BtRuntimeMap btRuntimeMap; + static BtProgressInfoFileMap btProgressInfoFileMap; +public: + static PeerStorageHandle getPeerStorage(const string& key); + static bool registerPeerStorage(const string& key, + const PeerStorageHandle& peer); + + static PieceStorageHandle getPieceStorage(const string& key); + static bool registerPieceStorage(const string& key, + const PieceStorageHandle& pieceStorage); + + static BtRuntimeHandle getBtRuntime(const string& key); + static bool registerBtRuntime(const string& key, + const BtRuntimeHandle& btRuntime); + + static BtAnnounceHandle getBtAnnounce(const string& key); + static bool registerBtAnnounce(const string& key, + const BtAnnounceHandle& btAnnounce); + + static BtProgressInfoFileHandle getBtProgressInfoFile(const string& key); + static bool registerBtProgressInfoFile(const string& key, + const BtProgressInfoFileHandle& btProgressInfoFile); +}; + +#define PEER_STORAGE(btContext) \ +BtRegistry::getPeerStorage(btContext->getInfoHashAsString()) + +#define PIECE_STORAGE(btContext) \ +BtRegistry::getPieceStorage(btContext->getInfoHashAsString()) + +#define BT_ANNOUNCE(btContext) \ +BtRegistry::getBtAnnounce(btContext->getInfoHashAsString()) + +#define BT_RUNTIME(btContext) \ +BtRegistry::getBtRuntime(btContext->getInfoHashAsString()) + +#define BT_PROGRESS_INFO_FILE(btContext) \ +BtRegistry::getBtProgressInfoFile(btContext->getInfoHashAsString()) + +#endif // _D_BT_REGISTRY_H_ diff --git a/src/BtRuntime.h b/src/BtRuntime.h new file mode 100644 index 00000000..911fa6d3 --- /dev/null +++ b/src/BtRuntime.h @@ -0,0 +1,94 @@ +/* */ +#ifndef _D_BT_RUNTIME_H_ +#define _D_BT_RUNTIME_H_ + +#include "common.h" +#include "SharedHandle.h" + +#define MIN_PEERS 15 + +class BtRuntime { +private: + long long int uploadLengthAtStartup; + int port; + bool halt; + int connections; + int cuidCounter; +public: + BtRuntime(): + uploadLengthAtStartup(0), + port(0), + halt(false), + connections(0), + cuidCounter(0) {} + ~BtRuntime() {} + + long long int getUploadLengthAtStartup() const { + return uploadLengthAtStartup; + } + + void setUploadLengthAtStartup(long long int length) { + this->uploadLengthAtStartup = length; + } + + void setListenPort(int port) { + this->port = port; + } + + int getListenPort() const { return port; } + + bool isHalt() const { return halt; } + + void setHalt(bool halt) { + this->halt = halt; + } + + int getConnections() const { return connections; } + + void increaseConnections() { connections++; } + + void decreaseConnections() { connections--; } + + bool lessThanMinPeer() const { return connections < MIN_PEERS; } + + bool lessThanEqMinPeer() const { return connections <= MIN_PEERS; } + + int getNewCuid() { return ++cuidCounter; } +}; + +typedef SharedHandle BtRuntimeHandle; + +#endif // _D_BT_RUNTIME_H_ diff --git a/src/CancelMessage.h b/src/CancelMessage.h index 1511d82a..b1a15281 100644 --- a/src/CancelMessage.h +++ b/src/CancelMessage.h @@ -36,7 +36,6 @@ #define _D_CANCEL_MESSAGE_H_ #include "SimplePeerMessage.h" -#include "TorrentMan.h" class CancelMessage : public SimplePeerMessage { private: diff --git a/src/CookieBox.cc b/src/CookieBox.cc index 5ec2abf3..42010121 100644 --- a/src/CookieBox.cc +++ b/src/CookieBox.cc @@ -68,7 +68,7 @@ void CookieBox::setField(Cookie& cookie, const string& name, const string& value void CookieBox::parse(Cookie& cookie, const string& cookieStr) const { cookie.clear(); Strings terms; - Util::slice(terms, cookieStr, ';'); + Util::slice(terms, cookieStr, ';', true); for(Strings::iterator itr = terms.begin(); itr != terms.end(); itr++) { pair nv; Util::split(nv, *itr, '='); diff --git a/src/CopyDiskAdaptor.cc b/src/CopyDiskAdaptor.cc index 5318d5c4..c39d8f8a 100644 --- a/src/CopyDiskAdaptor.cc +++ b/src/CopyDiskAdaptor.cc @@ -46,19 +46,17 @@ void CopyDiskAdaptor::onDownloadComplete() { } void CopyDiskAdaptor::fixFilename() { - if(topDir != NULL) { - topDir->createDir(storeDir, true); - } long long int offset = 0; for(FileEntries::iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { - if(!itr->extracted && itr->requested) { - string dest = storeDir+"/"+itr->path; + if(!(*itr)->isExtracted() && (*itr)->isRequested()) { + (*itr)->setupDir(storeDir); + string dest = storeDir+"/"+(*itr)->getPath(); logger->info("writing file %s", dest.c_str()); - Util::rangedFileCopy(dest, getFilePath(), offset, itr->length); - itr->extracted = true; + Util::rangedFileCopy(dest, getFilePath(), offset, (*itr)->getLength()); + (*itr)->setExtracted(true); } - offset += itr->length; + offset += (*itr)->getLength(); } } diff --git a/src/DefaultBtAnnounce.cc b/src/DefaultBtAnnounce.cc new file mode 100644 index 00000000..04e069eb --- /dev/null +++ b/src/DefaultBtAnnounce.cc @@ -0,0 +1,246 @@ +/* */ +#include "DefaultBtAnnounce.h" +#include "BtRegistry.h" +#include "LogFactory.h" +#include "MetaFileUtil.h" +#include "Dictionary.h" +#include "List.h" +#include "Data.h" +#include "DelegatingPeerListProcessor.h" +#include "Util.h" +#include "prefs.h" +#include "DlAbortEx.h" +#include "message.h" + +DefaultBtAnnounce::DefaultBtAnnounce(BtContextHandle btContext, + const Option* option): + btContext(btContext), + trackers(0), + interval(DEFAULT_ANNOUNCE_INTERVAL), + minInterval(DEFAULT_ANNOUNCE_INTERVAL), + complete(0), + incomplete(0), + announceList(btContext->getAnnounceTiers()), + trackerNumTry(0), + option(option), + btRuntime(BT_RUNTIME(btContext)), + pieceStorage(PIECE_STORAGE(btContext)), + peerStorage(PEER_STORAGE(btContext)) +{ + prevAnnounceTime.setTimeInSec(0); + key = generateKey(); + peerId = generatePeerId(); + logger = LogFactory::getInstance(); +} + +DefaultBtAnnounce::~DefaultBtAnnounce() { +} + +string DefaultBtAnnounce::generateKey() const { + return Util::randomAlpha(8); +} + +string DefaultBtAnnounce::generatePeerId() const { + string peerId = "-aria2-"; + peerId += Util::randomAlpha(20-peerId.size()); + return peerId; +} + +bool DefaultBtAnnounce::isDefaultAnnounceReady() { + return (trackers == 0 && prevAnnounceTime.elapsed(minInterval)); +} + +bool DefaultBtAnnounce::isStoppedAnnounceReady() { + return (trackers == 0 && + btRuntime->isHalt() && + announceList.countStoppedAllowedTier()); +} + +bool DefaultBtAnnounce::isCompletedAnnounceReady() { + return (trackers == 0 && + pieceStorage->downloadFinished() && + announceList.countCompletedAllowedTier()); +} + +bool DefaultBtAnnounce::isAnnounceReady() { + return + isStoppedAnnounceReady() || + isCompletedAnnounceReady() || + isDefaultAnnounceReady(); +} + +string DefaultBtAnnounce::getAnnounceUrl() { + if(isStoppedAnnounceReady()) { + announceList.moveToStoppedAllowedTier(); + announceList.setEvent(AnnounceTier::STOPPED); + } else if(isCompletedAnnounceReady()) { + announceList.moveToCompletedAllowedTier(); + announceList.setEvent(AnnounceTier::COMPLETED); + } else if(isDefaultAnnounceReady()) { + // If download completed before "started" event is sent to a tracker, + // we change the event to something else to prevent us from + // sending "completed" event. + if(pieceStorage->downloadFinished() && + announceList.getEvent() == AnnounceTier::STARTED) { + announceList.setEvent(AnnounceTier::STARTED_AFTER_COMPLETION); + } + } + int numWant = 50; + if(!btRuntime->lessThanEqMinPeer() || + btRuntime->isHalt()) { + numWant = 0; + } + TransferStat stat = peerStorage->calculateStat(); + long long int left = pieceStorage->getTotalLength()-pieceStorage->getCompletedLength(); + if(left < 0) { + left = 0; + } + string url = announceList.getAnnounce()+"?"+ + "info_hash="+Util::torrentUrlencode(btContext->getInfoHash(), + btContext->getInfoHashLength())+"&"+ + "peer_id="+peerId+"&"+ + "port="+Util::itos(btRuntime->getListenPort())+"&"+ + "uploaded="+Util::llitos(stat.getSessionUploadLength())+"&"+ + "downloaded="+Util::llitos(stat.getSessionDownloadLength())+"&"+ + "left="+Util::llitos(left)+"&"+ + "compact=1"+"&"+ + "key="+key+"&"+ + "numwant="+Util::itos(numWant)+"&"+ + "no_peer_id=1"; + string event = announceList.getEventString(); + if(!event.empty()) { + url += string("&")+"event="+event; + } + if(!trackerId.empty()) { + url += string("&")+"trackerid="+Util::torrentUrlencode((const unsigned char*)trackerId.c_str(), + trackerId.size()); + } + return url; +} + +void DefaultBtAnnounce::announceStart() { + trackers++; +} + +void DefaultBtAnnounce::announceSuccess() { + trackers = 0; + announceList.announceSuccess(); +} + +void DefaultBtAnnounce::announceFailure() { + trackers = 0; + trackerNumTry++; + announceList.announceFailure(); +} + +bool DefaultBtAnnounce::isAllAnnounceFailed() { + return + trackerNumTry >= option->getAsInt(PREF_TRACKER_MAX_TRIES); +} + +void DefaultBtAnnounce::resetAnnounce() { + prevAnnounceTime.reset(); + trackerNumTry = 0; +} + +void +DefaultBtAnnounce::processAnnounceResponse(const char* trackerResponse, + size_t trackerResponseLength) +{ + SharedHandle entry(MetaFileUtil::bdecoding(trackerResponse, + trackerResponseLength)); + Dictionary* response = (Dictionary*)entry.get(); + Data* failureReasonData = (Data*)response->get("failure reason"); + if(failureReasonData) { + throw new DlAbortEx("Tracker returned failure reason: %s", + failureReasonData->toString().c_str()); + } + Data* warningMessageData = (Data*)response->get("warning message"); + if(warningMessageData) { + logger->warn(MSG_TRACKER_WARNING_MESSAGE, + warningMessageData->toString().c_str()); + } + Data* trackerIdData = (Data*)response->get("tracker id"); + if(trackerIdData) { + trackerId = trackerIdData->toString(); + logger->debug("Tracker ID:%s", trackerId.c_str()); + } + Data* intervalData = (Data*)response->get("interval"); + if(intervalData) { + interval = intervalData->toInt(); + logger->debug("Interval:%d", interval); + } + Data* minIntervalData = (Data*)response->get("min interval"); + if(minIntervalData) { + minInterval = minIntervalData->toInt(); + logger->debug("Min interval:%d", minInterval); + } + if(minInterval > interval) { + minInterval = interval; + } + Data* completeData = (Data*)response->get("complete"); + if(completeData) { + complete = completeData->toInt(); + logger->debug("Complete:%d", complete); + } + Data* incompleteData = (Data*)response->get("incomplete"); + if(incompleteData) { + incomplete = incompleteData->toInt(); + logger->debug("Incomplete:%d", incomplete); + } + const MetaEntry* peersEntry = response->get("peers"); + if(peersEntry && + !btRuntime->isHalt() && + btRuntime->lessThanMinPeer()) { + DelegatingPeerListProcessor proc(btContext->getPieceLength(), + btContext->getTotalLength()); + Peers peers = proc.extractPeer(peersEntry); + peerStorage->addPeer(peers); + } + if(!peersEntry) { + logger->info("No peer list received."); + } +} + +bool DefaultBtAnnounce::noMoreAnnounce() { + return (trackers == 0 && + btRuntime->isHalt() && + !announceList.countStoppedAllowedTier()); +} + +void DefaultBtAnnounce::shuffleAnnounce() { + announceList.shuffle(); +} diff --git a/src/DefaultBtAnnounce.h b/src/DefaultBtAnnounce.h new file mode 100644 index 00000000..f54c1ac9 --- /dev/null +++ b/src/DefaultBtAnnounce.h @@ -0,0 +1,122 @@ +/* */ +#ifndef _D_DEFAULT_BT_ANNOUNCE_H_ +#define _D_DEFAULT_BT_ANNOUNCE_H_ + +#include "BtAnnounce.h" +#include "BtContext.h" +#include "TimeA2.h" +#include "AnnounceList.h" +#include "Option.h" +#include "Logger.h" +#include "BtRuntime.h" +#include "PieceStorage.h" +#include "PeerStorage.h" + +#define DEFAULT_ANNOUNCE_INTERVAL 1800 + +class DefaultBtAnnounce : public BtAnnounce { +private: + BtContextHandle btContext; + int trackers; + Time prevAnnounceTime; + int interval; + int minInterval; + int complete; + int incomplete; + AnnounceList announceList; + string trackerId; + string key; + int trackerNumTry; + string peerId; + const Option* option; + Logger* logger; + BtRuntimeHandle btRuntime; + PieceStorageHandle pieceStorage; + PeerStorageHandle peerStorage; +public: + DefaultBtAnnounce(BtContextHandle btContext, const Option* option); + virtual ~DefaultBtAnnounce(); + + void setBtRuntime(const BtRuntimeHandle& btRuntime) { + this->btRuntime = btRuntime; + } + BtRuntimeHandle getBtRuntime() const { return btRuntime; } + + void setPieceStorage(const PieceStorageHandle& pieceStorage) { + this->pieceStorage = pieceStorage; + } + PieceStorageHandle getPieceStorage() const { return pieceStorage; } + + void setPeerStorage(const PeerStorageHandle& peerStorage) { + this->peerStorage = peerStorage; + } + PeerStorageHandle getPeerStorage() const { return peerStorage; } + + bool isDefaultAnnounceReady(); + + bool isStoppedAnnounceReady(); + + bool isCompletedAnnounceReady(); + + virtual bool isAnnounceReady(); + + virtual string getAnnounceUrl(); + + virtual void announceStart(); + + virtual void announceSuccess(); + + virtual void announceFailure(); + + virtual bool isAllAnnounceFailed(); + + virtual void resetAnnounce(); + + virtual void processAnnounceResponse(const char* trackerResponse, + size_t trackerResponseLength); + + virtual bool noMoreAnnounce(); + + virtual void shuffleAnnounce(); + + string generateKey() const; + + string generatePeerId() const; + + virtual string getPeerId() { return peerId; } +}; + +#endif // _D_DEFAULT_BT_ANNOUNCE_H_ diff --git a/src/DefaultBtContext.cc b/src/DefaultBtContext.cc new file mode 100644 index 00000000..1acf5fc5 --- /dev/null +++ b/src/DefaultBtContext.cc @@ -0,0 +1,237 @@ +/* */ +#include "DefaultBtContext.h" +#include "MetaFileUtil.h" +#include "Dictionary.h" +#include "List.h" +#include "Data.h" +#include "DlAbortEx.h" +#include "ShaVisitor.h" +#include "Util.h" + +DefaultBtContext::DefaultBtContext() {} + +DefaultBtContext::~DefaultBtContext() {} + +const unsigned char* DefaultBtContext::getInfoHash() const { + return infoHash; +} + +int DefaultBtContext::getInfoHashLength() const { + return INFO_HASH_LENGTH; +} + +string DefaultBtContext::getInfoHashAsString() const { + return infoHashString; +} + +void DefaultBtContext::clear() { + memset(infoHash, 0, INFO_HASH_LENGTH); + infoHashString = ""; + pieceHashes.clear(); + fileEntries.clear(); + totalLength = 0; + pieceLength = 0; + fileMode = BtContext::SINGLE; + numPieces = 0; + name = ""; + announceTiers.clear(); +} + +void DefaultBtContext::extractPieceHash(const unsigned char* hashData, + int hashDataLength, + int hashLength) { + assert(hashDataLength > 0); + assert(hashLength > 0); + int numPieces = hashDataLength/hashLength; + assert(numPieces > 0); + + for(int i = 0; i < numPieces; i++) { + pieceHashes.push_back(Util::toHex(&hashData[i*hashLength], + hashLength)); + } +} + +void DefaultBtContext::extractFileEntries(Dictionary* infoDic, + const string& defaultName) { + // TODO use dynamic_cast + Data* nameData = (Data*)infoDic->get("name"); + if(nameData) { + name = nameData->toString(); + } else { + char* basec = strdup(defaultName.c_str()); + name = string(basename(basec))+".file"; + free(basec); + } + // TODO use dynamic_cast + List* files = (List*)infoDic->get("files"); + if(files) { + long long int length = 0; + long long int offset = 0; + // multi-file mode + fileMode = BtContext::MULTI; + const MetaList& metaList = files->getList(); + for(MetaList::const_iterator itr = metaList.begin(); + itr != metaList.end(); itr++) { + Dictionary* fileDic = (Dictionary*)(*itr); + // TODO use dynamic_cast + Data* lengthData = (Data*)fileDic->get("length"); + length += lengthData->toLLInt(); + // TODO use dynamic_cast + List* pathList = (List*)fileDic->get("path"); + const MetaList& paths = pathList->getList(); + string path; + for(int i = 0; i < (int)paths.size()-1; i++) { + Data* subpath = (Data*)paths.at(i); + path += subpath->toString()+"/"; + } + // TODO use dynamic_cast + Data* lastPath = (Data*)paths.back(); + path += lastPath->toString(); + + FileEntryHandle fileEntry(new FileEntry(path, + lengthData->toLLInt(), + offset)); + fileEntries.push_back(fileEntry); + offset += fileEntry->getLength(); + } + totalLength = length; + } else { + // single-file mode; + fileMode = BtContext::SINGLE; + Data* length = (Data*)infoDic->get("length"); + totalLength = length->toLLInt(); + FileEntryHandle fileEntry(new FileEntry(name, totalLength, 0)); + fileEntries.push_back(fileEntry); + } +} + +void DefaultBtContext::extractAnnounce(Data* announceData) { + Strings urls; + urls.push_back(announceData->toString()); + announceTiers.push_back(AnnounceTierHandle(new AnnounceTier(urls))); +} + +void DefaultBtContext::extractAnnounceList(List* announceListData) { + for(MetaList::const_iterator itr = announceListData->getList().begin(); + itr != announceListData->getList().end(); itr++) { + const List* elem = (List*)*itr; + Strings urls; + for(MetaList::const_iterator elemItr = elem->getList().begin(); + elemItr != elem->getList().end(); elemItr++) { + const Data* data = (Data*)*elemItr; + urls.push_back(data->toString()); + } + if(urls.size()) { + AnnounceTierHandle tier(new AnnounceTier(urls)); + announceTiers.push_back(tier); + } + } +} + +void DefaultBtContext::load(const string& torrentFile) { + clear(); + MetaEntry* rootEntry = MetaFileUtil::parseMetaFile(torrentFile); + if(!dynamic_cast(rootEntry)) { + throw new DlAbortEx("torrent file does not contain a root dictionary ."); + } + SharedHandle rootDic = + SharedHandle((Dictionary*)rootEntry); + Dictionary* infoDic = (Dictionary*)rootDic->get("info"); + // retrieve infoHash + ShaVisitor v; + infoDic->accept(&v); + int len; + v.getHash(infoHash, len); + infoHashString = Util::toHex(infoHash, INFO_HASH_LENGTH); + // calculate the number of pieces + Data* pieceHashData = (Data*)infoDic->get("pieces"); + numPieces = pieceHashData->getLen()/PIECE_HASH_LENGTH; + // retrieve piece length + Data* pieceLengthData = (Data*)infoDic->get("piece length"); + pieceLength = pieceLengthData->toInt(); + // retrieve piece hashes + extractPieceHash((unsigned char*)pieceHashData->getData(), + pieceHashData->getLen(), + PIECE_HASH_LENGTH); + // retrieve file entries + extractFileEntries(infoDic, torrentFile); + // retrieve announce + Data* announceData = (Data*)rootDic->get("announce"); + List* announceListData = (List*)rootDic->get("announce-list"); + if(announceListData) { + extractAnnounceList(announceListData); + } else if(announceData) { + extractAnnounce(announceData); + } + if(!announceTiers.size()) { + throw new DlAbortEx("No announce URL found."); + } +} + +string DefaultBtContext::getPieceHash(int index) const { + if(index < 0 || numPieces <= index) { + return ""; + } + return pieceHashes.at(index); +} + +long long int DefaultBtContext::getTotalLength() const { + return totalLength; +} + +BtContext::FILE_MODE DefaultBtContext::getFileMode() const { + return fileMode; +} + +FileEntries DefaultBtContext::getFileEntries() const { + return fileEntries; +} + +AnnounceTiers DefaultBtContext::getAnnounceTiers() const { + return announceTiers; +} + +string DefaultBtContext::getName() const { + return name; +} + +int DefaultBtContext::getPieceLength() const { + return pieceLength; +} + +int DefaultBtContext::getNumPieces() const { + return numPieces; +} diff --git a/src/DefaultBtContext.h b/src/DefaultBtContext.h new file mode 100644 index 00000000..74bae247 --- /dev/null +++ b/src/DefaultBtContext.h @@ -0,0 +1,97 @@ +/* */ +#ifndef _D_DEFAULT_BT_CONTEXT_H_ +#define _D_DEFAULT_BT_CONTEXT_H_ + +#include "BtContext.h" +#include "Dictionary.h" +#include "Data.h" +#include "List.h" +#define INFO_HASH_LENGTH 20 +#define PIECE_HASH_LENGTH 20 + +typedef Strings PieceHashes; + +class DefaultBtContext : public BtContext { +private: + unsigned char infoHash[INFO_HASH_LENGTH]; + string infoHashString; + PieceHashes pieceHashes; + FileEntries fileEntries; + FILE_MODE fileMode; + long long int totalLength; + int pieceLength; + string name; + int numPieces; + AnnounceTiers announceTiers; + + void clear(); + void extractPieceHash(const unsigned char* hashData, + int hashDataLength, + int hashLength); + void extractFileEntries(Dictionary* infoDic, + const string& defaultName); + void extractAnnounce(Data* announceData); + void extractAnnounceList(List* announceListData); + public: + DefaultBtContext(); + virtual ~DefaultBtContext(); + + virtual const unsigned char* getInfoHash() const; + + virtual int getInfoHashLength() const; + + virtual string getInfoHashAsString() const; + + virtual string getPieceHash(int index) const; + + virtual long long int getTotalLength() const; + + virtual FILE_MODE getFileMode() const; + + virtual FileEntries getFileEntries() const; + + virtual AnnounceTiers getAnnounceTiers() const; + + virtual void load(const string& torrentFile); + + virtual string getName() const; + + virtual int getPieceLength() const; + + virtual int getNumPieces() const; +}; + +#endif // _D_DEFAULT_BT_CONTEXT_H_ diff --git a/src/DefaultBtProgressInfoFile.cc b/src/DefaultBtProgressInfoFile.cc new file mode 100644 index 00000000..a524a589 --- /dev/null +++ b/src/DefaultBtProgressInfoFile.cc @@ -0,0 +1,172 @@ +/* */ +#include "DefaultBtProgressInfoFile.h" +#include "BtRegistry.h" +#include "LogFactory.h" +#include "prefs.h" +#include "DlAbortEx.h" +#include "message.h" +#include "File.h" +#include "Util.h" +#include + +DefaultBtProgressInfoFile::DefaultBtProgressInfoFile(const BtContextHandle& btContext, + const Option* option): + btContext(btContext), + option(option), + pieceStorage(PIECE_STORAGE(btContext)), + btRuntime(BT_RUNTIME(btContext)), + peerStorage(PEER_STORAGE(btContext)) +{ + logger = LogFactory::getInstance(); + string storeDir = option->get(PREF_DIR); + filename = storeDir+"/"+btContext->getName()+".aria2"; +} + +DefaultBtProgressInfoFile::~DefaultBtProgressInfoFile() {} + +void DefaultBtProgressInfoFile::save() { + logger->info(MSG_SAVING_SEGMENT_FILE, filename.c_str()); + FILE* file = openFile(filename, "w"); + try { + if(fwrite(btContext->getInfoHash(), + btContext->getInfoHashLength(), 1, file) < 1) { + throw string("writeError:info hash"); + } + if(fwrite(pieceStorage->getBitfield(), + pieceStorage->getBitfieldLength(), 1, file) < 1) { + throw string("writeError:bitfield"); + } + TransferStat stat = peerStorage->calculateStat(); + long long int allTimeDownloadLength = pieceStorage->getCompletedLength(); + if(fwrite(&allTimeDownloadLength, + sizeof(allTimeDownloadLength), 1, file) < 1) { + throw string("writeError:download length"); + } + long long int allTimeUploadLength = + btRuntime->getUploadLengthAtStartup()+ + stat.getSessionUploadLength(); + if(fwrite(&allTimeUploadLength, + sizeof(allTimeUploadLength), 1, file) < 1) { + throw string("writeError:upload length"); + } + fclose(file); + logger->info(MSG_SAVED_SEGMENT_FILE); + } catch(string ex) { + fclose(file); + throw new DlAbortEx(EX_SEGMENT_FILE_WRITE, + filename.c_str(), strerror(errno)); + } +} + +void DefaultBtProgressInfoFile::load() { + logger->info(MSG_LOADING_SEGMENT_FILE, filename.c_str()); + FILE* file = openFile(filename, "r+"); + unsigned char* savedInfoHash = 0; + unsigned char* savedBitfield = 0; + try { + savedInfoHash = new unsigned char[btContext->getInfoHashLength()]; + savedBitfield = new unsigned char[pieceStorage->getBitfieldLength()]; + if(fread(savedInfoHash, btContext->getInfoHashLength(), 1, file) < 1) { + throw string("readError"); + } + if(Util::toHex(savedInfoHash, btContext->getInfoHashLength()) != + btContext->getInfoHashAsString()) { + throw new DlAbortEx("Incorrect infoHash."); + } + if(fread(savedBitfield, pieceStorage->getBitfieldLength(), 1, file) < 1) { + throw string("readError"); + } + pieceStorage->setBitfield(savedBitfield, + pieceStorage->getBitfieldLength()); + // allTimeDownloadLength exists for only a compatibility reason. + long long int allTimeDownloadLength; + if(fread(&allTimeDownloadLength, + sizeof(allTimeDownloadLength), 1, file) < 1) { + throw string("readError"); + } + long long int allTimeUploadLength; + if(fread(&allTimeUploadLength, + sizeof(allTimeUploadLength), 1, file) < 1) { + throw string("readError"); + } + btRuntime->setUploadLengthAtStartup(allTimeUploadLength); + delete [] savedBitfield; + savedBitfield = 0; + delete [] savedInfoHash; + savedInfoHash = 0; + fclose(file); + } catch(string ex) { + if(savedBitfield) { + delete [] savedBitfield; + } + if(savedInfoHash) { + delete [] savedInfoHash; + } + fclose(file); + throw new DlAbortEx(EX_SEGMENT_FILE_READ, + filename.c_str(), strerror(errno)); + } + logger->info(MSG_LOADED_SEGMENT_FILE); +} + +void DefaultBtProgressInfoFile::removeFile() { + if(exists()) { + File f(filename); + f.remove(); + } +} + +FILE* DefaultBtProgressInfoFile::openFile(const string& filename, + const string& mode) const +{ + FILE* file = fopen(filename.c_str(), mode.c_str()); + if(!file) { + throw new DlAbortEx(EX_SEGMENT_FILE_OPEN, + filename.c_str(), strerror(errno)); + } + return file; +} + +bool DefaultBtProgressInfoFile::exists() { + File f(filename); + if(f.isFile()) { + logger->info(MSG_SEGMENT_FILE_EXISTS, filename.c_str()); + return true; + } else { + logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, filename.c_str()); + return false; + } +} diff --git a/src/DefaultBtProgressInfoFile.h b/src/DefaultBtProgressInfoFile.h new file mode 100644 index 00000000..201900dd --- /dev/null +++ b/src/DefaultBtProgressInfoFile.h @@ -0,0 +1,92 @@ +/* */ +#ifndef _D_DEFAULT_BT_PROGRESS_INFO_FILE_H_ +#define _D_DEFAULT_BT_PROGRESS_INFO_FILE_H_ + +#include "BtProgressInfoFile.h" +#include "BtContext.h" +#include "PieceStorage.h" +#include "BtRuntime.h" +#include "PeerStorage.h" +#include "Logger.h" +#include "Option.h" + +class DefaultBtProgressInfoFile : public BtProgressInfoFile { +private: + BtContextHandle btContext; + const Option* option; + Logger* logger; + PieceStorageHandle pieceStorage; + BtRuntimeHandle btRuntime; + PeerStorageHandle peerStorage; + string filename; + + FILE* openFile(const string& filename, const string& mode) const; +public: + DefaultBtProgressInfoFile(const BtContextHandle& btContext, + const Option* option); + virtual ~DefaultBtProgressInfoFile(); + + void setBtRuntime(const BtRuntimeHandle& btRuntime) { + this->btRuntime = btRuntime; + } + BtRuntimeHandle getBtRuntime() const { return btRuntime; } + + void setPieceStorage(const PieceStorageHandle& pieceStorage) { + this->pieceStorage = pieceStorage; + } + PieceStorageHandle getPieceStorage() const { return pieceStorage; } + + void setPeerStorage(const PeerStorageHandle& peerStorage) { + this->peerStorage = peerStorage; + } + PeerStorageHandle getPeerStorage() const { return peerStorage; } + + virtual void setFilename(const string& filename) { + this->filename = filename; + } + virtual string getFilename() { return filename; } + + virtual bool exists(); + + virtual void save(); + + virtual void load(); + + virtual void removeFile(); + +}; + +#endif // _D_DEFAULT_BT_PROGRESS_INFO_FILE_H_ diff --git a/src/DefaultPeerStorage.cc b/src/DefaultPeerStorage.cc new file mode 100644 index 00000000..456f99f2 --- /dev/null +++ b/src/DefaultPeerStorage.cc @@ -0,0 +1,174 @@ +/* */ +#include "DefaultPeerStorage.h" +#include "LogFactory.h" +#include "BtRegistry.h" + +extern PeerHandle nullPeer; + +DefaultPeerStorage::DefaultPeerStorage(BtContextHandle btContext, + const Option* option): + btContext(btContext), + option(option), + maxPeerListSize(MAX_PEER_LIST_SIZE), + peerEntryIdCounter(0), + btRuntime(BT_RUNTIME(btContext)) +{ + logger = LogFactory::getInstance(); +} + +DefaultPeerStorage::~DefaultPeerStorage() {} + +bool DefaultPeerStorage::addPeer(const PeerHandle& peer) { + Peers::iterator itr = find(peers.begin(), peers.end(), peer); + if(itr == peers.end()) { + if(peers.size() >= (size_t)maxPeerListSize) { + deleteUnusedPeer(peers.size()-maxPeerListSize+1); + } + ++peerEntryIdCounter; + peer->entryId = peerEntryIdCounter; + peers.push_back(peer); + return true; + } else { + const PeerHandle& peer = *itr; + if(peer->error >= MAX_PEER_ERROR || peer->cuid != 0) { + return false; + } else { + *itr = peer; + return true; + } + } +} + +void DefaultPeerStorage::addPeer(const Peers& peers) { + for(Peers::const_iterator itr = peers.begin(); + itr != peers.end(); itr++) { + const PeerHandle& peer = *itr; + if(addPeer(peer)) { + logger->debug("Adding peer %s:%d", + peer->ipaddr.c_str(), peer->port); + } + } +} + +const Peers& DefaultPeerStorage::getPeers() { + return peers; +} + +class FindFinePeer { +public: + bool operator()(const PeerHandle& peer) const { + return peer->cuid == 0 && peer->error < MAX_PEER_ERROR; + } +}; + +PeerHandle DefaultPeerStorage::getUnusedPeer() { + Peers::const_iterator itr = find_if(peers.begin(), peers.end(), + FindFinePeer()); + if(itr == peers.end()) { + return nullPeer; + } else { + return *itr; + } +} + +class FindPeer { +private: + string ipaddr; + int port; +public: + FindPeer(const string& ipaddr, int port):ipaddr(ipaddr), port(port) {} + + bool operator()(const PeerHandle& peer) const { + return ipaddr == peer->ipaddr && port == peer->port; + } +}; + +PeerHandle DefaultPeerStorage::getPeer(const string& ipaddr, + int port) const { + Peers::const_iterator itr = find_if(peers.begin(), peers.end(), + FindPeer(ipaddr, port)); + if(itr == peers.end()) { + return nullPeer; + } else { + return *itr; + } +} + +int DefaultPeerStorage::countPeer() const { + return peers.size(); +} + +bool DefaultPeerStorage::isPeerAvailable() { + return getUnusedPeer() != nullPeer; +} + +Peers DefaultPeerStorage::getActivePeers() { + Peers activePeers; + for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) { + PeerHandle& peer = *itr; + if(peer->isActive()) { + activePeers.push_back(peer); + } + } + return activePeers; +} + +TransferStat DefaultPeerStorage::calculateStat() { + TransferStat stat; + Peers activePeers = getActivePeers(); + for(Peers::iterator itr = activePeers.begin(); + itr != activePeers.end(); itr++) { + PeerHandle& peer = *itr; + stat.downloadSpeed += peer->calculateDownloadSpeed(); + stat.uploadSpeed += peer->calculateUploadSpeed(); + stat.sessionDownloadLength += peer->getSessionDownloadLength(); + stat.sessionUploadLength += peer->getSessionUploadLength(); + } + return stat; +} + +void DefaultPeerStorage::deleteUnusedPeer(int delSize) { + for(Peers::iterator itr = peers.begin(); + itr != peers.end() && delSize > 0;) { + const PeerHandle& p = *itr; + if(p->cuid == 0) { + itr = peers.erase(itr); + delSize--; + } else { + itr++; + } + } +} diff --git a/src/DefaultPeerStorage.h b/src/DefaultPeerStorage.h new file mode 100644 index 00000000..daabb69d --- /dev/null +++ b/src/DefaultPeerStorage.h @@ -0,0 +1,90 @@ +/* */ +#ifndef _D_DEFAULT_PEER_STORAGE_H_ +#define _D_DEFAULT_PEER_STORAGE_H_ + +#include "PeerStorage.h" +#include "BtContext.h" +#include "Option.h" +#include "Logger.h" +#include "BtRuntime.h" + +#define MAX_PEER_LIST_SIZE 100 +#define MAX_PEER_ERROR 5 + +class DefaultPeerStorage : public PeerStorage { +private: + BtContextHandle btContext; + const Option* option; + Peers peers; + int maxPeerListSize; + int peerEntryIdCounter; + Logger* logger; + BtRuntimeHandle btRuntime; +public: + DefaultPeerStorage(BtContextHandle btContext, const Option* option); + virtual ~DefaultPeerStorage(); + + void setBtRuntime(const BtRuntimeHandle& btRuntime) { + this->btRuntime = btRuntime; + } + BtRuntimeHandle getBtRuntime() const { return btRuntime; } + + virtual bool addPeer(const PeerHandle& peer); + + int countPeer() const; + + virtual PeerHandle getUnusedPeer(); + + PeerHandle getPeer(const string& ipaddr, int port) const; + + virtual void addPeer(const Peers& peers); + + virtual const Peers& getPeers(); + + virtual bool isPeerAvailable(); + + virtual Peers getActivePeers(); + + virtual TransferStat calculateStat(); + + void setMaxPeerListSize(int size) { this->maxPeerListSize = size; } + + int getMaxPeerListSize() const { return maxPeerListSize; } + + void deleteUnusedPeer(int delSize); +}; + +#endif // _D_DEFAULT_PEER_STORAGE_H_ diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc new file mode 100644 index 00000000..c819934f --- /dev/null +++ b/src/DefaultPieceStorage.cc @@ -0,0 +1,433 @@ +/* */ +#include "DefaultPieceStorage.h" +#include "LogFactory.h" +#include "prefs.h" +#include "DirectDiskAdaptor.h" +#include "MultiDiskAdaptor.h" +#include "CopyDiskAdaptor.h" +#include "DefaultDiskWriter.h" +#include "MultiDiskWriter.h" +#include "PreAllocationDiskWriter.h" +#include "DlAbortEx.h" + +DefaultPieceStorage::DefaultPieceStorage(BtContextHandle btContext, const Option* option): + btContext(btContext), + endGamePieceNum(END_GAME_PIECE_NUM), + option(option) +{ + bitfieldMan = new BitfieldMan(btContext->getPieceLength(), + btContext->getTotalLength()); + logger = LogFactory::getInstance(); +} + +DefaultPieceStorage::~DefaultPieceStorage() { + delete bitfieldMan; +} + +bool DefaultPieceStorage::hasMissingPiece(const PeerHandle& peer) { + return bitfieldMan->hasMissingPiece(peer->getBitfield(), + peer->getBitfieldLength()); +} + +bool DefaultPieceStorage::isEndGame() { + return bitfieldMan->countMissingBlock() <= endGamePieceNum; +} + +int DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer) { + int index = -1; + if(isEndGame()) { + index = bitfieldMan->getMissingIndex(peer->getBitfield(), + peer->getBitfieldLength()); + } else { + index = bitfieldMan->getMissingUnusedIndex(peer->getBitfield(), + peer->getBitfieldLength()); + } + return index; +} + +Piece DefaultPieceStorage::checkOutPiece(int index) { + if(index == -1) { + return Piece::nullPiece; + } + bitfieldMan->setUseBit(index); + + Piece piece = findUsedPiece(index); + if(Piece::isNull(piece)) { + Piece piece(index, bitfieldMan->getBlockLength(index)); + addUsedPiece(piece); + return piece; + } else { + return piece; + } +} + +void DefaultPieceStorage::addUsedPiece(const Piece& piece) { + // TODO ? if nullPiece + usedPieces.push_back(piece); +} + +class FindPiece { +private: + int index; +public: + FindPiece(int index):index(index) {} + + bool operator()(const Piece& piece) { + return piece.getIndex() == index; + } +}; + +Piece DefaultPieceStorage::findUsedPiece(int index) const { + Pieces::const_iterator itr = find_if(usedPieces.begin(), + usedPieces.end(), + FindPiece(index)); + if(itr == usedPieces.end()) { + return Piece::nullPiece; + } else { + return *itr; + } +} + +Piece DefaultPieceStorage::getMissingPiece(const PeerHandle& peer) { + int index = getMissingPieceIndex(peer); + return checkOutPiece(index); +} + +int DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer) { + int index = -1; + if(peer->isFastExtensionEnabled() && peer->countFastSet() > 0) { + BitfieldMan tempBitfield(bitfieldMan->getBlockLength(), + bitfieldMan->getTotalLength()); + for(Integers::const_iterator itr = peer->getFastSet().begin(); + itr != peer->getFastSet().end(); itr++) { + if(!bitfieldMan->isBitSet(index) && peer->hasPiece(*itr)) { + tempBitfield.setBit(*itr); + } + } + if(isEndGame()) { + index = bitfieldMan->getMissingIndex(tempBitfield.getBitfield(), + tempBitfield.getBitfieldLength()); + } else { + index = bitfieldMan->getMissingUnusedIndex(tempBitfield.getBitfield(), + tempBitfield.getBitfieldLength()); + } + } + return index; +} + +Piece DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer) { + int index = getMissingFastPieceIndex(peer); + return checkOutPiece(index); +} + +void DefaultPieceStorage::deleteUsedPiece(const Piece& piece) { + if(Piece::isNull(piece)) { + return; + } + Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), piece); + if(itr != usedPieces.end()) { + usedPieces.erase(itr); + } +} + +void DefaultPieceStorage::reduceUsedPieces(int delMax) { + int toDelete = usedPieces.size()-delMax; + if(toDelete <= 0) { + return; + } + int fillRate = 10; + while(fillRate < 50) { + int deleted = deleteUsedPiecesByFillRate(fillRate, toDelete); + if(deleted == 0) { + break; + } + toDelete -= deleted; + fillRate += 10; + } +} + +int DefaultPieceStorage::deleteUsedPiecesByFillRate(int fillRate, + int toDelete) { + int deleted = 0; + for(Pieces::iterator itr = usedPieces.begin(); + itr != usedPieces.end() && deleted < toDelete;) { + Piece& piece = *itr; + if(!bitfieldMan->isUseBitSet(piece.getIndex()) && + piece.countCompleteBlock() <= piece.countBlock()*(fillRate/100.0)) { + logger->debug("Deleting used piece index=%d, fillRate(%%)=%d<=%d", + piece.getIndex(), + (piece.countCompleteBlock()*100)/piece.countBlock(), + fillRate); + itr = usedPieces.erase(itr); + deleted++; + } else { + itr++; + } + } + return deleted; +} + +void DefaultPieceStorage::completePiece(const Piece& piece) { + if(Piece::isNull(piece)) { + return; + } + deleteUsedPiece(piece); + if(!isEndGame()) { + reduceUsedPieces(100); + } + if(downloadFinished()) { + return; + } + bitfieldMan->setBit(piece.getIndex()); + bitfieldMan->unsetUseBit(piece.getIndex()); + if(downloadFinished()) { + diskAdaptor->onDownloadComplete(); + if(isSelectiveDownloadingMode()) { + logger->notice(_("Download of selected files was complete.")); + finishSelectiveDownloadingMode(); + } else { + logger->info(_("The download was complete.")); + } + } +} + +bool DefaultPieceStorage::isSelectiveDownloadingMode() { + return bitfieldMan->isFilterEnabled(); +} + +void DefaultPieceStorage::finishSelectiveDownloadingMode() { + bitfieldMan->clearFilter(); + diskAdaptor->addAllDownloadEntry(); +} + +// not unittested +void DefaultPieceStorage::cancelPiece(const Piece& piece) { + if(Piece::isNull(piece)) { + return; + } + updatePiece(piece); + bitfieldMan->unsetUseBit(piece.getIndex()); + if(!isEndGame()) { + if(piece.countCompleteBlock() == 0) { + deleteUsedPiece(piece); + } + } +} + +// not unittested +void DefaultPieceStorage::updatePiece(const Piece& piece) { + if(Piece::isNull(piece)) { + return; + } + Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), + piece); + if(itr != usedPieces.end()) { + *itr = piece; + } +} + +// not unittested +void DefaultPieceStorage::syncPiece(Piece& piece) { + if(Piece::isNull(piece)) { + return; + } + Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), + piece); + if(itr != usedPieces.end()) { + piece = *itr; + return; + } else { + // hasPiece(piece.getIndex()) is true, then set all bit of + // piece.bitfield to 1 + if(hasPiece(piece.getIndex())) { + piece.setAllBlock(); + } + } +} + +bool DefaultPieceStorage::hasPiece(int index) { + return bitfieldMan->isBitSet(index); +} + +long long int DefaultPieceStorage::getTotalLength() { + return bitfieldMan->getTotalLength(); +} + +long long int DefaultPieceStorage::getFilteredTotalLength() { + return bitfieldMan->getFilteredTotalLength(); +} + +long long int DefaultPieceStorage::getCompletedLength() { + return bitfieldMan->getCompletedLength(); +} + +long long int DefaultPieceStorage::getFilteredCompletedLength() { + return bitfieldMan->getFilteredCompletedLength(); +} + +// not unittested +void DefaultPieceStorage::setFileFilter(const Strings& filePaths) { + if(btContext->getFileMode() != BtContext::MULTI || filePaths.empty()) { + return; + } + diskAdaptor->removeAllDownloadEntry(); + for(Strings::const_iterator pitr = filePaths.begin(); + pitr != filePaths.end(); pitr++) { + if(!diskAdaptor->addDownloadEntry(*pitr)) { + throw new DlAbortEx("No such file entry %s", (*pitr).c_str()); + } + FileEntryHandle fileEntry = diskAdaptor->getFileEntryFromPath(*pitr); + bitfieldMan->addFilter(fileEntry->getOffset(), fileEntry->getLength()); + } + bitfieldMan->enableFilter(); +} + +void DefaultPieceStorage::setFileFilter(const Integers& fileIndexes) { + Strings filePaths; + const FileEntries& entries = diskAdaptor->getFileEntries(); + for(int i = 0; i < (int)entries.size(); i++) { + if(find(fileIndexes.begin(), fileIndexes.end(), i+1) != fileIndexes.end()) { + logger->debug("index=%d is %s", i+1, entries.at(i)->getPath().c_str()); + filePaths.push_back(entries.at(i)->getPath()); + } + } + setFileFilter(filePaths); +} + +// not unittested +void DefaultPieceStorage::clearFileFilter() { + bitfieldMan->clearFilter(); + diskAdaptor->addAllDownloadEntry(); +} + +// not unittested +bool DefaultPieceStorage::downloadFinished() { + return bitfieldMan->isAllBitSet(); +} + +// not unittested +void DefaultPieceStorage::initStorage() { + if(diskAdaptor) { + delete diskAdaptor; + diskAdaptor = 0; + } + if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) { + if(btContext->getFileMode() == BtContext::SINGLE) { + diskAdaptor = new DirectDiskAdaptor(new DefaultDiskWriter(btContext->getTotalLength())); + } else { + diskAdaptor = new MultiDiskAdaptor(new MultiDiskWriter(btContext->getPieceLength())); + } + } else { + diskAdaptor = new CopyDiskAdaptor(new PreAllocationDiskWriter(btContext->getTotalLength())); + ((CopyDiskAdaptor*)diskAdaptor)->setTempFilename(btContext->getName()+".a2tmp"); + } + string storeDir = option->get(PREF_DIR); + if(storeDir == "") { + storeDir = "."; + } + if(btContext->getFileMode() == BtContext::MULTI) { + storeDir += "/"+btContext->getName(); + } + diskAdaptor->setStoreDir(storeDir); + diskAdaptor->setFileEntries(btContext->getFileEntries()); +} + +void DefaultPieceStorage::setBitfield(const unsigned char* bitfield, + int bitfieldLength) { + bitfieldMan->setBitfield(bitfield, bitfieldLength); +} + +int DefaultPieceStorage::getBitfieldLength() { + return bitfieldMan->getBitfieldLength(); +} + +const unsigned char* DefaultPieceStorage::getBitfield() { + return bitfieldMan->getBitfield(); +} + +DiskAdaptor* DefaultPieceStorage::getDiskAdaptor() { + return diskAdaptor; +} + +int DefaultPieceStorage::getPieceLength(int index) { + return bitfieldMan->getBlockLength(index); +} + +void DefaultPieceStorage::advertisePiece(int cuid, int index) { + HaveEntry entry(cuid, index); + haves.push_front(entry); +} + +Integers DefaultPieceStorage::getAdvertisedPieceIndexes(int myCuid, + const Time& lastCheckTime) { + Integers indexes; + for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) { + const Haves::value_type& have = *itr; + if(have.getCuid() == myCuid) { + continue; + } + if(lastCheckTime.isNewer(have.getRegisteredTime())) { + break; + } + indexes.push_back(have.getIndex()); + } + return indexes; +} + +class FindElapsedHave +{ +private: + int elapsed; +public: + FindElapsedHave(int elapsed):elapsed(elapsed) {} + + bool operator()(const HaveEntry& have) { + if(have.getRegisteredTime().elapsed(elapsed)) { + return true; + } else { + return false; + } + } +}; + +void DefaultPieceStorage::removeAdvertisedPiece(int elapsed) { + Haves::iterator itr = + find_if(haves.begin(), haves.end(), FindElapsedHave(elapsed)); + if(itr != haves.end()) { + logger->debug("Removed %d have entries.", haves.end()-itr); + haves.erase(itr, haves.end()); + } +} diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h new file mode 100644 index 00000000..4b9a2066 --- /dev/null +++ b/src/DefaultPieceStorage.h @@ -0,0 +1,158 @@ +/* */ +#ifndef _D_DEFAULT_PIECE_STORAGE_H_ +#define _D_DEFAULT_PIECE_STORAGE_H_ + +#include "PieceStorage.h" +#include "BtContext.h" +#include "DiskAdaptor.h" +#include "BitfieldMan.h" +#include "Logger.h" +#include "Option.h" +#include "Piece.h" + +#define END_GAME_PIECE_NUM 20 + +class HaveEntry { +private: + int cuid; + int index; + Time registeredTime; +public: + HaveEntry(int cuid, int index): + cuid(cuid), + index(index) {} + + int getCuid() const { return cuid; } + + int getIndex() const { return index; } + + const Time& getRegisteredTime() const { return registeredTime; } +}; + +typedef deque Haves; + +class DefaultPieceStorage : public PieceStorage { +private: + BtContextHandle btContext; + BitfieldMan* bitfieldMan; + DiskAdaptor* diskAdaptor; + Pieces usedPieces; + int endGamePieceNum; + Logger* logger; + const Option* option; + Haves haves; + + int getMissingPieceIndex(const PeerHandle& peer); + int getMissingFastPieceIndex(const PeerHandle& peer); + Piece checkOutPiece(int index); + void addUsedPiece(const Piece& piece); + Piece findUsedPiece(int index) const; + int deleteUsedPiecesByFillRate(int fillRate, int toDelete); + void reduceUsedPieces(int delMax); + void deleteUsedPiece(const Piece& piece); +public: + DefaultPieceStorage(BtContextHandle btContext, const Option* option); + virtual ~DefaultPieceStorage(); + + virtual bool hasMissingPiece(const PeerHandle& peer); + + virtual Piece getMissingPiece(const PeerHandle& peer); + + virtual Piece getMissingFastPiece(const PeerHandle& peer); + + virtual void completePiece(const Piece& piece); + + virtual void cancelPiece(const Piece& piece); + + virtual void updatePiece(const Piece& piece); + + virtual void syncPiece(Piece& piece); + + virtual bool hasPiece(int index); + + virtual long long int getTotalLength(); + + virtual long long int getFilteredTotalLength(); + + virtual long long int getCompletedLength(); + + virtual long long int getFilteredCompletedLength(); + + virtual void initStorage(); + + virtual void setFileFilter(const Strings& filePaths); + + virtual void setFileFilter(const Integers& fileIndexes); + + virtual void clearFileFilter(); + + virtual bool downloadFinished(); + + virtual void setBitfield(const unsigned char* bitfield, + int bitfieldLength); + + virtual int getBitfieldLength(); + + virtual const unsigned char* getBitfield(); + + void setEndGamePieceNum(int num) { + endGamePieceNum = num; + } + + int getEndGamePieceNum() const { + return endGamePieceNum; + } + + virtual bool isSelectiveDownloadingMode(); + + virtual void finishSelectiveDownloadingMode(); + + virtual bool isEndGame(); + + virtual DiskAdaptor* getDiskAdaptor(); + + virtual int getPieceLength(int index); + + virtual void advertisePiece(int cuid, int index); + + virtual Integers getAdvertisedPieceIndexes(int myCuid, + const Time& lastCheckTime); + + virtual void removeAdvertisedPiece(int elapsed); + +}; + +#endif // _D_DEFAULT_PIECE_STORAGE_H_ diff --git a/src/DelegatingPeerListProcessor.cc b/src/DelegatingPeerListProcessor.cc index b91554bb..38f9395c 100644 --- a/src/DelegatingPeerListProcessor.cc +++ b/src/DelegatingPeerListProcessor.cc @@ -54,4 +54,5 @@ bool DelegatingPeerListProcessor::canHandle(const MetaEntry* peersEntry) const { return true; } } + return false; } diff --git a/src/DirectDiskAdaptor.cc b/src/DirectDiskAdaptor.cc index f360393c..290516e7 100644 --- a/src/DirectDiskAdaptor.cc +++ b/src/DirectDiskAdaptor.cc @@ -39,7 +39,7 @@ DirectDiskAdaptor::DirectDiskAdaptor(DiskWriter* diskWriter):DiskAdaptor(diskWri DirectDiskAdaptor::~DirectDiskAdaptor() {} string DirectDiskAdaptor::getFilePath() const { - return storeDir+"/"+fileEntries.front().path; + return storeDir+"/"+fileEntries.front()->getPath(); } void DirectDiskAdaptor::onDownloadComplete() { diff --git a/src/Directory.cc b/src/Directory.cc index f3e2f2b3..c342f94b 100644 --- a/src/Directory.cc +++ b/src/Directory.cc @@ -42,6 +42,8 @@ Directory::Directory(const string& name):name(name) {} +Directory::Directory() {} + Directory::~Directory() { for(Files::iterator itr = files.begin(); itr != files.end(); itr++) { delete *itr; @@ -49,6 +51,9 @@ Directory::~Directory() { } void Directory::createDir(const string& parentDir, bool recursive) const { + if(name.size() == 0) { + return; + } string path = parentDir+"/"+name; File f(path); if(f.exists()) { diff --git a/src/Directory.h b/src/Directory.h index 1eef65fb..e3fb8cd9 100644 --- a/src/Directory.h +++ b/src/Directory.h @@ -48,10 +48,13 @@ private: Files files; public: Directory(const string& name); + Directory(); ~Directory(); void createDir(const string& parentDir, bool recursive) const; void addFile(Directory* directory); }; +typedef SharedHandle DirectoryHandle; + #endif // _D_DIRECTORY_H_ diff --git a/src/DiskAdaptor.cc b/src/DiskAdaptor.cc index 2ed4d2c2..9044b31b 100644 --- a/src/DiskAdaptor.cc +++ b/src/DiskAdaptor.cc @@ -36,15 +36,12 @@ #include "DlAbortEx.h" #include "LogFactory.h" -DiskAdaptor::DiskAdaptor(DiskWriter* diskWriter):diskWriter(diskWriter), topDir(NULL) { +DiskAdaptor::DiskAdaptor(DiskWriter* diskWriter):diskWriter(diskWriter) { logger = LogFactory::getInstance(); } DiskAdaptor::~DiskAdaptor() { delete diskWriter; - if(topDir != NULL) { - delete topDir; - } } void DiskAdaptor::openFile() { @@ -75,10 +72,10 @@ string DiskAdaptor::sha1Sum(long long int offset, long long int length) { return diskWriter->sha1Sum(offset, length); } -FileEntry DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const { +FileEntryHandle DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const { for(FileEntries::const_iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { - if(itr->path == fileEntryPath) { + if((*itr)->getPath() == fileEntryPath) { return *itr; } } @@ -88,8 +85,8 @@ FileEntry DiskAdaptor::getFileEntryFromPath(const string& fileEntryPath) const { bool DiskAdaptor::addDownloadEntry(const string& fileEntryPath) { for(FileEntries::iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { - if(itr->path == fileEntryPath) { - itr->requested = true; + if((*itr)->getPath() == fileEntryPath) { + (*itr)->setRequested(true); return true; } } @@ -100,20 +97,20 @@ bool DiskAdaptor::addDownloadEntry(int index) { if(fileEntries.size() <= (unsigned int)index) { return false; } - fileEntries.at(index).requested = true; + fileEntries.at(index)->setRequested(true); return true; } void DiskAdaptor::addAllDownloadEntry() { for(FileEntries::iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { - itr->requested = true; + (*itr)->setRequested(true); } } void DiskAdaptor::removeAllDownloadEntry() { for(FileEntries::iterator itr = fileEntries.begin(); itr != fileEntries.end(); itr++) { - itr->requested = false; + (*itr)->setRequested(false); } } diff --git a/src/DiskAdaptor.h b/src/DiskAdaptor.h index 276def84..a172cd4f 100644 --- a/src/DiskAdaptor.h +++ b/src/DiskAdaptor.h @@ -40,13 +40,13 @@ #include "Directory.h" #include "DiskWriter.h" #include "Logger.h" +#include "FileEntry.h" class DiskAdaptor { protected: DiskWriter* diskWriter; string storeDir; FileEntries fileEntries; - const Directory* topDir; const Logger* logger; virtual string getFilePath() const = 0; public: @@ -66,7 +66,9 @@ public: void setFileEntries(const FileEntries& fileEntries) { this->fileEntries = fileEntries; } - FileEntry getFileEntryFromPath(const string& fileEntryPath) const; + + FileEntryHandle getFileEntryFromPath(const string& fileEntryPath) const; + const FileEntries& getFileEntries() const { return fileEntries; } bool addDownloadEntry(const string& fileEntryPath); @@ -75,15 +77,8 @@ public: void removeAllDownloadEntry(); void setStoreDir(const string& storeDir) { this->storeDir = storeDir; } - string getStoreDir() const { return this->storeDir; } - void setTopDir(const Directory* dirctory) { - if(this->topDir != NULL) { - delete topDir; - } - this->topDir = dirctory; - } - const Directory* getTopDir() const { return this->topDir; } + string getStoreDir() const { return this->storeDir; } }; #endif // _D_DISK_ADAPTOR_H_ diff --git a/src/DownloadEngineFactory.cc b/src/DownloadEngineFactory.cc index 6ac1d745..2bb84da2 100644 --- a/src/DownloadEngineFactory.cc +++ b/src/DownloadEngineFactory.cc @@ -49,6 +49,10 @@ # include "UnionSeedCriteria.h" # include "TimeSeedCriteria.h" # include "ShareRatioSeedCriteria.h" +# include "DefaultPieceStorage.h" +# include "DefaultPeerStorage.h" +# include "DefaultBtAnnounce.h" +# include "DefaultBtProgressInfoFile.h" #endif // ENABLE_BITTORRENT ConsoleDownloadEngine* @@ -76,8 +80,8 @@ DownloadEngineFactory::newConsoleEngine(const Option* op, #ifdef ENABLE_BITTORRENT TorrentConsoleDownloadEngine* -DownloadEngineFactory::newTorrentConsoleEngine(const Option* op, - const string& torrentFile, +DownloadEngineFactory::newTorrentConsoleEngine(const BtContextHandle& btContext, + const Option* op, const Strings& targetFiles) { TorrentConsoleDownloadEngine* te = new TorrentConsoleDownloadEngine(); @@ -86,19 +90,44 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op, te->segmentMan = new SegmentMan(); te->segmentMan->diskWriter = byteArrayDiskWriter; te->segmentMan->option = op; - te->torrentMan = new TorrentMan(); - te->torrentMan->setStoreDir(op->get(PREF_DIR)); - te->torrentMan->option = op; + BtRuntimeHandle btRuntime(new BtRuntime()); + BtRegistry::registerBtRuntime(btContext->getInfoHashAsString(), btRuntime); + + PieceStorageHandle pieceStorage(new DefaultPieceStorage(btContext, op)); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), pieceStorage); + + PeerStorageHandle peerStorage(new DefaultPeerStorage(btContext, op)); + BtRegistry::registerPeerStorage(btContext->getInfoHashAsString(), peerStorage); + + BtAnnounceHandle btAnnounce(new DefaultBtAnnounce(btContext, op)); + BtRegistry::registerBtAnnounce(btContext->getInfoHashAsString(), btAnnounce); + btAnnounce->shuffleAnnounce(); + + BtProgressInfoFileHandle btProgressInfoFile(new DefaultBtProgressInfoFile(btContext, op)); + BtRegistry::registerBtProgressInfoFile(btContext->getInfoHashAsString(), + btProgressInfoFile); + + te->setBtContext(btContext); + // initialize file storage + pieceStorage->initStorage(); + if(btProgressInfoFile->exists()) { + // load .aria2 file if it exists. + btProgressInfoFile->load(); + pieceStorage->getDiskAdaptor()->openExistingFile(); + } else { + pieceStorage->getDiskAdaptor()->initAndOpenFile(); + } + Integers selectIndexes; Util::unfoldRange(op->get(PREF_SELECT_FILE), selectIndexes); if(selectIndexes.size()) { - te->torrentMan->setup(torrentFile, selectIndexes); + pieceStorage->setFileFilter(selectIndexes); } else { - te->torrentMan->setup(torrentFile, targetFiles); + pieceStorage->setFileFilter(targetFiles); } PeerListenCommand* listenCommand = - new PeerListenCommand(te->torrentMan->getNewCuid(), te); + new PeerListenCommand(btRuntime->getNewCuid(), te, btContext); int port; int listenPort = op->getAsInt(PREF_LISTEN_PORT); if(listenPort == -1) { @@ -110,31 +139,39 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op, printf(_("Errors occurred while binding port.\n")); exit(EXIT_FAILURE); } - te->torrentMan->setPort(port); + btRuntime->setListenPort(port); te->commands.push_back(listenCommand); - te->commands.push_back(new TrackerWatcherCommand(te->torrentMan->getNewCuid(), - te)); - te->commands.push_back(new TrackerUpdateCommand(te->torrentMan->getNewCuid(), - te)); - te->commands.push_back(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(), + te->commands.push_back(new TrackerWatcherCommand(btRuntime->getNewCuid(), + te, + btContext)); + te->commands.push_back(new TrackerUpdateCommand(btRuntime->getNewCuid(), + te, + btContext)); + te->commands.push_back(new TorrentAutoSaveCommand(btRuntime->getNewCuid(), te, + btContext, op->getAsInt(PREF_AUTO_SAVE_INTERVAL))); - te->commands.push_back(new PeerChokeCommand(te->torrentMan->getNewCuid(), - te, 10)); - te->commands.push_back(new HaveEraseCommand(te->torrentMan->getNewCuid(), - te, 10)); + te->commands.push_back(new PeerChokeCommand(btRuntime->getNewCuid(), + te, + btContext, + 10)); + te->commands.push_back(new HaveEraseCommand(btRuntime->getNewCuid(), + te, + btContext, + 10)); SharedHandle unionCri = new UnionSeedCriteria(); if(op->defined(PREF_SEED_TIME)) { unionCri->addSeedCriteria(new TimeSeedCriteria(op->getAsInt(PREF_SEED_TIME)*60)); } if(op->defined(PREF_SEED_RATIO)) { - unionCri->addSeedCriteria(new ShareRatioSeedCriteria(op->getAsDouble(PREF_SEED_RATIO), te->torrentMan)); + unionCri->addSeedCriteria(new ShareRatioSeedCriteria(op->getAsDouble(PREF_SEED_RATIO), btContext)); } if(unionCri->getSeedCriterion().size() > 0) { - te->commands.push_back(new SeedCheckCommand(te->torrentMan->getNewCuid(), + te->commands.push_back(new SeedCheckCommand(btRuntime->getNewCuid(), te, + btContext, unionCri)); } return te; diff --git a/src/DownloadEngineFactory.h b/src/DownloadEngineFactory.h index 33ee1299..f5f801c3 100644 --- a/src/DownloadEngineFactory.h +++ b/src/DownloadEngineFactory.h @@ -50,8 +50,8 @@ public: #ifdef ENABLE_BITTORRENT static TorrentConsoleDownloadEngine* - newTorrentConsoleEngine(const Option* option, - const string& torrentFile, + newTorrentConsoleEngine(const BtContextHandle& btContext, + const Option* option, const Strings& targetFiles); #endif // ENABLE_BITTORRENT }; diff --git a/src/File.cc b/src/File.cc index 459f6b53..0cd732b8 100644 --- a/src/File.cc +++ b/src/File.cc @@ -33,6 +33,7 @@ */ /* copyright --> */ #include "File.h" +#include "Util.h" #include #include #include @@ -83,3 +84,30 @@ long long int File::size() { } return fstat.st_size; } + +bool File::mkdirs() { + if(isDir()) { + return false; + } + Strings dirs; + Util::slice(dirs, name, '/'); + if(!dirs.size()) { + return true; + } + string accDir; + if(Util::startsWith(name, "/")) { + accDir = "/"; + } + mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR; + for(Strings::const_iterator itr = dirs.begin(); itr != dirs.end(); + itr++, accDir += "/") { + accDir += *itr; + if(File(accDir).isDir()) { + continue; + } + if(mkdir(accDir.c_str(), mode) == -1) { + return false; + } + } + return true; +} diff --git a/src/File.h b/src/File.h index 1e3e8134..033c6598 100644 --- a/src/File.h +++ b/src/File.h @@ -72,6 +72,15 @@ public: */ bool remove(); + /** + * Creates the directory denoted by name. + * This method creates complete directory structure. + * Returns true if the directory is created successfully, otherwise returns + * false. + * If the directory already exists, then returns false. + */ + bool mkdirs(); + long long int size(); }; diff --git a/src/FileEntry.cc b/src/FileEntry.cc new file mode 100644 index 00000000..1e74ffa8 --- /dev/null +++ b/src/FileEntry.cc @@ -0,0 +1,64 @@ +/* */ +#include "FileEntry.h" +#include "File.h" +#include "DlAbortEx.h" +#include + +FileEntry::FileEntry(const string& path, + long long int length, + long long int offset): + path(path), length(length), offset(offset), + extracted(false), requested(true) {} + +FileEntry::~FileEntry() {} + +void FileEntry::setupDir(const string& parentDir) { + string absPath = parentDir+"/"+path; + char* temp = strdup(absPath.c_str()); + string dir = string(dirname(temp)); + free(temp); + if(!dir.size()) { + return; + } + File f(dir); + if(f.isDir()) { + // nothing to do + } else if(f.exists()) { + throw new DlAbortEx("%s is not a directory.", dir.c_str()); + } else if(!f.mkdirs()) { + throw new DlAbortEx("Failed to create directory %s.", dir.c_str()); + } +} diff --git a/src/FileEntry.h b/src/FileEntry.h index 5c7281d0..0113921a 100644 --- a/src/FileEntry.h +++ b/src/FileEntry.h @@ -38,18 +38,41 @@ #include "common.h" class FileEntry { -public: +private: string path; long long int length; long long int offset; bool extracted; bool requested; - FileEntry(const string& path, long long int length, long long int offset): - path(path), length(length), offset(offset), - extracted(false), requested(true) {} - ~FileEntry() {} +public: + FileEntry(const string& path, long long int length, long long int offset); + + ~FileEntry(); + + const string& getPath() const { return path; } + + void setPath(const string& path) { this->path = path; } + + long long int getLength() const { return length; } + + void setLength(long long int length) { this->length = length; } + + long long int getOffset() const { return offset; } + + void setOffset(long long int offset) { this->offset = offset; } + + bool isExtracted() const { return extracted; } + + void setExtracted(bool flag) { this->extracted = flag; } + + bool isRequested() const { return requested; } + + void setRequested(bool flag) { this->requested = flag; } + + void setupDir(const string& parentDir); }; -typedef deque FileEntries; +typedef SharedHandle FileEntryHandle; +typedef deque FileEntries; #endif // _D_FILE_ENTRY_H_ diff --git a/src/HandshakeMessage.cc b/src/HandshakeMessage.cc index a3af8579..9e9fd390 100644 --- a/src/HandshakeMessage.cc +++ b/src/HandshakeMessage.cc @@ -93,7 +93,7 @@ string HandshakeMessage::toString() const { void HandshakeMessage::check() const { PeerMessageUtil::checkHandshake(this, - peerInteraction->getTorrentMan()->getInfoHash()); + peerInteraction->getBtContext()->getInfoHash()); } bool HandshakeMessage::isFastExtensionSupported() const { diff --git a/src/HandshakeMessage.h b/src/HandshakeMessage.h index bd2ff0ae..6c931c91 100644 --- a/src/HandshakeMessage.h +++ b/src/HandshakeMessage.h @@ -36,7 +36,6 @@ #define _D_HANDSHAKE_MESSAGE_H_ #include "SimplePeerMessage.h" -#include "TorrentMan.h" #define PSTR "BitTorrent protocol" #define HANDSHAKE_MESSAGE_LENGTH 68 diff --git a/src/HaveEraseCommand.cc b/src/HaveEraseCommand.cc index d0fb3b2d..0758d10a 100644 --- a/src/HaveEraseCommand.cc +++ b/src/HaveEraseCommand.cc @@ -34,13 +34,21 @@ /* copyright --> */ #include "HaveEraseCommand.h" +HaveEraseCommand::HaveEraseCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + int interval) + :BtContextAwareCommand(cuid, btContext), + e(e), + interval(interval) {} + bool HaveEraseCommand::execute() { - if(e->torrentMan->isHalt()) { + if(btRuntime->isHalt()) { return true; } if(cp.elapsed(interval)) { cp.reset(); - e->torrentMan->removeAdvertisedPiece(5); + pieceStorage->removeAdvertisedPiece(5); } e->commands.push_back(this); return false; diff --git a/src/HaveEraseCommand.h b/src/HaveEraseCommand.h index 7730111f..59a663bf 100644 --- a/src/HaveEraseCommand.h +++ b/src/HaveEraseCommand.h @@ -35,19 +35,19 @@ #ifndef _D_HAVE_ERASE_COMMAND_H_ #define _D_HAVE_ERASE_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" -class HaveEraseCommand : public Command { +class HaveEraseCommand : public BtContextAwareCommand { private: TorrentDownloadEngine* e; Time cp; int interval; public: - HaveEraseCommand(int cuid, TorrentDownloadEngine* e, int interval) - :Command(cuid), - e(e), - interval(interval) {} + HaveEraseCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + int interval); virtual ~HaveEraseCommand() {} diff --git a/src/Makefile.am b/src/Makefile.am index 3807881e..e7860354 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -69,7 +69,6 @@ SRCS += MetaEntry.h\ MetaFileUtil.cc MetaFileUtil.h\ MetaEntryVisitor.h\ ShaVisitor.cc ShaVisitor.h\ - TorrentMan.cc TorrentMan.h\ PeerConnection.cc PeerConnection.h\ PeerMessageUtil.cc PeerMessageUtil.h\ PeerAbstractCommand.cc PeerAbstractCommand.h\ @@ -92,7 +91,7 @@ SRCS += MetaEntry.h\ CopyDiskAdaptor.cc CopyDiskAdaptor.h\ DirectDiskAdaptor.cc DirectDiskAdaptor.h\ MultiDiskAdaptor.cc MultiDiskAdaptor.h\ - FileEntry.h\ + FileEntry.cc FileEntry.h\ TrackerUpdateCommand.cc TrackerUpdateCommand.h\ ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\ PeerChokeCommand.cc PeerChokeCommand.h\ @@ -125,7 +124,21 @@ SRCS += MetaEntry.h\ DefaultPeerListProcessor.cc DefaultPeerListProcessor.h\ CompactPeerListProcessor.cc CompactPeerListProcessor.h\ DelegatingPeerListProcessor.cc DelegatingPeerListProcessor.h\ - AnnounceList.h AnnounceList.cc + AnnounceTier.h\ + AnnounceList.h AnnounceList.cc\ + BtContext.h\ + DefaultBtContext.cc DefaultBtContext.h\ + PieceStorage.h\ + DefaultPieceStorage.cc DefaultPieceStorage.h\ + PeerService.h\ + DefaultPeerStorage.cc DefaultPeerStorage.h\ + BtAnnounce.h\ + DefaultBtAnnounce.cc DefaultBtAnnounce.h\ + BtRegistry.cc BtRegistry.h\ + BtRuntime.h\ + BtProgressInfoFile.h\ + DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ + BtContextAwareCommand.cc BtContextAwareCommand.h endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/src/Makefile.in b/src/Makefile.in index f52fe022..3ebd9e44 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -46,7 +46,6 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ MetaFileUtil.cc MetaFileUtil.h\ @ENABLE_BITTORRENT_TRUE@ MetaEntryVisitor.h\ @ENABLE_BITTORRENT_TRUE@ ShaVisitor.cc ShaVisitor.h\ -@ENABLE_BITTORRENT_TRUE@ TorrentMan.cc TorrentMan.h\ @ENABLE_BITTORRENT_TRUE@ PeerConnection.cc PeerConnection.h\ @ENABLE_BITTORRENT_TRUE@ PeerMessageUtil.cc PeerMessageUtil.h\ @ENABLE_BITTORRENT_TRUE@ PeerAbstractCommand.cc PeerAbstractCommand.h\ @@ -69,7 +68,7 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ CopyDiskAdaptor.cc CopyDiskAdaptor.h\ @ENABLE_BITTORRENT_TRUE@ DirectDiskAdaptor.cc DirectDiskAdaptor.h\ @ENABLE_BITTORRENT_TRUE@ MultiDiskAdaptor.cc MultiDiskAdaptor.h\ -@ENABLE_BITTORRENT_TRUE@ FileEntry.h\ +@ENABLE_BITTORRENT_TRUE@ FileEntry.cc FileEntry.h\ @ENABLE_BITTORRENT_TRUE@ TrackerUpdateCommand.cc TrackerUpdateCommand.h\ @ENABLE_BITTORRENT_TRUE@ ByteArrayDiskWriter.cc ByteArrayDiskWriter.h\ @ENABLE_BITTORRENT_TRUE@ PeerChokeCommand.cc PeerChokeCommand.h\ @@ -102,7 +101,21 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ DefaultPeerListProcessor.cc DefaultPeerListProcessor.h\ @ENABLE_BITTORRENT_TRUE@ CompactPeerListProcessor.cc CompactPeerListProcessor.h\ @ENABLE_BITTORRENT_TRUE@ DelegatingPeerListProcessor.cc DelegatingPeerListProcessor.h\ -@ENABLE_BITTORRENT_TRUE@ AnnounceList.h AnnounceList.cc +@ENABLE_BITTORRENT_TRUE@ AnnounceTier.h\ +@ENABLE_BITTORRENT_TRUE@ AnnounceList.h AnnounceList.cc\ +@ENABLE_BITTORRENT_TRUE@ BtContext.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtContext.cc DefaultBtContext.h\ +@ENABLE_BITTORRENT_TRUE@ PieceStorage.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultPieceStorage.cc DefaultPieceStorage.h\ +@ENABLE_BITTORRENT_TRUE@ PeerService.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultPeerStorage.cc DefaultPeerStorage.h\ +@ENABLE_BITTORRENT_TRUE@ BtAnnounce.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtAnnounce.cc DefaultBtAnnounce.h\ +@ENABLE_BITTORRENT_TRUE@ BtRegistry.cc BtRegistry.h\ +@ENABLE_BITTORRENT_TRUE@ BtRuntime.h\ +@ENABLE_BITTORRENT_TRUE@ BtProgressInfoFile.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ +@ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.cc BtContextAwareCommand.h @ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @@ -172,10 +185,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ BitfieldMan.cc BitfieldMan.h NameResolver.cc NameResolver.h \ MetaEntry.h Data.cc Data.h Dictionary.cc Dictionary.h List.cc \ List.h MetaFileUtil.cc MetaFileUtil.h MetaEntryVisitor.h \ - ShaVisitor.cc ShaVisitor.h TorrentMan.cc TorrentMan.h \ - PeerConnection.cc PeerConnection.h PeerMessageUtil.cc \ - PeerMessageUtil.h PeerAbstractCommand.cc PeerAbstractCommand.h \ - PeerInitiateConnectionCommand.cc \ + ShaVisitor.cc ShaVisitor.h PeerConnection.cc PeerConnection.h \ + PeerMessageUtil.cc PeerMessageUtil.h PeerAbstractCommand.cc \ + PeerAbstractCommand.h PeerInitiateConnectionCommand.cc \ PeerInitiateConnectionCommand.h PeerInteractionCommand.cc \ PeerInteractionCommand.h Peer.cc Peer.h \ TorrentDownloadEngine.cc TorrentDownloadEngine.h \ @@ -189,11 +201,11 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ MultiDiskWriter.h DiskAdaptor.cc DiskAdaptor.h \ CopyDiskAdaptor.cc CopyDiskAdaptor.h DirectDiskAdaptor.cc \ DirectDiskAdaptor.h MultiDiskAdaptor.cc MultiDiskAdaptor.h \ - FileEntry.h TrackerUpdateCommand.cc TrackerUpdateCommand.h \ - ByteArrayDiskWriter.cc ByteArrayDiskWriter.h \ - PeerChokeCommand.cc PeerChokeCommand.h ChokeMessage.cc \ - ChokeMessage.h UnchokeMessage.cc UnchokeMessage.h \ - InterestedMessage.cc InterestedMessage.h \ + FileEntry.cc FileEntry.h TrackerUpdateCommand.cc \ + TrackerUpdateCommand.h ByteArrayDiskWriter.cc \ + ByteArrayDiskWriter.h PeerChokeCommand.cc PeerChokeCommand.h \ + ChokeMessage.cc ChokeMessage.h UnchokeMessage.cc \ + UnchokeMessage.h InterestedMessage.cc InterestedMessage.h \ NotInterestedMessage.cc NotInterestedMessage.h HaveMessage.cc \ HaveMessage.h BitfieldMessage.cc BitfieldMessage.h \ RequestMessage.cc RequestMessage.h PieceMessage.cc \ @@ -211,9 +223,17 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ PeerListProcessor.h DefaultPeerListProcessor.cc \ DefaultPeerListProcessor.h CompactPeerListProcessor.cc \ CompactPeerListProcessor.h DelegatingPeerListProcessor.cc \ - DelegatingPeerListProcessor.h AnnounceList.h AnnounceList.cc \ - Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ - MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ + DelegatingPeerListProcessor.h AnnounceTier.h AnnounceList.h \ + AnnounceList.cc BtContext.h DefaultBtContext.cc \ + DefaultBtContext.h PieceStorage.h DefaultPieceStorage.cc \ + DefaultPieceStorage.h PeerService.h DefaultPeerStorage.cc \ + DefaultPeerStorage.h BtAnnounce.h DefaultBtAnnounce.cc \ + DefaultBtAnnounce.h BtRegistry.cc BtRegistry.h BtRuntime.h \ + BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \ + DefaultBtProgressInfoFile.h BtContextAwareCommand.cc \ + BtContextAwareCommand.h Metalinker.cc Metalinker.h \ + MetalinkEntry.cc MetalinkEntry.h MetalinkResource.cc \ + MetalinkResource.h MetalinkProcessor.h \ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h \ MetalinkRequestInfo.cc MetalinkRequestInfo.h @ENABLE_ASYNC_DNS_TRUE@am__objects_1 = NameResolver.$(OBJEXT) @@ -221,7 +241,6 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ Dictionary.$(OBJEXT) List.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ MetaFileUtil.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ ShaVisitor.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TorrentMan.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerConnection.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerMessageUtil.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerAbstractCommand.$(OBJEXT) \ @@ -243,6 +262,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ CopyDiskAdaptor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DirectDiskAdaptor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ MultiDiskAdaptor.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ FileEntry.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ TrackerUpdateCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ ByteArrayDiskWriter.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerChokeCommand.$(OBJEXT) \ @@ -270,7 +290,14 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ DefaultPeerListProcessor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ CompactPeerListProcessor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DelegatingPeerListProcessor.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ AnnounceList.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ AnnounceList.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtContext.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultPieceStorage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultPeerStorage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtAnnounce.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtRegistry.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtProgressInfoFile.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @@ -598,6 +625,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtContextAwareCommand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CancelMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChokeMessage.Po@am__quote@ @@ -608,8 +637,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyDiskAdaptor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounce.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtContext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtProgressInfoFile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerStorage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DelegatingPeerListProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dictionary.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectDiskAdaptor.Po@am__quote@ @@ -620,6 +654,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DownloadEngineFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/File.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpConnection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpDownloadCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpInitiateConnectionCommand.Po@am__quote@ @@ -687,7 +722,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentAutoSaveCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentConsoleDownloadEngine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentDownloadEngine.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentRequestInfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerUpdateCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@ diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc index 835a11f3..fc4a5400 100644 --- a/src/MultiDiskAdaptor.cc +++ b/src/MultiDiskAdaptor.cc @@ -46,14 +46,21 @@ string MultiDiskAdaptor::getFilePath() const { return storeDir; } +void MultiDiskAdaptor::mkdir() const { + for(FileEntries::const_iterator itr = fileEntries.begin(); + itr != fileEntries.end(); itr++) { + (*itr)->setupDir(storeDir); + } +} + void MultiDiskAdaptor::openFile() { - topDir->createDir(storeDir, true); + mkdir(); setDiskWriterFileEntries(); DiskAdaptor::openFile(); } void MultiDiskAdaptor::initAndOpenFile() { - topDir->createDir(storeDir, true); + mkdir(); setDiskWriterFileEntries(); DiskAdaptor::initAndOpenFile(); } diff --git a/src/MultiDiskAdaptor.h b/src/MultiDiskAdaptor.h index 0012779a..27fa74ee 100644 --- a/src/MultiDiskAdaptor.h +++ b/src/MultiDiskAdaptor.h @@ -41,6 +41,7 @@ class MultiDiskAdaptor : public DiskAdaptor { private: void setDiskWriterFileEntries(); + void mkdir() const; protected: virtual string getFilePath() const; public: diff --git a/src/MultiDiskWriter.cc b/src/MultiDiskWriter.cc index f49db771..b231d564 100644 --- a/src/MultiDiskWriter.cc +++ b/src/MultiDiskWriter.cc @@ -68,7 +68,7 @@ void MultiDiskWriter::setFileEntries(const FileEntries& fileEntries) { void MultiDiskWriter::openFile(const string& filename) { for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); itr != diskWriterEntries.end(); itr++) { - (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry.path); + (*itr)->diskWriter->openFile(filename+"/"+(*itr)->fileEntry->getPath()); } } @@ -76,7 +76,7 @@ void MultiDiskWriter::openFile(const string& filename) { void MultiDiskWriter::initAndOpenFile(const string& filename) { for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); itr != diskWriterEntries.end(); itr++) { - (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry.path); + (*itr)->diskWriter->initAndOpenFile(filename+"/"+(*itr)->fileEntry->getPath()); } } @@ -90,7 +90,7 @@ void MultiDiskWriter::closeFile() { void MultiDiskWriter::openExistingFile(const string& filename) { for(DiskWriterEntries::iterator itr = diskWriterEntries.begin(); itr != diskWriterEntries.end(); itr++) { - (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry.path); + (*itr)->diskWriter->openExistingFile(filename+"/"+(*itr)->fileEntry->getPath()); } } @@ -107,7 +107,7 @@ void MultiDiskWriter::writeData(const char* data, int len, long long int offset) writing = true; fileOffset = 0; } else { - fileOffset -= (*itr)->fileEntry.length; + fileOffset -= (*itr)->fileEntry->getLength(); } } if(!writing) { @@ -116,14 +116,14 @@ void MultiDiskWriter::writeData(const char* data, int len, long long int offset) } bool MultiDiskWriter::isInRange(const DiskWriterEntry* entry, long long int offset) const { - return entry->fileEntry.offset <= offset && - offset < entry->fileEntry.offset+entry->fileEntry.length; + return entry->fileEntry->getOffset() <= offset && + offset < entry->fileEntry->getOffset()+entry->fileEntry->getLength(); } int MultiDiskWriter::calculateLength(const DiskWriterEntry* entry, long long int fileOffset, int rem) const { int length; - if(entry->fileEntry.length < fileOffset+rem) { - length = entry->fileEntry.length-fileOffset; + if(entry->fileEntry->getLength() < fileOffset+rem) { + length = entry->fileEntry->getLength()-fileOffset; } else { length = rem; } @@ -144,7 +144,7 @@ int MultiDiskWriter::readData(char* data, int len, long long int offset) { reading = true; fileOffset = 0; } else { - fileOffset -= (*itr)->fileEntry.length; + fileOffset -= (*itr)->fileEntry->getLength(); } } if(!reading) { @@ -187,7 +187,7 @@ string MultiDiskWriter::sha1Sum(long long int offset, long long int length) { reading = true; fileOffset = 0; } else { - fileOffset -= (*itr)->fileEntry.length; + fileOffset -= (*itr)->fileEntry->getLength(); } } if(!reading) { diff --git a/src/MultiDiskWriter.h b/src/MultiDiskWriter.h index d0ac9655..c7e5d26c 100644 --- a/src/MultiDiskWriter.h +++ b/src/MultiDiskWriter.h @@ -36,16 +36,16 @@ #define _D_MULTI_DISK_WRITER_H_ #include "DefaultDiskWriter.h" -#include "TorrentMan.h" #include "messageDigest.h" +#include "FileEntry.h" class DiskWriterEntry { public: - FileEntry fileEntry; + FileEntryHandle fileEntry; DiskWriter* diskWriter; public: - DiskWriterEntry(const FileEntry& fileEntry):fileEntry(fileEntry) { - diskWriter = new DefaultDiskWriter(this->fileEntry.length); + DiskWriterEntry(const FileEntryHandle& fileEntry):fileEntry(fileEntry) { + diskWriter = new DefaultDiskWriter(this->fileEntry->getLength()); } ~DiskWriterEntry() { delete diskWriter; diff --git a/src/Peer.h b/src/Peer.h index cc9fe26e..c7af34ee 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -75,11 +75,12 @@ private: long long int sessionDownloadLength; int pieceLength; int latency; + bool active; public: - Peer(string ipaddr, int port, int pieceLength, long long int totalLength) - :entryId(0), ipaddr(ipaddr), port(port), error(0), + Peer(string ipaddr, int port, int pieceLength, long long int totalLength): + entryId(0), ipaddr(ipaddr), port(port), error(0), sessionUploadLength(0), sessionDownloadLength(0), - pieceLength(pieceLength) + pieceLength(pieceLength), active(false) { resetStatus(); this->bitfield = new BitfieldMan(pieceLength, totalLength); @@ -148,10 +149,16 @@ public: void activate() { peerStat.downloadStart(); + active = true; } void deactivate() { peerStat.downloadStop(); + active = false; + } + + bool isActive() const { + return active; } void setPeerId(const char* peerId) { @@ -193,5 +200,6 @@ public: }; typedef SharedHandle PeerHandle; +typedef deque Peers; #endif // _D_PEER_H_ diff --git a/src/PeerAbstractCommand.cc b/src/PeerAbstractCommand.cc index 6127450d..37e24c4e 100644 --- a/src/PeerAbstractCommand.cc +++ b/src/PeerAbstractCommand.cc @@ -41,23 +41,25 @@ PeerAbstractCommand::PeerAbstractCommand(int cuid, const PeerHandle& peer, TorrentDownloadEngine* e, + const BtContextHandle& btContext, const SocketHandle& s) - :Command(cuid), e(e), socket(s), peer(peer), - checkSocketIsReadable(false), checkSocketIsWritable(false), - uploadLimitCheck(false), uploadLimit(0), noCheck(false) { + :BtContextAwareCommand(cuid, btContext), e(e), socket(s), peer(peer), + checkSocketIsReadable(false), checkSocketIsWritable(false), + uploadLimitCheck(false), uploadLimit(0), noCheck(false) +{ setReadCheckSocket(socket); timeout = e->option->getAsInt(PREF_TIMEOUT); - e->torrentMan->connections++; + btRuntime->increaseConnections(); } PeerAbstractCommand::~PeerAbstractCommand() { disableReadCheckSocket(); disableWriteCheckSocket(); - e->torrentMan->connections--; + btRuntime->decreaseConnections(); } bool PeerAbstractCommand::execute() { - if(e->torrentMan->isHalt()) { + if(btRuntime->isHalt()) { return true; } try { diff --git a/src/PeerAbstractCommand.h b/src/PeerAbstractCommand.h index 96573d81..52f25520 100644 --- a/src/PeerAbstractCommand.h +++ b/src/PeerAbstractCommand.h @@ -35,12 +35,12 @@ #ifndef _D_PEER_ABSTRACT_COMMAND_H_ #define _D_PEER_ABSTRACT_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "Request.h" #include "TorrentDownloadEngine.h" #include "TimeA2.h" -class PeerAbstractCommand : public Command { +class PeerAbstractCommand : public BtContextAwareCommand { private: Time checkPoint; int timeout; @@ -48,6 +48,7 @@ protected: TorrentDownloadEngine* e; SocketHandle socket; PeerHandle peer; + void setTimeout(int timeout) { this->timeout = timeout; } virtual bool prepareForNextPeer(int wait); virtual bool prepareForRetry(int wait); @@ -71,6 +72,7 @@ private: public: PeerAbstractCommand(int cuid, const PeerHandle& peer, TorrentDownloadEngine* e, + const BtContextHandle& btContext, const SocketHandle& s = SocketHandle()); virtual ~PeerAbstractCommand(); bool execute(); diff --git a/src/PeerChokeCommand.cc b/src/PeerChokeCommand.cc index 4b0cd314..0b49b26d 100644 --- a/src/PeerChokeCommand.cc +++ b/src/PeerChokeCommand.cc @@ -35,7 +35,14 @@ #include "PeerChokeCommand.h" #include "Util.h" -PeerChokeCommand::PeerChokeCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), interval(interval), e(e), rotate(0) {} +PeerChokeCommand::PeerChokeCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + int interval): + BtContextAwareCommand(cuid, btContext), + interval(interval), + e(e), + rotate(0) {} PeerChokeCommand::~PeerChokeCommand() {} @@ -89,14 +96,14 @@ void PeerChokeCommand::orderByDownloadRate(Peers& peers) const { } bool PeerChokeCommand::execute() { - if(e->torrentMan->isHalt()) { + if(btRuntime->isHalt()) { return true; } if(checkPoint.elapsed(interval)) { checkPoint.reset(); - Peers peers = e->torrentMan->getActivePeers(); + Peers peers = peerStorage->getActivePeers(); for_each(peers.begin(), peers.end(), ChokePeer()); - if(e->torrentMan->downloadComplete()) { + if(pieceStorage->downloadFinished()) { orderByUploadRate(peers); } else { orderByDownloadRate(peers); @@ -109,7 +116,7 @@ bool PeerChokeCommand::execute() { peer->chokingRequired = false; peer->optUnchoking = false; itr = peers.erase(itr); - if(e->torrentMan->downloadComplete()) { + if(pieceStorage->downloadFinished()) { logger->debug("cat01, unchoking %s, upload speed=%d", peer->ipaddr.c_str(), peer->calculateUploadSpeed()); @@ -128,7 +135,7 @@ bool PeerChokeCommand::execute() { peer->chokingRequired = false; peer->optUnchoking = false; itr = peers.erase(itr); - if(e->torrentMan->downloadComplete()) { + if(pieceStorage->downloadFinished()) { logger->debug("cat01, unchoking %s, upload speed=%d", peer->ipaddr.c_str(), peer->calculateUploadSpeed()); diff --git a/src/PeerChokeCommand.h b/src/PeerChokeCommand.h index 8319a269..6b03ccac 100644 --- a/src/PeerChokeCommand.h +++ b/src/PeerChokeCommand.h @@ -35,11 +35,11 @@ #ifndef _D_PEER_CHOKE_COMMAND_H_ #define _D_PEER_CHOKE_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" #include "TimeA2.h" -class PeerChokeCommand : public Command { +class PeerChokeCommand : public BtContextAwareCommand { private: int interval; TorrentDownloadEngine* e; @@ -51,7 +51,11 @@ private: void optUnchokingPeer(Peers& peers) const; public: - PeerChokeCommand(int cuid, TorrentDownloadEngine* e, int interval); + PeerChokeCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + int interval); + virtual ~PeerChokeCommand(); bool execute(); diff --git a/src/PeerConnection.h b/src/PeerConnection.h index ab025ee9..de52f004 100644 --- a/src/PeerConnection.h +++ b/src/PeerConnection.h @@ -38,7 +38,6 @@ #include "Option.h" #include "Socket.h" #include "Logger.h" -#include "TorrentMan.h" #include "PeerMessage.h" #include "common.h" diff --git a/src/PeerInitiateConnectionCommand.cc b/src/PeerInitiateConnectionCommand.cc index a578b40e..399cfb1e 100644 --- a/src/PeerInitiateConnectionCommand.cc +++ b/src/PeerInitiateConnectionCommand.cc @@ -41,8 +41,9 @@ PeerInitiateConnectionCommand::PeerInitiateConnectionCommand(int cuid, const PeerHandle& peer, - TorrentDownloadEngine* e) - :PeerAbstractCommand(cuid, peer, e) {} + TorrentDownloadEngine* e, + const BtContextHandle& btContext) + :PeerAbstractCommand(cuid, peer, e, btContext) {} PeerInitiateConnectionCommand::~PeerInitiateConnectionCommand() {} @@ -51,7 +52,13 @@ bool PeerInitiateConnectionCommand::executeInternal() { logger->info(MSG_CONNECTING_TO_SERVER, cuid, peer->ipaddr.c_str(), peer->port); socket->establishConnection(peer->ipaddr, peer->port); - command = new PeerInteractionCommand(cuid, peer, e, socket, PeerInteractionCommand::INITIATOR_SEND_HANDSHAKE); + command = + new PeerInteractionCommand(cuid, + peer, + e, + btContext, + socket, + PeerInteractionCommand::INITIATOR_SEND_HANDSHAKE); e->commands.push_back(command); return true; @@ -59,19 +66,26 @@ bool PeerInitiateConnectionCommand::executeInternal() { // TODO this method removed when PeerBalancerCommand is implemented bool PeerInitiateConnectionCommand::prepareForNextPeer(int wait) { - if(e->torrentMan->isPeerAvailable()) { - PeerHandle peer = e->torrentMan->getPeer(); - int newCuid = e->torrentMan->getNewCuid(); + if(peerStorage->isPeerAvailable() && btRuntime->lessThanEqMinPeer()) { + PeerHandle peer = peerStorage->getUnusedPeer(); + int newCuid = btRuntime->getNewCuid(); peer->cuid = newCuid; PeerInitiateConnectionCommand* command = - new PeerInitiateConnectionCommand(newCuid, peer, e); + new PeerInitiateConnectionCommand(newCuid, + peer, + e, + btContext); e->commands.push_back(command); } return true; } bool PeerInitiateConnectionCommand::prepareForRetry(int wait) { - PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(cuid, peer, e); + PeerInitiateConnectionCommand* command = + new PeerInitiateConnectionCommand(cuid, + peer, + e, + btContext); e->commands.push_back(command); return true; } diff --git a/src/PeerInitiateConnectionCommand.h b/src/PeerInitiateConnectionCommand.h index 15bad8d8..7a86f097 100644 --- a/src/PeerInitiateConnectionCommand.h +++ b/src/PeerInitiateConnectionCommand.h @@ -43,8 +43,11 @@ protected: bool prepareForRetry(int wait); bool prepareForNextPeer(int wait); public: - PeerInitiateConnectionCommand(int cuid, const PeerHandle& peer, - TorrentDownloadEngine* e); + PeerInitiateConnectionCommand(int cuid, + const PeerHandle& peer, + TorrentDownloadEngine* e, + const BtContextHandle& btContext); + ~PeerInitiateConnectionCommand(); }; diff --git a/src/PeerInteraction.cc b/src/PeerInteraction.cc index 50e6fe86..1ec87ce0 100644 --- a/src/PeerInteraction.cc +++ b/src/PeerInteraction.cc @@ -39,20 +39,24 @@ #include "PeerMessageUtil.h" #include "Util.h" #include "prefs.h" +#include "BtRegistry.h" #include PeerInteraction::PeerInteraction(int cuid, const PeerHandle& peer, const SocketHandle& socket, const Option* op, - TorrentMan* torrentMan) + const BtContextHandle& btContext) :cuid(cuid), option(op), - torrentMan(torrentMan), + btContext(btContext), + peerStorage(PEER_STORAGE(btContext)), + pieceStorage(PIECE_STORAGE(btContext)), + btAnnounce(BT_ANNOUNCE(btContext)), peer(peer), quickReplied(false) { peerConnection = new PeerConnection(cuid, socket, op); - peerMessageFactory = new PeerMessageFactory(cuid, this, peer); + peerMessageFactory = new PeerMessageFactory(cuid, btContext, this, peer); logger = LogFactory::getInstance(); } @@ -78,7 +82,7 @@ void PeerInteraction::sendMessages() { PeerMessageHandle msg = messageQueue.front(); messageQueue.pop_front(); if(uploadLimit > 0) { - TransferStat stat = torrentMan->calculateStat(); + TransferStat stat = peerStorage->calculateStat(); if(uploadLimit < stat.uploadSpeed && msg->isUploading() && !msg->isInProgress()) { tempQueue.push_back(msg); @@ -155,7 +159,7 @@ void PeerInteraction::abortPiece(Piece& piece) { itr++; } } - torrentMan->cancelPiece(piece); + pieceStorage->cancelPiece(piece); } } @@ -184,7 +188,7 @@ void PeerInteraction::checkRequestSlot() { } else { Piece piece = getDownloadPiece(slot.getIndex()); if(piece.hasBlock(slot.getBlockIndex()) || - torrentMan->hasPiece(piece.getIndex())) { + pieceStorage->hasPiece(piece.getIndex())) { logger->debug("CUID#%d - Deleting request slot blockIndex=%d because" " the block has been acquired.", cuid, slot.getBlockIndex()); @@ -242,7 +246,7 @@ PeerMessageHandle PeerInteraction::receiveHandshake(bool quickReply) { if(!quickReplied && quickReply && msgLength >= 48) { quickReplied = true; // check info_hash - if(memcmp(torrentMan->getInfoHash(), &msg[28], INFO_HASH_LENGTH) == 0) { + if(memcmp(btContext->getInfoHash(), &msg[28], INFO_HASH_LENGTH) == 0) { sendHandshake(); } } @@ -272,18 +276,18 @@ PeerMessageHandle PeerInteraction::receiveMessage() { void PeerInteraction::syncPiece() { for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { - torrentMan->syncPiece(*itr); + pieceStorage->syncPiece(*itr); } } void PeerInteraction::updatePiece() { for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { - torrentMan->updatePiece(*itr); + pieceStorage->updatePiece(*itr); } } void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { - if(pieces.empty() && !torrentMan->hasMissingPiece(peer)) { + if(pieces.empty() && !pieceStorage->hasMissingPiece(peer)) { if(peer->amInterested) { logger->debug("CUID#%d - Not interested in the peer", cuid); addMessage(peerMessageFactory->createNotInterestedMessage()); @@ -293,7 +297,7 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { onChoked(); if(peer->isFastExtensionEnabled()) { while((int)pieces.size() < pieceNum) { - Piece piece = torrentMan->getMissingFastPiece(peer); + Piece piece = pieceStorage->getMissingFastPiece(peer); if(Piece::isNull(piece)) { break; } else { @@ -303,7 +307,7 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { } } else { while((int)pieces.size() < pieceNum) { - Piece piece = torrentMan->getMissingPiece(peer); + Piece piece = pieceStorage->getMissingPiece(peer); if(Piece::isNull(piece)) { break; } else { @@ -338,16 +342,16 @@ void PeerInteraction::addRequests() { MAX_PENDING_REQUEST = 6; } int pieceNum; - if(torrentMan->isEndGame()) { + if(pieceStorage->isEndGame()) { pieceNum = 1; } else { - int blocks = DIV_FLOOR(torrentMan->pieceLength, BLOCK_LENGTH); + int blocks = DIV_FLOOR(btContext->getPieceLength(), BLOCK_LENGTH); pieceNum = DIV_FLOOR(MAX_PENDING_REQUEST, blocks); } getNewPieceAndSendInterest(pieceNum); for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { Piece& piece = *itr; - if(torrentMan->isEndGame()) { + if(pieceStorage->isEndGame()) { BlockIndexes missingBlockIndexes = piece.getAllMissingBlockIndexes(); random_shuffle(missingBlockIndexes.begin(), missingBlockIndexes.end()); int count = countRequestSlot(); @@ -380,23 +384,23 @@ void PeerInteraction::addRequests() { void PeerInteraction::sendHandshake() { PeerMessageHandle handle = - peerMessageFactory->createHandshakeMessage(torrentMan->getInfoHash(), - torrentMan->peerId.c_str()); + peerMessageFactory->createHandshakeMessage(btContext->getInfoHash(), + btAnnounce->getPeerId().c_str()); addMessage(handle); sendMessages(); } void PeerInteraction::sendBitfield() { if(peer->isFastExtensionEnabled()) { - if(torrentMan->hasAllPieces()) { + if(pieceStorage->downloadFinished()) { addMessage(peerMessageFactory->createHaveAllMessage()); - } else if(torrentMan->getDownloadLength() > 0) { + } else if(pieceStorage->getCompletedLength() > 0) { addMessage(peerMessageFactory->createBitfieldMessage()); } else { addMessage(peerMessageFactory->createHaveNoneMessage()); } } else { - if(torrentMan->getDownloadLength() > 0) { + if(pieceStorage->getCompletedLength() > 0) { addMessage(peerMessageFactory->createBitfieldMessage()); } } @@ -405,8 +409,10 @@ void PeerInteraction::sendBitfield() { void PeerInteraction::sendAllowedFast() { if(peer->isFastExtensionEnabled()) { - Integers fastSet = Util::computeFastSet(peer->ipaddr, torrentMan->getInfoHash(), - torrentMan->pieces, ALLOWED_FAST_SET_SIZE); + Integers fastSet = Util::computeFastSet(peer->ipaddr, + btContext->getInfoHash(), + btContext->getNumPieces(), + ALLOWED_FAST_SET_SIZE); for(Integers::const_iterator itr = fastSet.begin(); itr != fastSet.end(); itr++) { addMessage(peerMessageFactory->createAllowedFastMessage(*itr)); diff --git a/src/PeerInteraction.h b/src/PeerInteraction.h index 342f99eb..ef62ba4d 100644 --- a/src/PeerInteraction.h +++ b/src/PeerInteraction.h @@ -37,9 +37,13 @@ #include "common.h" #include "PeerConnection.h" +#include "PeerMessageFactory.h" #include "RequestSlot.h" #include "SharedHandle.h" -#include "PeerMessageFactory.h" +#include "BtContext.h" +#include "PeerStorage.h" +#include "PieceStorage.h" +#include "BtAnnounce.h" #define REQUEST_TIME_OUT 60 #define ALLOWED_FAST_SET_SIZE 10 @@ -53,7 +57,10 @@ private: RequestSlots requestSlots; MessageQueue messageQueue; const Option* option; - TorrentMan* torrentMan; + BtContextHandle btContext; + PeerStorageHandle peerStorage; + PieceStorageHandle pieceStorage; + BtAnnounceHandle btAnnounce; PeerConnection* peerConnection; PeerHandle peer; Pieces pieces; @@ -70,7 +77,7 @@ public: const PeerHandle& peer, const SocketHandle& socket, const Option* op, - TorrentMan* torrentMan); + const BtContextHandle& btContext); ~PeerInteraction(); void addMessage(const PeerMessageHandle& peerMessage); @@ -89,16 +96,20 @@ public: int countMessageInQueue() const; - TorrentMan* getTorrentMan() const { return torrentMan; } + BtContextHandle getBtContext() const { return btContext; } + PeerConnection* getPeerConnection() const { return peerConnection; } + // If this object has nullPiece, then return false, otherwise true bool hasDownloadPiece(int index) const; + // If the piece which this object has is nullPiece, then throws an exception. // So before calling this function, call hasDownloadPiece and make sure // this has valid piece, not nullPiece. Piece& getDownloadPiece(int index); bool isInFastSet(int index) const; + void addFastSetIndex(int index); void syncPiece(); diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 30d934d9..86a6c3cd 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -49,26 +49,27 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, const PeerHandle& p, TorrentDownloadEngine* e, + const BtContextHandle& btContext, const SocketHandle& s, int sequence) - :PeerAbstractCommand(cuid, p, e, s), sequence(sequence) { + :PeerAbstractCommand(cuid, p, e, btContext, s), sequence(sequence) { if(sequence == INITIATOR_SEND_HANDSHAKE) { disableReadCheckSocket(); setWriteCheckSocket(socket); setTimeout(e->option->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)); } peerInteraction = new PeerInteraction(cuid, peer, socket, e->option, - e->torrentMan); + btContext); setUploadLimit(e->option->getAsInt(PREF_MAX_UPLOAD_LIMIT)); chokeUnchokeCount = 0; haveCount = 0; keepAliveCount = 0; - e->torrentMan->addActivePeer(peer); + peer->activate(); } PeerInteractionCommand::~PeerInteractionCommand() { delete peerInteraction; - e->torrentMan->deleteActivePeer(peer); + peer->deactivate(); } bool PeerInteractionCommand::executeInternal() { @@ -173,7 +174,7 @@ void PeerInteractionCommand::detectMessageFlooding() { /* void PeerInteractionCommand::checkLongTimePeerChoking() { - if(e->torrentMan->downloadComplete()) { + if(pieceStorage->downloadFinished()) { return; } if(peer->amInterested && peer->peerChoking) { @@ -205,7 +206,7 @@ void PeerInteractionCommand::receiveMessages() { for(int i = 0; i < 50; i++) { int maxSpeedLimit = e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT); if(maxSpeedLimit > 0) { - TransferStat stat = e->torrentMan->calculateStat(); + TransferStat stat = peerStorage->calculateStat(); if(maxSpeedLimit < stat.downloadSpeed) { disableReadCheckSocket(); setNoCheck(true); @@ -245,12 +246,15 @@ void PeerInteractionCommand::receiveMessages() { // TODO this method removed when PeerBalancerCommand is implemented bool PeerInteractionCommand::prepareForNextPeer(int wait) { - if(e->torrentMan->isPeerAvailable()) { - PeerHandle peer = e->torrentMan->getPeer(); - int newCuid = e->torrentMan->getNewCuid(); + if(peerStorage->isPeerAvailable() && btRuntime->lessThanEqMinPeer()) { + PeerHandle peer = peerStorage->getUnusedPeer(); + int newCuid = btRuntime->getNewCuid(); peer->cuid = newCuid; PeerInitiateConnectionCommand* command = - new PeerInitiateConnectionCommand(newCuid, peer, e); + new PeerInitiateConnectionCommand(newCuid, + peer, + e, + btContext); e->commands.push_back(command); } return true; @@ -278,12 +282,12 @@ void PeerInteractionCommand::sendKeepAlive() { } void PeerInteractionCommand::checkHave() { - PieceIndexes indexes = - e->torrentMan->getAdvertisedPieceIndexes(cuid, haveCheckTime); + Integers indexes = + pieceStorage->getAdvertisedPieceIndexes(cuid, haveCheckTime); haveCheckTime.reset(); if(indexes.size() >= 20) { if(peer->isFastExtensionEnabled()) { - if(e->torrentMan->hasAllPieces()) { + if(pieceStorage->downloadFinished()) { peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> createHaveAllMessage()); } else { @@ -295,7 +299,7 @@ void PeerInteractionCommand::checkHave() { createBitfieldMessage()); } } else { - for(PieceIndexes::iterator itr = indexes.begin(); itr != indexes.end(); itr++) { + for(Integers::iterator itr = indexes.begin(); itr != indexes.end(); itr++) { peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> createHaveMessage(*itr)); } diff --git a/src/PeerInteractionCommand.h b/src/PeerInteractionCommand.h index 5b0e65cf..73b9fc54 100644 --- a/src/PeerInteractionCommand.h +++ b/src/PeerInteractionCommand.h @@ -73,7 +73,9 @@ protected: public: PeerInteractionCommand(int cuid, const PeerHandle& peer, TorrentDownloadEngine* e, + const BtContextHandle& btContext, const SocketHandle& s, int sequence); + ~PeerInteractionCommand(); enum Seq { diff --git a/src/PeerListProcessor.h b/src/PeerListProcessor.h index 617042af..7a235641 100644 --- a/src/PeerListProcessor.h +++ b/src/PeerListProcessor.h @@ -40,8 +40,6 @@ #include "Peer.h" #include "SharedHandle.h" -typedef deque Peers; - class PeerListProcessor { public: virtual ~PeerListProcessor() {} diff --git a/src/PeerListenCommand.cc b/src/PeerListenCommand.cc index ae9bfd9b..d7808127 100644 --- a/src/PeerListenCommand.cc +++ b/src/PeerListenCommand.cc @@ -35,8 +35,11 @@ #include "PeerListenCommand.h" #include "PeerInteractionCommand.h" -PeerListenCommand::PeerListenCommand(int cuid, TorrentDownloadEngine* e) - :Command(cuid), e(e) {} +PeerListenCommand::PeerListenCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext) + :BtContextAwareCommand(cuid, btContext), + e(e) {} PeerListenCommand::~PeerListenCommand() {} @@ -61,7 +64,7 @@ int PeerListenCommand::bindPort(int portRangeStart, int portRangeEnd) { } bool PeerListenCommand::execute() { - if(e->torrentMan->isHalt()) { + if(btRuntime->isHalt()) { return true; } for(int i = 0; i < 3 && socket->isReadable(0); i++) { @@ -73,15 +76,17 @@ bool PeerListenCommand::execute() { pair localInfo; peerSocket->getAddrInfo(localInfo); if(peerInfo.first != localInfo.first && - e->torrentMan->connections < MAX_PEERS) { + btRuntime->getConnections() < MAX_PEERS) { PeerHandle peer = PeerHandle(new Peer(peerInfo.first, peerInfo.second, - e->torrentMan->pieceLength, - e->torrentMan->getTotalLength())); - if(e->torrentMan->addPeer(peer)) { - int newCuid = e->torrentMan->getNewCuid(); + btContext->getPieceLength(), + btContext->getTotalLength())); + if(peerStorage->addPeer(peer)) { + int newCuid = btRuntime->getNewCuid(); peer->cuid = newCuid; PeerInteractionCommand* command = - new PeerInteractionCommand(newCuid, peer, e, peerSocket, + new PeerInteractionCommand(newCuid, peer, e, + btContext, + peerSocket, PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE); e->commands.push_back(command); logger->debug("CUID#%d - incoming connection, adding new command CUID#%d", cuid, newCuid); diff --git a/src/PeerListenCommand.h b/src/PeerListenCommand.h index a83c1e01..1ae2de91 100644 --- a/src/PeerListenCommand.h +++ b/src/PeerListenCommand.h @@ -35,15 +35,18 @@ #ifndef _D_PEER_LISTEN_COMMAND_H_ #define _D_PEER_LISTEN_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" -class PeerListenCommand : public Command { +class PeerListenCommand : public BtContextAwareCommand { private: TorrentDownloadEngine* e; SocketHandle socket; public: - PeerListenCommand(int cuid, TorrentDownloadEngine* e); + PeerListenCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext); + ~PeerListenCommand(); bool execute(); diff --git a/src/PeerMessage.cc b/src/PeerMessage.cc index d7a16ff2..fe440668 100644 --- a/src/PeerMessage.cc +++ b/src/PeerMessage.cc @@ -38,6 +38,10 @@ PeerMessage::PeerMessage() :inProgress(false), invalidate(false), - uploading(false) { + uploading(false), + btContext(0), + peerStorage(0), + pieceStorage(0) + { logger = LogFactory::getInstance(); } diff --git a/src/PeerMessage.h b/src/PeerMessage.h index 0ef772ff..2d54646b 100644 --- a/src/PeerMessage.h +++ b/src/PeerMessage.h @@ -39,7 +39,10 @@ #include "Logger.h" #include "Peer.h" #include "Piece.h" -#include "SharedHandle.h" +#include "BtContext.h" +#include "PeerStorage.h" +#include "PieceStorage.h" +#include "BtRegistry.h" #include class PeerInteraction; @@ -53,6 +56,9 @@ protected: PeerHandle peer; PeerInteraction* peerInteraction; const Logger* logger; + BtContextHandle btContext; + PeerStorageHandle peerStorage; + PieceStorageHandle pieceStorage; public: PeerMessage(); @@ -63,18 +69,29 @@ public: bool isUploading() const { return uploading; } int getCuid() const { return cuid; } + void setCuid(int cuid) { this->cuid = cuid; } + PeerHandle getPeer() const { return this->peer; } + void setPeer(const PeerHandle& peer) { this->peer = peer; } + PeerInteraction* getPeerInteraction() const { return peerInteraction; } + void setPeerInteraction(PeerInteraction* peerInteraction) { this->peerInteraction = peerInteraction; } + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + pieceStorage = PIECE_STORAGE(btContext); + peerStorage = PEER_STORAGE(btContext); + } + virtual int getId() const = 0; virtual void receivedAction() = 0; virtual void send() = 0; diff --git a/src/PeerMessageFactory.cc b/src/PeerMessageFactory.cc index 1c031075..95709c8e 100644 --- a/src/PeerMessageFactory.cc +++ b/src/PeerMessageFactory.cc @@ -33,7 +33,6 @@ */ /* copyright --> */ #include "PeerMessageFactory.h" -#include "PeerInteraction.h" #include "PeerMessageUtil.h" #include "ChokeMessage.h" #include "UnchokeMessage.h" @@ -54,11 +53,16 @@ #include "SuggestPieceMessage.h" #include "RequestSlot.h" #include "DlAbortEx.h" +#include "BtRegistry.h" +#include "PeerInteraction.h" PeerMessageFactory::PeerMessageFactory(int cuid, + const BtContextHandle& btContext, PeerInteraction* peerInteraction, const PeerHandle& peer) :cuid(cuid), + btContext(btContext), + pieceStorage(PIECE_STORAGE(btContext)), peerInteraction(peerInteraction), peer(peer) {} @@ -86,29 +90,26 @@ PeerMessageHandle PeerMessageFactory::createPeerMessage(const char* msg, int msg break; case HaveMessage::ID: peerMessage = HaveMessage::create(msg, msgLength); - ((HaveMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()-> - pieces); + ((HaveMessage*)peerMessage)->setPieces(btContext->getNumPieces()); break; case BitfieldMessage::ID: peerMessage = BitfieldMessage::create(msg, msgLength); - ((BitfieldMessage*)peerMessage)->setPieces(peerInteraction-> - getTorrentMan()->pieces); + ((BitfieldMessage*)peerMessage)->setPieces(btContext->getNumPieces()); break; case RequestMessage::ID: peerMessage = RequestMessage::create(msg, msgLength); - ((RequestMessage*)peerMessage)->setPieces(peerInteraction-> - getTorrentMan()->pieces); - ((RequestMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((RequestMessage*)peerMessage)->getIndex())); + ((RequestMessage*)peerMessage)->setPieces(btContext->getNumPieces()); + ((RequestMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((RequestMessage*)peerMessage)->getIndex())); break; case CancelMessage::ID: peerMessage = CancelMessage::create(msg, msgLength); - ((CancelMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces); - ((CancelMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((CancelMessage*)peerMessage)->getIndex())); + ((CancelMessage*)peerMessage)->setPieces(btContext->getNumPieces()); + ((CancelMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((CancelMessage*)peerMessage)->getIndex())); break; case PieceMessage::ID: peerMessage = PieceMessage::create(msg, msgLength); - ((PieceMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces); - ((PieceMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((PieceMessage*)peerMessage)->getIndex())); + ((PieceMessage*)peerMessage)->setPieces(btContext->getNumPieces()); + ((PieceMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((PieceMessage*)peerMessage)->getIndex())); break; case PortMessage::ID: peerMessage = PortMessage::create(msg, msgLength); @@ -121,16 +122,16 @@ PeerMessageHandle PeerMessageFactory::createPeerMessage(const char* msg, int msg break; case RejectMessage::ID: peerMessage = RejectMessage::create(msg, msgLength); - ((RejectMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces); - ((RejectMessage*)peerMessage)->setPieceLength(peerInteraction->getTorrentMan()->getPieceLength(((RejectMessage*)peerMessage)->getIndex())); + ((RejectMessage*)peerMessage)->setPieces(btContext->getNumPieces()); + ((RejectMessage*)peerMessage)->setPieceLength(pieceStorage->getPieceLength(((RejectMessage*)peerMessage)->getIndex())); break; case SuggestPieceMessage::ID: peerMessage = SuggestPieceMessage::create(msg, msgLength); - ((SuggestPieceMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces); + ((SuggestPieceMessage*)peerMessage)->setPieces(btContext->getNumPieces()); break; case AllowedFastMessage::ID: peerMessage = AllowedFastMessage::create(msg, msgLength); - ((AllowedFastMessage*)peerMessage)->setPieces(peerInteraction->getTorrentMan()->pieces); + ((AllowedFastMessage*)peerMessage)->setPieces(btContext->getNumPieces()); break; default: throw new DlAbortEx("Invalid message id. id = %d", id); @@ -167,6 +168,7 @@ PeerMessageFactory::setPeerMessageCommonProperty(PeerMessageHandle& peerMessage) peerMessage->setPeer(peer); peerMessage->setCuid(cuid); peerMessage->setPeerInteraction(peerInteraction); + peerMessage->setBtContext(btContext); } PeerMessageHandle PeerMessageFactory::createRequestMessage(const Piece& piece, @@ -235,10 +237,8 @@ PeerMessageHandle PeerMessageFactory::createNotInterestedMessage() const { PeerMessageHandle PeerMessageFactory::createBitfieldMessage() const { PeerMessageHandle handle = - PeerMessageHandle(new BitfieldMessage(peerInteraction->getTorrentMan()-> - getBitfield(), - peerInteraction->getTorrentMan()-> - getBitfieldLength())); + PeerMessageHandle(new BitfieldMessage(pieceStorage->getBitfield(), + pieceStorage->getBitfieldLength())); setPeerMessageCommonProperty(handle); return handle; } diff --git a/src/PeerMessageFactory.h b/src/PeerMessageFactory.h index 147be5c4..481a0b31 100644 --- a/src/PeerMessageFactory.h +++ b/src/PeerMessageFactory.h @@ -38,18 +38,23 @@ #include "common.h" #include "PeerMessage.h" #include "HandshakeMessage.h" +#include "BtContext.h" +#include "PieceStorage.h" class PeerInteraction; class PeerMessageFactory { private: int cuid; + BtContextHandle btContext; + PieceStorageHandle pieceStorage; PeerInteraction* peerInteraction; PeerHandle peer; void setPeerMessageCommonProperty(PeerMessageHandle& peerMessage) const; public: PeerMessageFactory(int cuid, + const BtContextHandle& btContext, PeerInteraction* peerInteraction, const PeerHandle& peer); diff --git a/src/PeerStorage.h b/src/PeerStorage.h new file mode 100644 index 00000000..c5bc49e4 --- /dev/null +++ b/src/PeerStorage.h @@ -0,0 +1,128 @@ +/* */ +#ifndef _D_PEER_STORAGE_H_ +#define _D_PEER_STORAGE_H_ + +#include "common.h" +#include "Peer.h" + +class TransferStat { +public: + int downloadSpeed; + int uploadSpeed; + long long int sessionDownloadLength; + long long int sessionUploadLength; +public: + TransferStat():downloadSpeed(0), uploadSpeed(0), + sessionDownloadLength(0), sessionUploadLength(0) {} + + int getDownloadSpeed() const { + return downloadSpeed; + } + + void setDownloadSpeed(int s) { downloadSpeed = s; } + + int getUploadSpeed() const { + return uploadSpeed; + } + + void setUploadSpeed(int s) { uploadSpeed = s; } + + /** + * Returns the number of bytes downloaded since the program started. + * This is not the total number of bytes downloaded. + */ + long long int getSessionDownloadLength() const { + return sessionDownloadLength; + } + + void setSessionDownloadLength(long long int s) { sessionDownloadLength = s; } + + /** + * Returns the number of bytes uploaded since the program started. + * This is not the total number of bytes uploaded. + */ + long long int getSessionUploadLength() const { + return sessionUploadLength; + } + + void setSessionUploadLength(long long int s) { sessionUploadLength = s; } +}; + +class PeerStorage { +public: + virtual ~PeerStorage() {} + + /** + * Adds new peer to internal peer list. + * If the peer is added successfully, returns true. Otherwise returns false. + */ + virtual bool addPeer(const PeerHandle& peer) = 0; + + /** + * Adds all peers in peers to internal peer list. + */ + virtual void addPeer(const Peers& peers) = 0; + + /** + * Returns internal peer list. + */ + virtual const Peers& getPeers() = 0; + + /** + * Returns one of the unused peers. + */ + virtual PeerHandle getUnusedPeer() = 0; + + /** + * Returns true if at least one unused peer exists. + * Otherwise returns false. + */ + virtual bool isPeerAvailable() = 0; + + /** + * Returns the list of peers which are currently connected from localhost. + */ + virtual Peers getActivePeers() = 0; + + /** + * Calculates current download/upload statistics. + */ + virtual TransferStat calculateStat() = 0; +}; + +typedef SharedHandle PeerStorageHandle; + +#endif // _D_PEER_STORAGE_H_ diff --git a/src/Piece.cc b/src/Piece.cc index 900a4a96..f8d5ed68 100644 --- a/src/Piece.cc +++ b/src/Piece.cc @@ -33,6 +33,7 @@ */ /* copyright --> */ #include "Piece.h" +#include "Util.h" Piece Piece::nullPiece; @@ -79,3 +80,7 @@ int Piece::getMissingBlockIndex() const { BlockIndexes Piece::getAllMissingBlockIndexes() const { return bitfield->getAllMissingIndexes(); } + +string Piece::toString() const { + return "piece: index="+Util::itos(index)+", length="+Util::itos(length); +} diff --git a/src/Piece.h b/src/Piece.h index 4a7c2a6a..f18eae38 100644 --- a/src/Piece.h +++ b/src/Piece.h @@ -117,10 +117,14 @@ public: void clearAllBlock(); void setAllBlock(); + string toString() const; + static Piece nullPiece; static bool isNull(const Piece& piece) { return piece.index == 0 && piece.length == 0; } }; +typedef deque Pieces; + #endif // _D_PIECE_H_ diff --git a/src/PieceMessage.cc b/src/PieceMessage.cc index 4c1f414c..367ad2f9 100644 --- a/src/PieceMessage.cc +++ b/src/PieceMessage.cc @@ -65,7 +65,6 @@ PieceMessage* PieceMessage::create(const char* data, int dataLength) { } void PieceMessage::receivedAction() { - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); RequestSlot slot = peerInteraction->getCorrespondingRequestSlot(index, begin, blockLength); @@ -77,15 +76,15 @@ void PieceMessage::receivedAction() { peer->updateLatency(slot.getLatencyInMillis()); Piece& piece = peerInteraction->getDownloadPiece(slot.getIndex()); long long int offset = - ((long long int)index)*torrentMan->pieceLength+begin; + ((long long int)index)*btContext->getPieceLength()+begin; logger->debug("CUID#%d - Writing the block length=%d, offset=%lld", cuid, blockLength, offset); - torrentMan->diskAdaptor->writeData(block, - blockLength, - offset); + pieceStorage->getDiskAdaptor()->writeData(block, + blockLength, + offset); piece.completeBlock(slot.getBlockIndex()); peerInteraction->deleteRequestSlot(slot); - torrentMan->updatePiece(piece); + pieceStorage->updatePiece(piece); logger->debug("CUID#%d - Setting piece block index=%d", cuid, slot.getBlockIndex()); if(piece.pieceComplete()) { @@ -123,7 +122,6 @@ void PieceMessage::send() { if(invalidate) { return; } - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); PeerConnection* peerConnection = peerInteraction->getPeerConnection(); if(!headerSent) { if(!inProgress) { @@ -146,13 +144,11 @@ void PieceMessage::send() { } if(headerSent) { inProgress = false; - int pieceLength = torrentMan->pieceLength; long long int pieceDataOffset = - ((long long int)index)*pieceLength+begin+blockLength-leftDataLength; + ((long long int)index)*btContext->getPieceLength()+begin+blockLength-leftDataLength; int writtenLength = sendPieceData(pieceDataOffset, leftDataLength); peer->updateUploadLength(writtenLength); - torrentMan->addUploadLength(writtenLength); if(writtenLength != leftDataLength) { inProgress = true; } @@ -165,10 +161,9 @@ int PieceMessage::sendPieceData(long long int offset, int length) const { char buf[BUF_SIZE]; int iteration = length/BUF_SIZE; int writtenLength = 0; - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); PeerConnection* peerConnection = peerInteraction->getPeerConnection(); for(int i = 0; i < iteration; i++) { - if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) { + if(pieceStorage->getDiskAdaptor()->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) { throw new DlAbortEx("Failed to read data from disk."); } int ws = peerConnection->sendMessage(buf, BUF_SIZE); @@ -181,7 +176,7 @@ int PieceMessage::sendPieceData(long long int offset, int length) const { int rem = length%BUF_SIZE; if(rem > 0) { - if(torrentMan->diskAdaptor->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) { + if(pieceStorage->getDiskAdaptor()->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) { throw new DlAbortEx("Failed to read data from disk."); } int ws = peerConnection->sendMessage(buf, rem); @@ -202,42 +197,39 @@ string PieceMessage::toString() const { } bool PieceMessage::checkPieceHash(const Piece& piece) { - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); long long int offset = - ((long long int)piece.getIndex())*torrentMan->pieceLength; - return torrentMan->diskAdaptor->sha1Sum(offset, piece.getLength()) == - torrentMan->getPieceHash(piece.getIndex()); + ((long long int)piece.getIndex())*btContext->getPieceLength(); + return pieceStorage->getDiskAdaptor()->sha1Sum(offset, piece.getLength()) == + btContext->getPieceHash(piece.getIndex()); } void PieceMessage::onGotNewPiece(Piece& piece) { - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); logger->info(MSG_GOT_NEW_PIECE, cuid, piece.getIndex()); - torrentMan->completePiece(piece); - torrentMan->advertisePiece(cuid, piece.getIndex()); + pieceStorage->completePiece(piece); + pieceStorage->advertisePiece(cuid, piece.getIndex()); } void PieceMessage::onGotWrongPiece(Piece& piece) { - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); logger->error(MSG_GOT_WRONG_PIECE, cuid, piece.getIndex()); erasePieceOnDisk(piece); piece.clearAllBlock(); - torrentMan->updatePiece(piece); + pieceStorage->updatePiece(piece); peerInteraction->abortPiece(piece); } void PieceMessage::erasePieceOnDisk(const Piece& piece) { - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); int BUFSIZE = 4096; char buf[BUFSIZE]; memset(buf, 0, BUFSIZE); - long long int offset = ((long long int)piece.getIndex())*torrentMan->pieceLength; + long long int offset = + ((long long int)piece.getIndex())*btContext->getPieceLength(); for(int i = 0; i < piece.getLength()/BUFSIZE; i++) { - torrentMan->diskAdaptor->writeData(buf, BUFSIZE, offset); + pieceStorage->getDiskAdaptor()->writeData(buf, BUFSIZE, offset); offset += BUFSIZE; } int r = piece.getLength()%BUFSIZE; if(r > 0) { - torrentMan->diskAdaptor->writeData(buf, r, offset); + pieceStorage->getDiskAdaptor()->writeData(buf, r, offset); } } diff --git a/src/PieceMessage.h b/src/PieceMessage.h index 90f5b0b7..328ff7bd 100644 --- a/src/PieceMessage.h +++ b/src/PieceMessage.h @@ -36,7 +36,6 @@ #define _D_PIECE_MESSAGE_H_ #include "PeerMessage.h" -#include "TorrentMan.h" class PieceMessage : public PeerMessage { private: diff --git a/src/PieceStorage.h b/src/PieceStorage.h new file mode 100644 index 00000000..4ee76e05 --- /dev/null +++ b/src/PieceStorage.h @@ -0,0 +1,157 @@ +/* */ +#ifndef _D_PIECE_STORAGE_H_ +#define _D_PIECE_STORAGE_H_ + +#include "common.h" +#include "Peer.h" +#include "Piece.h" +#include "DiskAdaptor.h" + +class PieceStorage { +public: + virtual ~PieceStorage() {} + + /** + * Returns true if the peer has a piece that localhost doesn't have. + * Otherwise returns false. + */ + virtual bool hasMissingPiece(const PeerHandle& peer) = 0; + + /** + * Returns a piece that the peer has but localhost doesn't. + * The piece will be marked "used" status in order to prevent other command + * from get the same piece. But in end game mode, same piece may be returned + * to several commands. + */ + virtual Piece getMissingPiece(const PeerHandle& peer) = 0; + /** + * Returns a piece that the peer has but localhost doesn't. + * Only pieces that declared as "fast" are returned. + * The piece will be marked "used" status in order to prevent other command + * from get the same piece. But in end game mode, same piece may be returned + * to several commands. + */ + virtual Piece getMissingFastPiece(const PeerHandle& peer) = 0; + + /** + * Tells that the download of the specfied piece completes. + */ + virtual void completePiece(const Piece& piece) = 0; + + /** + * Tells that the download of the specified piece is canceled. + */ + virtual void cancelPiece(const Piece& piece) = 0; + + /** + * Updates the internal piece data with the specified piece data. + */ + virtual void updatePiece(const Piece& piece) = 0; + + /** + * Updates the spcefied piece data with the internal piece data. + */ + virtual void syncPiece(Piece& piece) = 0; + + /** + * Returns true if the specified piece is already downloaded. + * Otherwise returns false. + */ + virtual bool hasPiece(int index) = 0; + + virtual long long int getTotalLength() = 0; + + virtual long long int getFilteredTotalLength() = 0; + + virtual long long int getCompletedLength() = 0; + + virtual long long int getFilteredCompletedLength() = 0; + + virtual void setFileFilter(const Strings& filePaths) = 0; + + virtual void setFileFilter(const Integers& fileIndexes) = 0; + + virtual void clearFileFilter() = 0; + + virtual bool downloadFinished() = 0; + + /** + * Initializes DiskAdaptor. + * TODO add better documentation here. + */ + virtual void initStorage() = 0; + + virtual const unsigned char* getBitfield() = 0; + + virtual void setBitfield(const unsigned char* bitfield, + int bitfieldLength) = 0; + + virtual int getBitfieldLength() = 0; + + virtual bool isSelectiveDownloadingMode() = 0; + + virtual void finishSelectiveDownloadingMode() = 0; + + virtual bool isEndGame() = 0; + + virtual DiskAdaptor* getDiskAdaptor() = 0; + + virtual int getPieceLength(int index) = 0; + + /** + * Adds piece index to advertise to other commands. They send have message + * based on this information. + */ + virtual void advertisePiece(int cuid, int index) = 0; + + /** + * Returns piece index which is not advertised by the caller command and + * newer than lastCheckTime. + */ + virtual Integers getAdvertisedPieceIndexes(int myCuid, + const Time& lastCheckTime) = 0; + + /** + * Removes have entry if specified seconds have elapsed since its + * registration. + */ + virtual void removeAdvertisedPiece(int elapsed) = 0; + +}; + +typedef SharedHandle PieceStorageHandle; + +#endif // _D_PIECE_STORAGE_H_ diff --git a/src/RejectMessage.h b/src/RejectMessage.h index 7d2b43cf..5b33d37e 100644 --- a/src/RejectMessage.h +++ b/src/RejectMessage.h @@ -36,7 +36,6 @@ #define _D_REJECT_MESSAGE_H_ #include "SimplePeerMessage.h" -#include "TorrentMan.h" class RejectMessage : public SimplePeerMessage { private: diff --git a/src/RequestMessage.cc b/src/RequestMessage.cc index 62c68427..0ab6e343 100644 --- a/src/RequestMessage.cc +++ b/src/RequestMessage.cc @@ -55,8 +55,7 @@ RequestMessage* RequestMessage::create(const char* data, int dataLength) { } void RequestMessage::receivedAction() { - TorrentMan* torrentMan = peerInteraction->getTorrentMan(); - if(torrentMan->hasPiece(index) && + if(pieceStorage->hasPiece(index) && (!peer->amChoking || peer->amChoking && peerInteraction->isInFastSet(index))) { peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> diff --git a/src/RequestMessage.h b/src/RequestMessage.h index 68d20d77..7c7c7b20 100644 --- a/src/RequestMessage.h +++ b/src/RequestMessage.h @@ -36,7 +36,6 @@ #define _D_REQUEST_MESSAGE_H_ #include "SimplePeerMessage.h" -#include "TorrentMan.h" class RequestMessage : public SimplePeerMessage { private: diff --git a/src/SeedCheckCommand.cc b/src/SeedCheckCommand.cc index 51de429d..ae869724 100644 --- a/src/SeedCheckCommand.cc +++ b/src/SeedCheckCommand.cc @@ -34,8 +34,17 @@ /* copyright --> */ #include "SeedCheckCommand.h" +SeedCheckCommand::SeedCheckCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + SeedCriteriaHandle seedCriteria) + :BtContextAwareCommand(cuid, btContext), + e(e), + seedCriteria(seedCriteria), + checkStarted(false) {} + bool SeedCheckCommand::execute() { - if(e->torrentMan->isHalt()) { + if(btRuntime->isHalt()) { return true; } if(!seedCriteria.get()) { @@ -43,7 +52,7 @@ bool SeedCheckCommand::execute() { } if(checkPoint.elapsed(1)) { if(!checkStarted) { - if(e->torrentMan->downloadComplete()) { + if(pieceStorage->downloadFinished()) { checkStarted = true; seedCriteria->reset(); } @@ -51,7 +60,7 @@ bool SeedCheckCommand::execute() { if(checkStarted) { if(seedCriteria->evaluate()) { logger->notice("CUID#%d - Seeding is over.", cuid); - e->torrentMan->setHalt(true); + btRuntime->setHalt(true); } } } diff --git a/src/SeedCheckCommand.h b/src/SeedCheckCommand.h index 5e4f92bb..4ade4094 100644 --- a/src/SeedCheckCommand.h +++ b/src/SeedCheckCommand.h @@ -35,24 +35,22 @@ #ifndef _D_SEED_CHECK_COMMAND_H_ #define _D_SEED_CHECK_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" #include "TimeA2.h" #include "SeedCriteria.h" -class SeedCheckCommand : public Command { +class SeedCheckCommand : public BtContextAwareCommand { private: TorrentDownloadEngine* e; Time checkPoint; SeedCriteriaHandle seedCriteria; bool checkStarted; public: - SeedCheckCommand(int cuid, TorrentDownloadEngine* e, - SeedCriteriaHandle seedCriteria) - :Command(cuid), - e(e), - seedCriteria(seedCriteria), - checkStarted(false) {} + SeedCheckCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + SeedCriteriaHandle seedCriteria); virtual ~SeedCheckCommand() {} diff --git a/src/ShareRatioSeedCriteria.h b/src/ShareRatioSeedCriteria.h index 72f32227..6ded3b02 100644 --- a/src/ShareRatioSeedCriteria.h +++ b/src/ShareRatioSeedCriteria.h @@ -36,26 +36,37 @@ #define _D_SHARE_RATIO_SEED_CRITERIA_H_ #include "SeedCriteria.h" -#include "TorrentMan.h" +#include "BtContext.h" +#include "PeerStorage.h" +#include "BtRuntime.h" +#include "BtRegistry.h" class ShareRatioSeedCriteria : public SeedCriteria { private: double ratio; - TorrentMan* torrentMan; + BtContextHandle btContext; + PeerStorageHandle peerStorage; + BtRuntimeHandle btRuntime; public: - ShareRatioSeedCriteria(double ratio, TorrentMan* torrentMan) + ShareRatioSeedCriteria(double ratio, const BtContextHandle& btContext) :ratio(ratio), - torrentMan(torrentMan) {} + btContext(btContext), + peerStorage(PEER_STORAGE(btContext)), + btRuntime(BT_RUNTIME(btContext)) {} + virtual ~ShareRatioSeedCriteria() {} virtual void reset() {} virtual bool evaluate() { - if(torrentMan->getDownloadLength() == 0) { + if(btContext->getTotalLength() == 0) { return false; } + TransferStat stat = peerStorage->calculateStat(); + long long int allTimeUploadLength = + btRuntime->getUploadLengthAtStartup()+stat.getSessionUploadLength(); return ratio <= - ((double)torrentMan->getUploadLength())/torrentMan->getDownloadLength(); + ((double)allTimeUploadLength)/btContext->getTotalLength(); } void setRatio(double ratio) { diff --git a/src/TorrentAutoSaveCommand.cc b/src/TorrentAutoSaveCommand.cc index 5d2154c3..b363e3ca 100644 --- a/src/TorrentAutoSaveCommand.cc +++ b/src/TorrentAutoSaveCommand.cc @@ -35,15 +35,21 @@ #include "TorrentAutoSaveCommand.h" #include "Util.h" -TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), e(e), interval(interval) {} +TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + int interval): + BtContextAwareCommand(cuid, btContext), + e(e), + interval(interval) {} TorrentAutoSaveCommand::~TorrentAutoSaveCommand() {} bool TorrentAutoSaveCommand::execute() { - if(checkPoint.elapsed(interval) || e->torrentMan->isHalt()) { + if(checkPoint.elapsed(interval) || btRuntime->isHalt()) { checkPoint.reset(); - e->torrentMan->save(); - if(e->torrentMan->isHalt()) { + btProgressInfoFile->save(); + if(btRuntime->isHalt()) { return true; } } diff --git a/src/TorrentAutoSaveCommand.h b/src/TorrentAutoSaveCommand.h index 9c360020..d0f511a3 100644 --- a/src/TorrentAutoSaveCommand.h +++ b/src/TorrentAutoSaveCommand.h @@ -35,17 +35,22 @@ #ifndef _D_TORRENT_AUTO_SAVE_COMMAND_H_ #define _D_TORRENT_AUTO_SAVE_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" #include "TimeA2.h" +#include "BtContext.h" -class TorrentAutoSaveCommand : public Command { +class TorrentAutoSaveCommand : public BtContextAwareCommand { private: TorrentDownloadEngine* e; int interval; Time checkPoint; public: - TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval); + TorrentAutoSaveCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext, + int interval); + ~TorrentAutoSaveCommand(); bool execute(); diff --git a/src/TorrentConsoleDownloadEngine.cc b/src/TorrentConsoleDownloadEngine.cc index 3f6ab8b1..e697c718 100644 --- a/src/TorrentConsoleDownloadEngine.cc +++ b/src/TorrentConsoleDownloadEngine.cc @@ -34,6 +34,9 @@ /* copyright --> */ #include "TorrentConsoleDownloadEngine.h" #include "Util.h" +#include + +volatile sig_atomic_t haltRequested = 0; TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {} @@ -42,8 +45,8 @@ TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {} void TorrentConsoleDownloadEngine::sendStatistics() { printf("\r "); printf("\r"); - if(torrentMan->downloadComplete()) { - printf("Download Completed "); + if(pieceStorage->downloadFinished()) { + printf("Download Completed."); } else { printf("%s/%sB %d%% %s D:%.2f", Util::llitos(downloadLength, true).c_str(), @@ -55,7 +58,14 @@ void TorrentConsoleDownloadEngine::sendStatistics() { } printf(" U:%.2f(%s) %d peers", uploadSpeed/1024.0, - Util::llitos(torrentMan->getUploadLength(), true).c_str(), - torrentMan->connections); + Util::llitos(uploadLength, true).c_str(), + btRuntime->getConnections()); fflush(stdout); } + +void TorrentConsoleDownloadEngine::afterEachIteration() { + if(haltRequested) { + btRuntime->setHalt(true); + } + TorrentDownloadEngine::afterEachIteration(); +} diff --git a/src/TorrentConsoleDownloadEngine.h b/src/TorrentConsoleDownloadEngine.h index 2bbd1f0f..dea43c82 100644 --- a/src/TorrentConsoleDownloadEngine.h +++ b/src/TorrentConsoleDownloadEngine.h @@ -43,6 +43,8 @@ protected: public: TorrentConsoleDownloadEngine(); ~TorrentConsoleDownloadEngine(); + + virtual void afterEachIteration(); }; #endif // _D_TORRENT_CONSOLE_DOWNLOAD_ENGINE_H_ diff --git a/src/TorrentDownloadEngine.cc b/src/TorrentDownloadEngine.cc index 974c1995..30a0587c 100644 --- a/src/TorrentDownloadEngine.cc +++ b/src/TorrentDownloadEngine.cc @@ -34,22 +34,35 @@ /* copyright --> */ #include "TorrentDownloadEngine.h" #include "Util.h" +#include "BtRegistry.h" -TorrentDownloadEngine::TorrentDownloadEngine():filenameFixed(false), - torrentMan(NULL) {} +TorrentDownloadEngine::TorrentDownloadEngine(): + filenameFixed(false), + btContext(0), + btRuntime(0), + pieceStorage(0), + peerStorage(0), + btAnnounce(0), + btProgressInfoFile(0) {} TorrentDownloadEngine::~TorrentDownloadEngine() { - if(torrentMan != NULL) { - delete torrentMan; - } +} + +void TorrentDownloadEngine::setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + btRuntime = BT_RUNTIME(btContext); + pieceStorage = PIECE_STORAGE(btContext); + peerStorage = PEER_STORAGE(btContext); + btAnnounce = BT_ANNOUNCE(btContext); + btProgressInfoFile = BT_PROGRESS_INFO_FILE(btContext); } void TorrentDownloadEngine::onEndOfRun() { - torrentMan->diskAdaptor->closeFile(); - if(torrentMan->downloadComplete()) { - torrentMan->remove(); + pieceStorage->getDiskAdaptor()->closeFile(); + if(pieceStorage->downloadFinished()) { + btProgressInfoFile->removeFile(); } else { - torrentMan->save(); + btProgressInfoFile->save(); } } @@ -57,16 +70,12 @@ void TorrentDownloadEngine::initStatistics() { downloadSpeed = 0; uploadSpeed = 0; cp.reset(); - lastCalcStat.reset(); startup.reset(); eta = 0; avgSpeed = 0; downloadLength = 0; + uploadLength = 0; totalLength = 0; - if(torrentMan->isSelectiveDownloadingMode()) { - selectedDownloadLengthDiff = torrentMan->getDownloadLength()-torrentMan->getCompletedLength(); - selectedTotalLength = torrentMan->getSelectedTotalLength(); - } } int TorrentDownloadEngine::calculateSpeed(long long int length, int elapsed) { @@ -75,10 +84,22 @@ int TorrentDownloadEngine::calculateSpeed(long long int length, int elapsed) { } void TorrentDownloadEngine::calculateStat() { - TransferStat stat = torrentMan->calculateStat(); - downloadSpeed = stat.downloadSpeed; - uploadSpeed = stat.uploadSpeed; - avgSpeed = calculateSpeed(stat.sessionDownloadLength, startup.difference()); + TransferStat stat = peerStorage->calculateStat(); + + if(pieceStorage->isSelectiveDownloadingMode()) { + downloadLength = pieceStorage->getFilteredCompletedLength(); + totalLength = pieceStorage->getFilteredTotalLength(); + } else { + downloadLength = pieceStorage->getCompletedLength(); + totalLength = pieceStorage->getTotalLength(); + } + uploadLength = stat.getSessionUploadLength()+ + btRuntime->getUploadLengthAtStartup(); + + downloadSpeed = stat.getDownloadSpeed(); + uploadSpeed = stat.getUploadSpeed(); + avgSpeed = calculateSpeed(stat.getSessionDownloadLength(), + startup.difference()); if(avgSpeed < 0) { avgSpeed = 0; } else if(avgSpeed != 0) { @@ -87,20 +108,8 @@ void TorrentDownloadEngine::calculateStat() { } void TorrentDownloadEngine::calculateStatistics() { - if(torrentMan->isSelectiveDownloadingMode()) { - downloadLength = torrentMan->getDownloadLength()-selectedDownloadLengthDiff; - totalLength = selectedTotalLength; - } else { - downloadLength = torrentMan->getDownloadLength(); - totalLength = torrentMan->getTotalLength(); - } - - Time now; - if(now.getTimeInMillis()-lastCalcStat.getTimeInMillis() >= 1000) { - calculateStat(); - lastCalcStat = now; - } if(cp.difference() >= 1) { + calculateStat(); sendStatistics(); cp.reset(); } diff --git a/src/TorrentDownloadEngine.h b/src/TorrentDownloadEngine.h index b9ac9f67..f87cd32e 100644 --- a/src/TorrentDownloadEngine.h +++ b/src/TorrentDownloadEngine.h @@ -36,8 +36,13 @@ #define _D_TORRENT_DOWNLOAD_ENGINE_H_ #include "DownloadEngine.h" -#include "TorrentMan.h" #include "TimeA2.h" +#include "BtContext.h" +#include "BtRuntime.h" +#include "PieceStorage.h" +#include "PeerStorage.h" +#include "BtAnnounce.h" +#include "BtProgressInfoFile.h" class TorrentDownloadEngine : public DownloadEngine { private: @@ -59,8 +64,16 @@ protected: // The estimated remaining time to complete the download. int eta; long long int downloadLength; + long long int uploadLength; long long int totalLength; + BtContextHandle btContext; + BtRuntimeHandle btRuntime; + PieceStorageHandle pieceStorage; + PeerStorageHandle peerStorage; + BtAnnounceHandle btAnnounce; + BtProgressInfoFileHandle btProgressInfoFile; + int calculateSpeed(long long int sessionLength, int elapsed); void calculateStat(); @@ -70,9 +83,9 @@ public: TorrentDownloadEngine(); virtual ~TorrentDownloadEngine(); - TorrentMan* torrentMan; - bool isFilenameFixed() const { return filenameFixed; } + + void setBtContext(const BtContextHandle& btContext); }; #endif // _D_TORRENT_DOWNLOAD_ENGINE_H_ diff --git a/src/TorrentRequestInfo.cc b/src/TorrentRequestInfo.cc index 3760da2e..d2ba00d1 100644 --- a/src/TorrentRequestInfo.cc +++ b/src/TorrentRequestInfo.cc @@ -36,19 +36,24 @@ #include "DownloadEngineFactory.h" #include "prefs.h" #include "Util.h" +#include "BtRegistry.h" +#include "DefaultBtContext.h" extern RequestInfo* requestInfo; extern void setSignalHander(int signal, void (*handler)(int), int flags); extern bool timeoutSpecified; +extern volatile sig_atomic_t haltRequested; void torrentHandler(int signal) { - ((TorrentDownloadEngine*)requestInfo->getDownloadEngine())-> - torrentMan->setHalt(true); + haltRequested = 1; } RequestInfo* TorrentRequestInfo::execute() { + BtContextHandle btContext(new DefaultBtContext()); + btContext->load(torrentFile); + if(op->get(PREF_SHOW_FILES) == V_TRUE) { - showFileEntry(); + showFileEntry(btContext); return 0; } if(!timeoutSpecified) { @@ -56,45 +61,42 @@ RequestInfo* TorrentRequestInfo::execute() { } // set max_tries to 1. AnnounceList handles retries. op->put(PREF_MAX_TRIES, "1"); - e = DownloadEngineFactory::newTorrentConsoleEngine(op, - torrentFile, - targetFiles); + SharedHandle + e(DownloadEngineFactory::newTorrentConsoleEngine(btContext, + op, + targetFiles)); + setSignalHander(SIGINT, torrentHandler, SA_RESETHAND); setSignalHander(SIGTERM, torrentHandler, SA_RESETHAND); try { e->run(); - if(e->torrentMan->downloadComplete()) { + if(PIECE_STORAGE(btContext)->downloadFinished()) { printDownloadCompeleteMessage(); } - } catch(Exception* e) { - logger->error("Exception caught", e); - delete e; + } catch(Exception* ex) { + logger->error("Exception caught", ex); fail = true; + delete ex; } setSignalHander(SIGINT, SIG_DFL, 0); setSignalHander(SIGTERM, SIG_DFL, 0); - delete e; return 0; } -// TODO should be const TorrentMan* torrentMan -void TorrentRequestInfo::showFileEntry() +void TorrentRequestInfo::showFileEntry(const BtContextHandle& btContext) { - TorrentMan torrentMan; - torrentMan.option = op; - - FileEntries fileEntries = - torrentMan.readFileEntryFromMetaInfoFile(torrentFile); + FileEntries fileEntries = btContext->getFileEntries(); cout << _("Files:") << endl; cout << "idx|path/length" << endl; cout << "===+===========================================================================" << endl; int count = 1; for(FileEntries::const_iterator itr = fileEntries.begin(); itr != fileEntries.end(); count++, itr++) { - printf("%3d|%s\n |%s Bytes\n", count, itr->path.c_str(), - Util::llitos(itr->length, true).c_str()); + printf("%3d|%s\n |%s Bytes\n", count, + (*itr)->getPath().c_str(), + Util::llitos((*itr)->getLength(), true).c_str()); cout << "---+---------------------------------------------------------------------------" << endl; } } diff --git a/src/TorrentRequestInfo.h b/src/TorrentRequestInfo.h index 4c6266c4..82013467 100644 --- a/src/TorrentRequestInfo.h +++ b/src/TorrentRequestInfo.h @@ -37,19 +37,19 @@ #include "RequestInfo.h" #include "TorrentDownloadEngine.h" +#include "BtContext.h" class TorrentRequestInfo : public RequestInfo { private: string torrentFile; - TorrentDownloadEngine* e; Strings targetFiles; - void showFileEntry(); + void showFileEntry(const BtContextHandle& btContext); public: TorrentRequestInfo(const string& torrentFile, Option* op): RequestInfo(op), - torrentFile(torrentFile), - e(0) {} + torrentFile(torrentFile) {} + virtual ~TorrentRequestInfo() {} virtual RequestInfo* execute(); @@ -57,8 +57,10 @@ public: void setTargetFiles(const Strings& targetFiles) { this->targetFiles = targetFiles; } - virtual DownloadEngine* getDownloadEngine() { return e; } + virtual DownloadEngine* getDownloadEngine() { + return 0; + } }; #endif // _D_TORRENT_REQUEST_INFO_H_ diff --git a/src/TrackerUpdateCommand.cc b/src/TrackerUpdateCommand.cc index 1fdebc96..eebe71b4 100644 --- a/src/TrackerUpdateCommand.cc +++ b/src/TrackerUpdateCommand.cc @@ -40,7 +40,13 @@ #include "SleepCommand.h" #include "Util.h" -TrackerUpdateCommand::TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e):Command(cuid), e(e) { +extern PeerHandle nullPeer; + +TrackerUpdateCommand::TrackerUpdateCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext): + BtContextAwareCommand(cuid, btContext), e(e) +{ logger = LogFactory::getInstance(); } @@ -77,7 +83,7 @@ char* TrackerUpdateCommand::getTrackerResponse(size_t& trackerResponseLength) { } bool TrackerUpdateCommand::execute() { - if(e->segmentMan->errors > 0 && e->torrentMan->isHalt()) { + if(e->segmentMan->errors > 0 && btRuntime->isHalt()) { return true; } if(!e->segmentMan->finished()) { @@ -89,19 +95,25 @@ bool TrackerUpdateCommand::execute() { try { trackerResponse = getTrackerResponse(trackerResponseLength); - e->torrentMan->processAnnounceResponse(trackerResponse, - trackerResponseLength); - while(e->torrentMan->needMorePeerConnection()) { - PeerHandle peer = e->torrentMan->getPeer(); - int newCuid = e->torrentMan->getNewCuid(); + btAnnounce->processAnnounceResponse(trackerResponse, + trackerResponseLength); + while(!btRuntime->isHalt() && btRuntime->lessThanMinPeer()) { + PeerHandle peer = peerStorage->getUnusedPeer(); + if(peer == nullPeer) { + break; + } + int newCuid = btRuntime->getNewCuid(); peer->cuid = newCuid; PeerInitiateConnectionCommand* command = - new PeerInitiateConnectionCommand(newCuid, peer, e); + new PeerInitiateConnectionCommand(newCuid, + peer, + e, + btContext); e->commands.push_back(command); logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid); } - e->torrentMan->announceSuccess(); - e->torrentMan->resetAnnounce(); + btAnnounce->announceSuccess(); + btAnnounce->resetAnnounce(); e->segmentMan->init(); } catch(Exception* err) { logger->error("CUID#%d - Error occurred while processing tracker response.", cuid, err); @@ -111,7 +123,7 @@ bool TrackerUpdateCommand::execute() { if(trackerResponse) { delete [] trackerResponse; } - if(e->torrentMan->isHalt()) { + if(btRuntime->isHalt()) { return true; } else { return prepareForRetry(); diff --git a/src/TrackerUpdateCommand.h b/src/TrackerUpdateCommand.h index a4a0ad10..13dd5796 100644 --- a/src/TrackerUpdateCommand.h +++ b/src/TrackerUpdateCommand.h @@ -35,18 +35,21 @@ #ifndef _D_TRACKER_UPDATE_COMMAND_H_ #define _D_TRACKER_UPDATE_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" #include "Logger.h" -class TrackerUpdateCommand : public Command { +class TrackerUpdateCommand : public BtContextAwareCommand { private: TorrentDownloadEngine* e; const Logger* logger; bool prepareForRetry(); char* getTrackerResponse(size_t& trackerResponseLength); public: - TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e); + TrackerUpdateCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext); + virtual ~TrackerUpdateCommand(); bool execute(); diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index cea9a914..825def5d 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -39,17 +39,19 @@ #include "prefs.h" TrackerWatcherCommand::TrackerWatcherCommand(int cuid, - TorrentDownloadEngine* e): - Command(cuid), e(e) { + TorrentDownloadEngine* e, + const BtContextHandle& btContext): + BtContextAwareCommand(cuid, btContext), e(e) +{ } TrackerWatcherCommand::~TrackerWatcherCommand() {} bool TrackerWatcherCommand::execute() { - if(e->torrentMan->isHalt() && - e->segmentMan->errors > 0 && e->torrentMan->isAllAnnounceFailed() || - e->torrentMan->noMoreAnnounce()) { + if(btRuntime->isHalt() && + e->segmentMan->errors > 0 && btAnnounce->isAllAnnounceFailed() || + btAnnounce->noMoreAnnounce()) { return true; } Command* command = createCommand(); @@ -62,18 +64,18 @@ bool TrackerWatcherCommand::execute() { Command* TrackerWatcherCommand::createCommand() { Command* command = 0; - if(e->torrentMan->isAnnounceReady()) { - command = createRequestCommand(e->torrentMan->getAnnounceUrl()); - e->torrentMan->announceStart(); // inside it, trackers++. + if(btAnnounce->isAnnounceReady()) { + command = createRequestCommand(btAnnounce->getAnnounceUrl()); + btAnnounce->announceStart(); // inside it, trackers++. } else if(e->segmentMan->errors > 0) { - e->torrentMan->announceFailure(); // inside it, trackers = 0. + btAnnounce->announceFailure(); // inside it, trackers = 0. e->segmentMan->init(); - if(e->torrentMan->isAllAnnounceFailed()) { - e->torrentMan->resetAnnounce(); + if(btAnnounce->isAllAnnounceFailed()) { + btAnnounce->resetAnnounce(); // sleep a few seconds. command = new SleepCommand(cuid, e, - createRequestCommand(e->torrentMan->getAnnounceUrl()), + createRequestCommand(btAnnounce->getAnnounceUrl()), e->option->getAsInt(PREF_RETRY_WAIT)); } } @@ -84,7 +86,8 @@ Command* TrackerWatcherCommand::createRequestCommand(const string& url) { RequestHandle req; req->setUrl(url); req->isTorrent = true; - Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(e->torrentMan->getNewCuid(), req, e); + Command* command = + InitiateConnectionCommandFactory::createInitiateConnectionCommand(btRuntime->getNewCuid(), req, e); logger->info("CUID#%d - Creating new tracker request command #%d", cuid, command->getCuid()); return command; diff --git a/src/TrackerWatcherCommand.h b/src/TrackerWatcherCommand.h index 17708d1f..785fa7c3 100644 --- a/src/TrackerWatcherCommand.h +++ b/src/TrackerWatcherCommand.h @@ -35,10 +35,10 @@ #ifndef _D_TRACKER_WATCHER_COMMAND_H_ #define _D_TRACKER_WATCHER_COMMAND_H_ -#include "Command.h" +#include "BtContextAwareCommand.h" #include "TorrentDownloadEngine.h" -class TrackerWatcherCommand : public Command { +class TrackerWatcherCommand : public BtContextAwareCommand { private: TorrentDownloadEngine* e; @@ -48,7 +48,10 @@ private: */ Command* createRequestCommand(const string& url); public: - TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e); + TrackerWatcherCommand(int cuid, + TorrentDownloadEngine* e, + const BtContextHandle& btContext); + ~TrackerWatcherCommand(); Command* createCommand(); diff --git a/src/Util.cc b/src/Util.cc index ef2aafd7..ffc38a2a 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -117,20 +117,28 @@ int Util::difftvsec(struct timeval tv1, struct timeval tv2) { return tv1.tv_sec-tv2.tv_sec; } -void Util::slice(Strings& result, const string& src, char delim) { +void Util::slice(Strings& result, const string& src, char delim, bool doTrim) { string::size_type p = 0; while(1) { string::size_type np = src.find(delim, p); if(np == string::npos) { - string term = trim(src.substr(p)); - if(term.size() > 0) { + string term = src.substr(p); + if(doTrim) { + term = trim(term); + } + if(term.size()) { result.push_back(term); } break; } string term = src.substr(p, np-p); + if(doTrim) { + term = trim(term); + } p = np+1; - result.push_back(trim(term)); + if(term.size()) { + result.push_back(term); + } } } diff --git a/src/Util.h b/src/Util.h index 7379b35f..9c9ad79a 100644 --- a/src/Util.h +++ b/src/Util.h @@ -65,7 +65,7 @@ public: * Take a string src which is a deliminated list and add its elements * into result. result is not cleared before conversion begins. */ - static void slice(Strings& result, const string& src, char delim); + static void slice(Strings& result, const string& src, char delim, bool trim = false); static string trim(const string& src); diff --git a/src/common.h b/src/common.h index 2013fdf3..15ebb043 100644 --- a/src/common.h +++ b/src/common.h @@ -71,6 +71,8 @@ public: } }; +#include "SharedHandle.h" + typedef deque Strings; typedef deque Integers; diff --git a/src/main.cc b/src/main.cc index ca4344c3..a14362a1 100644 --- a/src/main.cc +++ b/src/main.cc @@ -105,7 +105,7 @@ void showVersion() { "along with this program; if not, write to the Free Software\n" "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"); cout << endl; - printf(_("Contact Info: %s\n"), "Tasuhiro Tsujikawa "); + printf(_("Contact Info: %s\n"), "Tatsuhiro Tsujikawa "); cout << endl; } diff --git a/test/AnnounceListTest.cc b/test/AnnounceListTest.cc index 2913b637..a081da39 100644 --- a/test/AnnounceListTest.cc +++ b/test/AnnounceListTest.cc @@ -227,10 +227,10 @@ Strings createUrls(const string& url) { } void AnnounceListTest::testMoveToStoppedAllowedTier() { - AnnounceTier t1(createUrls("tracker1")); - AnnounceTier t2(createUrls("tracker2")); - t2.event = AnnounceTier::COMPLETED; - AnnounceTier t3(createUrls("tracker3")); + AnnounceTierHandle t1(new AnnounceTier(createUrls("tracker1"))); + AnnounceTierHandle t2(new AnnounceTier(createUrls("tracker2"))); + t2->event = AnnounceTier::COMPLETED; + AnnounceTierHandle t3(new AnnounceTier(createUrls("tracker3"))); AnnounceTiers tiers; tiers.push_back(t1); @@ -250,10 +250,10 @@ void AnnounceListTest::testMoveToStoppedAllowedTier() { } void AnnounceListTest::testMoveToCompletedAllowedTier() { - AnnounceTier t1(createUrls("tracker1")); - AnnounceTier t2(createUrls("tracker2")); - t2.event = AnnounceTier::COMPLETED; - AnnounceTier t3(createUrls("tracker3")); + AnnounceTierHandle t1(new AnnounceTier(createUrls("tracker1"))); + AnnounceTierHandle t2(new AnnounceTier(createUrls("tracker2"))); + t2->event = AnnounceTier::COMPLETED; + AnnounceTierHandle t3(new AnnounceTier(createUrls("tracker3"))); AnnounceTiers tiers; tiers.push_back(t1); diff --git a/test/BitfieldManTest.cc b/test/BitfieldManTest.cc index 257c4c2f..cdb3b64d 100644 --- a/test/BitfieldManTest.cc +++ b/test/BitfieldManTest.cc @@ -95,21 +95,21 @@ void BitfieldManTest::testFilter() { int index; index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); + CPPUNIT_ASSERT_EQUAL(2, index); + index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); + btman.setUseBit(index); CPPUNIT_ASSERT_EQUAL(3, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); CPPUNIT_ASSERT_EQUAL(4, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); - CPPUNIT_ASSERT_EQUAL(2, index); + CPPUNIT_ASSERT_EQUAL(5, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); CPPUNIT_ASSERT_EQUAL(6, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); - CPPUNIT_ASSERT_EQUAL(5, index); - index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); - btman.setUseBit(index); CPPUNIT_ASSERT_EQUAL(7, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); @@ -118,17 +118,18 @@ void BitfieldManTest::testFilter() { // test offset=5, length=2 btman.clearAllBit(); + btman.clearAllUseBit(); btman.clearFilter(); btman.addFilter(5, 2); btman.enableFilter(); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); btman.setBit(index); - CPPUNIT_ASSERT_EQUAL(3, index); + CPPUNIT_ASSERT_EQUAL(2, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); btman.setBit(index); - CPPUNIT_ASSERT_EQUAL(2, index); + CPPUNIT_ASSERT_EQUAL(3, index); index = btman.getMissingUnusedIndex(peerBt, sizeof(peerBt)); btman.setUseBit(index); CPPUNIT_ASSERT_EQUAL(-1, index); diff --git a/test/BtRegistryTest.cc b/test/BtRegistryTest.cc new file mode 100644 index 00000000..29b97788 --- /dev/null +++ b/test/BtRegistryTest.cc @@ -0,0 +1,88 @@ +#include "BtRegistry.h" +#include "Exception.h" +#include "MockPeerStorage.h" +#include "MockPieceStorage.h" +#include "MockBtAnnounce.h" +#include "MockBtProgressInfoFile.h" +#include +#include + +using namespace std; + +class BtRegistryTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtRegistryTest); + CPPUNIT_TEST(testGetPeerStorage); + CPPUNIT_TEST(testGetPieceStorage); + CPPUNIT_TEST(testGetBtRuntime); + CPPUNIT_TEST(testGetBtAnnounce); + CPPUNIT_TEST(testGetBtProgressInfoFile); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testGetPeerStorage(); + void testGetPieceStorage(); + void testGetBtRuntime(); + void testGetBtAnnounce(); + void testGetBtProgressInfoFile(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION( BtRegistryTest ); + +void BtRegistryTest::testGetPeerStorage() { + CPPUNIT_ASSERT(!BtRegistry::getPeerStorage("test").get()); + + PeerStorageHandle peerStorage(new MockPeerStorage()); + + CPPUNIT_ASSERT(BtRegistry::registerPeerStorage("test", + peerStorage)); + CPPUNIT_ASSERT_EQUAL(peerStorage.get(), + BtRegistry::getPeerStorage("test").get()); +} + +void BtRegistryTest::testGetPieceStorage() { + CPPUNIT_ASSERT(!BtRegistry::getPieceStorage("test").get()); + + PieceStorageHandle pieceStorage(new MockPieceStorage()); + + CPPUNIT_ASSERT(BtRegistry::registerPieceStorage("test", + pieceStorage)); + CPPUNIT_ASSERT_EQUAL(pieceStorage.get(), + BtRegistry::getPieceStorage("test").get()); +} + +void BtRegistryTest::testGetBtRuntime() { + CPPUNIT_ASSERT(!BtRegistry::getBtRuntime("test").get()); + + BtRuntimeHandle runtime; + + CPPUNIT_ASSERT(BtRegistry::registerBtRuntime("test", runtime)); + CPPUNIT_ASSERT_EQUAL(runtime.get(), + BtRegistry::getBtRuntime("test").get()); +} + +void BtRegistryTest::testGetBtAnnounce() { + CPPUNIT_ASSERT(!BtRegistry::getBtAnnounce("test").get()); + + BtAnnounceHandle btAnnounce(new MockBtAnnounce()); + + CPPUNIT_ASSERT(BtRegistry::registerBtAnnounce("test", btAnnounce)); + CPPUNIT_ASSERT_EQUAL(btAnnounce.get(), + BtRegistry::getBtAnnounce("test").get()); +} + +void BtRegistryTest::testGetBtProgressInfoFile() { + CPPUNIT_ASSERT(!BtRegistry::getBtProgressInfoFile("test").get()); + + BtProgressInfoFileHandle btProgressInfoFile(new MockBtProgressInfoFile()); + + CPPUNIT_ASSERT(BtRegistry::registerBtProgressInfoFile("test", + btProgressInfoFile)); + CPPUNIT_ASSERT_EQUAL(btProgressInfoFile.get(), + BtRegistry::getBtProgressInfoFile("test").get()); +} diff --git a/test/DefaultBtAnnounceTest.cc b/test/DefaultBtAnnounceTest.cc new file mode 100644 index 00000000..782cfad2 --- /dev/null +++ b/test/DefaultBtAnnounceTest.cc @@ -0,0 +1,37 @@ +#include "DefaultBtAnnounce.h" +#include "DefaultBtContext.h" +#include "Option.h" +#include "Util.h" +#include "Exception.h" +#include + +using namespace std; + +class DefaultBtAnnounceTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultBtAnnounceTest); + CPPUNIT_TEST(testIsDefaultAnnounceReady); + CPPUNIT_TEST_SUITE_END(); +private: + BtContextHandle btContext; + Option* option; +public: + DefaultBtAnnounceTest():btContext(0) {} + + void setUp() { + btContext = BtContextHandle(new DefaultBtContext()); + btContext->load("test.torrent"); + option = new Option(); + } + + void testIsDefaultAnnounceReady(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtAnnounceTest); + +void DefaultBtAnnounceTest::testIsDefaultAnnounceReady() { + DefaultBtAnnounce btAnnounce(btContext, option); + + CPPUNIT_ASSERT(btAnnounce.isDefaultAnnounceReady()); +} diff --git a/test/DefaultBtContextTest.cc b/test/DefaultBtContextTest.cc new file mode 100644 index 00000000..3010aea9 --- /dev/null +++ b/test/DefaultBtContextTest.cc @@ -0,0 +1,219 @@ +#include "DefaultBtContext.h" +#include "Util.h" +#include "Exception.h" +#include + +using namespace std; + +class DefaultBtContextTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultBtContextTest); + CPPUNIT_TEST(testGetInfoHash); + CPPUNIT_TEST(testGetPieceHash); + CPPUNIT_TEST(testGetFileEntries); + CPPUNIT_TEST(testGetTotalLength); + CPPUNIT_TEST(testGetFileEntriesSingle); + CPPUNIT_TEST(testGetTotalLengthSingle); + CPPUNIT_TEST(testGetFileModeMulti); + CPPUNIT_TEST(testGetFileModeSingle); + CPPUNIT_TEST(testGetNameMulti); + CPPUNIT_TEST(testGetNameSingle); + CPPUNIT_TEST(testGetAnnounceTier); + CPPUNIT_TEST(testGetAnnounceTierAnnounceList); + CPPUNIT_TEST(testGetPieceLength); + CPPUNIT_TEST(testGetInfoHashAsString); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp() { + } + + void testGetInfoHash(); + void testGetPieceHash(); + void testGetFileEntries(); + void testGetTotalLength(); + void testGetFileEntriesSingle(); + void testGetTotalLengthSingle(); + void testGetFileModeMulti(); + void testGetFileModeSingle(); + void testGetNameMulti(); + void testGetNameSingle(); + void testGetAnnounceTier(); + void testGetAnnounceTierAnnounceList(); + void testGetPieceLength(); + void testGetInfoHashAsString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtContextTest); + +void DefaultBtContextTest::testGetInfoHash() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + string correctHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c"; + + CPPUNIT_ASSERT_EQUAL(20, btContext.getInfoHashLength()); + CPPUNIT_ASSERT_EQUAL(correctHash, Util::toHex(btContext.getInfoHash(), + btContext.getInfoHashLength())); +} + +void DefaultBtContextTest::testGetPieceHash() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + CPPUNIT_ASSERT_EQUAL(Util::toHex((const unsigned char*)"AAAAAAAAAAAAAAAAAAAA", 20), + btContext.getPieceHash(0)); + CPPUNIT_ASSERT_EQUAL(Util::toHex((const unsigned char*)"BBBBBBBBBBBBBBBBBBBB", 20), + btContext.getPieceHash(1)); + CPPUNIT_ASSERT_EQUAL(Util::toHex((const unsigned char*)"CCCCCCCCCCCCCCCCCCCC", 20), + btContext.getPieceHash(2)); + CPPUNIT_ASSERT_EQUAL(string(""), + btContext.getPieceHash(-1)); + CPPUNIT_ASSERT_EQUAL(string(""), + btContext.getPieceHash(3)); +} + +void DefaultBtContextTest::testGetFileEntries() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + // This is multi-file torrent. + FileEntries fileEntries = btContext.getFileEntries(); + // There are 2 file entries. + CPPUNIT_ASSERT_EQUAL((size_t)2, fileEntries.size()); + FileEntries::iterator itr = fileEntries.begin(); + + FileEntryHandle fileEntry1 = *itr; + CPPUNIT_ASSERT_EQUAL(string("aria2/src/aria2c"), + fileEntry1->getPath()); + itr++; + FileEntryHandle fileEntry2 = *itr; + CPPUNIT_ASSERT_EQUAL(string("aria2-0.2.2.tar.bz2"), + fileEntry2->getPath()); +} + +void DefaultBtContextTest::testGetFileEntriesSingle() { + DefaultBtContext btContext; + btContext.load("single.torrent"); + // This is multi-file torrent. + FileEntries fileEntries = btContext.getFileEntries(); + // There is 1 file entry. + CPPUNIT_ASSERT_EQUAL((size_t)1, fileEntries.size()); + FileEntries::iterator itr = fileEntries.begin(); + + FileEntryHandle fileEntry1 = *itr; + CPPUNIT_ASSERT_EQUAL(string("aria2-0.8.2.tar.bz2"), + fileEntry1->getPath()); +} + +void DefaultBtContextTest::testGetTotalLength() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + CPPUNIT_ASSERT_EQUAL((long long int)384, + btContext.getTotalLength()); +} + +void DefaultBtContextTest::testGetTotalLengthSingle() { + DefaultBtContext btContext; + btContext.load("single.torrent"); + + CPPUNIT_ASSERT_EQUAL((long long int)384, + btContext.getTotalLength()); +} + +void DefaultBtContextTest::testGetFileModeMulti() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + CPPUNIT_ASSERT_EQUAL(BtContext::MULTI, + btContext.getFileMode()); +} + +void DefaultBtContextTest::testGetFileModeSingle() { + DefaultBtContext btContext; + btContext.load("single.torrent"); + + CPPUNIT_ASSERT_EQUAL(BtContext::SINGLE, + btContext.getFileMode()); +} + +void DefaultBtContextTest::testGetNameMulti() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + CPPUNIT_ASSERT_EQUAL(string("aria2-test"), + btContext.getName()); +} + +void DefaultBtContextTest::testGetNameSingle() { + DefaultBtContext btContext; + btContext.load("single.torrent"); + + CPPUNIT_ASSERT_EQUAL(string("aria2-0.8.2.tar.bz2"), + btContext.getName()); +} + +void DefaultBtContextTest::testGetAnnounceTier() { + DefaultBtContext btContext; + btContext.load("single.torrent"); + + AnnounceTiers tiers = btContext.getAnnounceTiers(); + + // There is 1 tier. + CPPUNIT_ASSERT_EQUAL((size_t)1, + tiers.size()); + + AnnounceTiers::iterator itr = tiers.begin(); + AnnounceTierHandle tier1 = *itr; + CPPUNIT_ASSERT_EQUAL((size_t)1, + tier1->urls.size()); + CPPUNIT_ASSERT_EQUAL(string("http://aria.rednoah.com/announce.php"), + tier1->urls.at(0)); + +} + +void DefaultBtContextTest::testGetAnnounceTierAnnounceList() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + AnnounceTiers tiers = btContext.getAnnounceTiers(); + + // There are 3 tiers. + CPPUNIT_ASSERT_EQUAL((size_t)3, + tiers.size()); + + AnnounceTierHandle tier1 = tiers.at(0); + CPPUNIT_ASSERT_EQUAL((size_t)1, + tier1->urls.size()); + CPPUNIT_ASSERT_EQUAL(string("http://tracker1"), + tier1->urls.at(0)); + + AnnounceTierHandle tier2 = tiers.at(1); + CPPUNIT_ASSERT_EQUAL((size_t)1, + tier2->urls.size()); + CPPUNIT_ASSERT_EQUAL(string("http://tracker2"), + tier2->urls.at(0)); + + AnnounceTierHandle tier3 = tiers.at(2); + CPPUNIT_ASSERT_EQUAL((size_t)1, + tier3->urls.size()); + CPPUNIT_ASSERT_EQUAL(string("http://tracker3"), + tier3->urls.at(0)); + +} + +void DefaultBtContextTest::testGetPieceLength() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + CPPUNIT_ASSERT_EQUAL(128, + btContext.getPieceLength()); +} + +void DefaultBtContextTest::testGetInfoHashAsString() { + DefaultBtContext btContext; + btContext.load("test.torrent"); + + CPPUNIT_ASSERT_EQUAL(string("248d0a1cd08284299de78d5c1ed359bb46717d8c"), + btContext.getInfoHashAsString()); +} diff --git a/test/DefaultBtProgressInfoFileTest.cc b/test/DefaultBtProgressInfoFileTest.cc new file mode 100644 index 00000000..5613f95c --- /dev/null +++ b/test/DefaultBtProgressInfoFileTest.cc @@ -0,0 +1,34 @@ +#include "DefaultBtProgressInfoFile.h" +#include "DefaultBtContext.h" +#include "Option.h" +#include "Util.h" +#include "Exception.h" +#include + +using namespace std; + +class DefaultBtProgressInfoFileTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultBtProgressInfoFileTest); + CPPUNIT_TEST(testSave); + CPPUNIT_TEST_SUITE_END(); +private: + BtContextHandle btContext; + Option* option; +public: + DefaultBtProgressInfoFileTest():btContext(0) {} + + void setUp() { + btContext = BtContextHandle(new DefaultBtContext()); + btContext->load("test.torrent"); + option = new Option(); + } + + void testSave(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtProgressInfoFileTest); + +void DefaultBtProgressInfoFileTest::testSave() { +} diff --git a/test/DefaultPeerStorageTest.cc b/test/DefaultPeerStorageTest.cc new file mode 100644 index 00000000..1d65bd60 --- /dev/null +++ b/test/DefaultPeerStorageTest.cc @@ -0,0 +1,204 @@ +#include "DefaultPeerStorage.h" +#include "DefaultBtContext.h" +#include "Util.h" +#include "Exception.h" +#include + +extern PeerHandle nullPeer; + +using namespace std; + +class DefaultPeerStorageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultPeerStorageTest); + CPPUNIT_TEST(testCountPeer); + CPPUNIT_TEST(testDeleteUnusedPeer); + CPPUNIT_TEST(testAddPeer); + CPPUNIT_TEST(testGetPeer); + CPPUNIT_TEST(testIsPeerAvailable); + CPPUNIT_TEST(testActivatePeer); + CPPUNIT_TEST(testCalculateStat); + CPPUNIT_TEST_SUITE_END(); +private: + BtContextHandle btContext; + BtRuntimeHandle btRuntime; + Option* option; +public: + DefaultPeerStorageTest():btContext(0) {} + + void setUp() { + btContext = BtContextHandle(new DefaultBtContext()); + btContext->load("test.torrent"); + option = new Option(); + btRuntime = BtRuntimeHandle(new BtRuntime()); + } + + void testCountPeer(); + void testDeleteUnusedPeer(); + void testAddPeer(); + void testGetPeer(); + void testIsPeerAvailable(); + void testActivatePeer(); + void testCalculateStat(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultPeerStorageTest); + +void DefaultPeerStorageTest::testCountPeer() { + DefaultPeerStorage ps(btContext, option); + + CPPUNIT_ASSERT_EQUAL(0, + ps.countPeer()); + + PeerHandle peer(new Peer("192.168.0.1", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + ps.addPeer(peer); + CPPUNIT_ASSERT_EQUAL(1, + ps.countPeer()); +} + +void DefaultPeerStorageTest::testDeleteUnusedPeer() { + DefaultPeerStorage ps(btContext, option); + + PeerHandle peer1(new Peer("192.168.0.1", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + PeerHandle peer2(new Peer("192.168.0.2", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + PeerHandle peer3(new Peer("192.168.0.3", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + + ps.addPeer(peer1); + ps.addPeer(peer2); + ps.addPeer(peer3); + + ps.deleteUnusedPeer(2); + + CPPUNIT_ASSERT_EQUAL(1, ps.countPeer()); + CPPUNIT_ASSERT_EQUAL(string("192.168.0.3"), + ps.getPeer("192.168.0.3", 6889)->ipaddr); + + ps.addPeer(peer1); + ps.addPeer(peer2); + + peer2->cuid = 1; + + ps.deleteUnusedPeer(3); + + // peer2 has been in use, so it did't deleted. + CPPUNIT_ASSERT_EQUAL(1, ps.countPeer()); + CPPUNIT_ASSERT_EQUAL(string("192.168.0.2"), + ps.getPeer("192.168.0.2", 6889)->ipaddr); + +} + +void DefaultPeerStorageTest::testAddPeer() { + DefaultPeerStorage ps(btContext, option); + + PeerHandle peer1(new Peer("192.168.0.1", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + PeerHandle peer2(new Peer("192.168.0.2", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + PeerHandle peer3(new Peer("192.168.0.3", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + + ps.addPeer(peer1); + ps.addPeer(peer2); + ps.addPeer(peer3); + + CPPUNIT_ASSERT_EQUAL(3, ps.countPeer()); + + // this is true, because peer1 in the container has no errors and + // it is replaced by peer1(self assignment). + CPPUNIT_ASSERT_EQUAL(true, ps.addPeer(peer1)); + // the number of peers doesn't change. + CPPUNIT_ASSERT_EQUAL(3, ps.countPeer()); + + ps.setMaxPeerListSize(3); + + PeerHandle peer4(new Peer("192.168.0.4", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + + CPPUNIT_ASSERT(ps.addPeer(peer4)); + // peer3 was deleted. + CPPUNIT_ASSERT_EQUAL(3, ps.countPeer()); + + peer4->error = MAX_PEER_ERROR; + + // this returns false, because peer4 in the container has error. + CPPUNIT_ASSERT_EQUAL(false, ps.addPeer(peer4)); +} + +void DefaultPeerStorageTest::testGetPeer() { + DefaultPeerStorage ps(btContext, option); + ps.setBtRuntime(btRuntime); + + PeerHandle peer1(new Peer("192.168.0.1", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + + ps.addPeer(peer1); + + CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), + ps.getUnusedPeer()->ipaddr); + + peer1->cuid = 1; + + CPPUNIT_ASSERT(nullPeer == ps.getUnusedPeer()); + + peer1->resetStatus(); + peer1->error = 1; + + CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), + ps.getUnusedPeer()->ipaddr); + + peer1->resetStatus(); + peer1->error = MAX_PEER_ERROR; + + CPPUNIT_ASSERT(nullPeer == ps.getUnusedPeer()); +} + +void DefaultPeerStorageTest::testIsPeerAvailable() { + DefaultPeerStorage ps(btContext, option); + ps.setBtRuntime(btRuntime); + + CPPUNIT_ASSERT_EQUAL(false, ps.isPeerAvailable()); + + PeerHandle peer1(new Peer("192.168.0.1", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + + ps.addPeer(peer1); + + CPPUNIT_ASSERT_EQUAL(true, ps.isPeerAvailable()); + + peer1->cuid = 1; + + CPPUNIT_ASSERT_EQUAL(false, ps.isPeerAvailable()); + + peer1->resetStatus(); + + peer1->error = MAX_PEER_ERROR; + + CPPUNIT_ASSERT_EQUAL(false, ps.isPeerAvailable()); +} + +void DefaultPeerStorageTest::testActivatePeer() { + DefaultPeerStorage ps(btContext, option); + + CPPUNIT_ASSERT_EQUAL((size_t)0, ps.getActivePeers().size()); + + PeerHandle peer1(new Peer("192.168.0.1", 6889, btContext->getPieceLength(), + btContext->getTotalLength())); + + ps.addPeer(peer1); + + Peers activePeer = ps.getActivePeers(); + + CPPUNIT_ASSERT_EQUAL((size_t)0, ps.getActivePeers().size()); + + peer1->activate(); + + CPPUNIT_ASSERT_EQUAL((size_t)1, ps.getActivePeers().size()); +} + +void DefaultPeerStorageTest::testCalculateStat() { +} diff --git a/test/DefaultPieceStorageTest.cc b/test/DefaultPieceStorageTest.cc new file mode 100644 index 00000000..d26926b0 --- /dev/null +++ b/test/DefaultPieceStorageTest.cc @@ -0,0 +1,110 @@ +#include "DefaultPieceStorage.h" +#include "DefaultBtContext.h" +#include "Util.h" +#include "Exception.h" +#include + +using namespace std; + +class DefaultPieceStorageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultPieceStorageTest); + CPPUNIT_TEST(testGetTotalLength); + CPPUNIT_TEST(testGetMissingPiece); + CPPUNIT_TEST(testGetMissingFastPiece); + CPPUNIT_TEST(testHasMissingPiece); + CPPUNIT_TEST(testCompletePiece); + CPPUNIT_TEST_SUITE_END(); +private: + BtContextHandle btContext; + PeerHandle peer; + Option* option; +public: + DefaultPieceStorageTest():btContext(0) {} + + void setUp() { + btContext = BtContextHandle(new DefaultBtContext()); + btContext->load("test.torrent"); + peer = PeerHandle(new Peer("192.168.0.1", 6889, + btContext->getPieceLength(), + btContext->getTotalLength())); + option = new Option(); + } + + void testGetTotalLength(); + void testGetMissingPiece(); + void testGetMissingFastPiece(); + void testHasMissingPiece(); + void testCompletePiece(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultPieceStorageTest); + +void DefaultPieceStorageTest::testGetTotalLength() { + DefaultPieceStorage pss(btContext, option); + + CPPUNIT_ASSERT_EQUAL((long long int)384, + pss.getTotalLength()); +} + +void DefaultPieceStorageTest::testGetMissingPiece() { + DefaultPieceStorage pss(btContext, option); + pss.setEndGamePieceNum(0); + + peer->setAllBitfield(); + Piece piece = pss.getMissingPiece(peer); + CPPUNIT_ASSERT_EQUAL(string("piece: index=0, length=128"), + piece.toString()); + piece = pss.getMissingPiece(peer); + CPPUNIT_ASSERT_EQUAL(string("piece: index=1, length=128"), + piece.toString()); + piece = pss.getMissingPiece(peer); + CPPUNIT_ASSERT_EQUAL(string("piece: index=2, length=128"), + piece.toString()); + piece = pss.getMissingPiece(peer); + CPPUNIT_ASSERT(Piece::isNull(piece)); +} + +void DefaultPieceStorageTest::testGetMissingFastPiece() { + DefaultPieceStorage pss(btContext, option); + pss.setEndGamePieceNum(0); + + peer->setAllBitfield(); + peer->setFastExtensionEnabled(true); + peer->addFastSetIndex(2); + + Piece piece = pss.getMissingFastPiece(peer); + CPPUNIT_ASSERT_EQUAL(string("piece: index=2, length=128"), + piece.toString()); +} + +void DefaultPieceStorageTest::testHasMissingPiece() { + DefaultPieceStorage pss(btContext, option); + + CPPUNIT_ASSERT(!pss.hasMissingPiece(peer)); + + peer->setAllBitfield(); + + CPPUNIT_ASSERT(pss.hasMissingPiece(peer)); +} + +void DefaultPieceStorageTest::testCompletePiece() { + DefaultPieceStorage pss(btContext, option); + pss.setEndGamePieceNum(0); + + peer->setAllBitfield(); + + Piece piece = pss.getMissingPiece(peer); + CPPUNIT_ASSERT_EQUAL(string("piece: index=0, length=128"), + piece.toString()); + + CPPUNIT_ASSERT_EQUAL((long long int)0, + pss.getCompletedLength()); + + pss.completePiece(piece); + + CPPUNIT_ASSERT_EQUAL((long long int)128, + pss.getCompletedLength()); + +} diff --git a/test/FileTest.cc b/test/FileTest.cc index a31f824a..3dfd65bf 100644 --- a/test/FileTest.cc +++ b/test/FileTest.cc @@ -15,6 +15,7 @@ class FileTest:public CppUnit::TestFixture { CPPUNIT_TEST(testIsDir); CPPUNIT_TEST(testRemove); CPPUNIT_TEST(testSize); + CPPUNIT_TEST(testMkdir); CPPUNIT_TEST_SUITE_END(); private: @@ -27,6 +28,7 @@ public: void testIsDir(); void testRemove(); void testSize(); + void testMkdir(); }; @@ -68,6 +70,7 @@ void FileTest::testIsDir() { void FileTest::testRemove() { int fd; string name = "/tmp/aria2test"; + unlink(name.c_str()); if((fd = creat(name.c_str(), S_IRUSR|S_IWUSR)) < 0) { CPPUNIT_FAIL("cannot create test file"); } @@ -93,3 +96,19 @@ void FileTest::testSize() { File f("4096chunk.txt"); CPPUNIT_ASSERT_EQUAL(4096, (int)f.size()); } + +void FileTest::testMkdir() { + string dir = "/tmp/aria2test2/test"; + File d(dir); + if(d.exists()) { + CPPUNIT_ASSERT(d.remove()); + } + CPPUNIT_ASSERT(!d.exists()); + + CPPUNIT_ASSERT(d.mkdirs()); + + CPPUNIT_ASSERT(d.exists()); + // this test failes because d.mkdir returns false when the directory is + // already exists. + CPPUNIT_ASSERT(!d.mkdirs()); +} diff --git a/test/Makefile.am b/test/Makefile.am index 01091dab..10e5f44a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,7 +13,6 @@ aria2c_SOURCES = AllTest.cc\ ListTest.cc\ MetaFileUtilTest.cc\ ShaVisitorTest.cc\ - TorrentManTest.cc\ PeerMessageUtilTest.cc\ BitfieldManTest.cc\ DefaultDiskWriterTest.cc\ @@ -42,7 +41,12 @@ aria2c_SOURCES = AllTest.cc\ SpeedCalcTest.cc\ DefaultPeerListProcessorTest.cc\ AnnounceListTest.cc\ - TrackerWatcherCommandTest.cc + TrackerWatcherCommandTest.cc\ + DefaultBtContextTest.cc\ + DefaultPieceStorageTest.cc\ + DefaultPeerStorageTest.cc\ + DefaultBtAnnounceTest.cc\ + BtRegistryTest.cc #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} diff --git a/test/Makefile.in b/test/Makefile.in index 90750cfd..514243d8 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -63,11 +63,11 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \ CookieBoxTest.$(OBJEXT) DataTest.$(OBJEXT) \ DictionaryTest.$(OBJEXT) ListTest.$(OBJEXT) \ MetaFileUtilTest.$(OBJEXT) ShaVisitorTest.$(OBJEXT) \ - TorrentManTest.$(OBJEXT) PeerMessageUtilTest.$(OBJEXT) \ - BitfieldManTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT) \ - MultiDiskWriterTest.$(OBJEXT) ChokeMessageTest.$(OBJEXT) \ - UnchokeMessageTest.$(OBJEXT) HaveAllMessageTest.$(OBJEXT) \ - HaveNoneMessageTest.$(OBJEXT) InterestedMessageTest.$(OBJEXT) \ + PeerMessageUtilTest.$(OBJEXT) BitfieldManTest.$(OBJEXT) \ + DefaultDiskWriterTest.$(OBJEXT) MultiDiskWriterTest.$(OBJEXT) \ + ChokeMessageTest.$(OBJEXT) UnchokeMessageTest.$(OBJEXT) \ + HaveAllMessageTest.$(OBJEXT) HaveNoneMessageTest.$(OBJEXT) \ + InterestedMessageTest.$(OBJEXT) \ NotInterestedMessageTest.$(OBJEXT) HaveMessageTest.$(OBJEXT) \ BitfieldMessageTest.$(OBJEXT) RequestMessageTest.$(OBJEXT) \ CancelMessageTest.$(OBJEXT) PieceMessageTest.$(OBJEXT) \ @@ -78,7 +78,11 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \ ShareRatioSeedCriteriaTest.$(OBJEXT) \ TimeSeedCriteriaTest.$(OBJEXT) SegmentManTest.$(OBJEXT) \ SpeedCalcTest.$(OBJEXT) DefaultPeerListProcessorTest.$(OBJEXT) \ - AnnounceListTest.$(OBJEXT) TrackerWatcherCommandTest.$(OBJEXT) + AnnounceListTest.$(OBJEXT) TrackerWatcherCommandTest.$(OBJEXT) \ + DefaultBtContextTest.$(OBJEXT) \ + DefaultPieceStorageTest.$(OBJEXT) \ + DefaultPeerStorageTest.$(OBJEXT) \ + DefaultBtAnnounceTest.$(OBJEXT) BtRegistryTest.$(OBJEXT) aria2c_OBJECTS = $(am_aria2c_OBJECTS) am__DEPENDENCIES_1 = aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1) @@ -251,7 +255,6 @@ aria2c_SOURCES = AllTest.cc\ ListTest.cc\ MetaFileUtilTest.cc\ ShaVisitorTest.cc\ - TorrentManTest.cc\ PeerMessageUtilTest.cc\ BitfieldManTest.cc\ DefaultDiskWriterTest.cc\ @@ -280,7 +283,12 @@ aria2c_SOURCES = AllTest.cc\ SpeedCalcTest.cc\ DefaultPeerListProcessorTest.cc\ AnnounceListTest.cc\ - TrackerWatcherCommandTest.cc + TrackerWatcherCommandTest.cc\ + DefaultBtContextTest.cc\ + DefaultPieceStorageTest.cc\ + DefaultPeerStorageTest.cc\ + DefaultBtAnnounceTest.cc\ + BtRegistryTest.cc #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} @@ -349,13 +357,18 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CancelMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChokeMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncodingTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounceTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtContextTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriterTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessorTest.Po@am__quote@ +@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)/DictionaryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfigTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@ @@ -381,7 +394,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalcTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommandTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@ diff --git a/test/MockBtAnnounce.h b/test/MockBtAnnounce.h new file mode 100644 index 00000000..a34e0cd2 --- /dev/null +++ b/test/MockBtAnnounce.h @@ -0,0 +1,62 @@ +#ifndef _D_MOCK_BT_ANNOUNCE_H_ +#define _D_MOCK_BT_ANNOUNCE_H_ + +#include "BtAnnounce.h" + +class MockBtAnnounce : public BtAnnounce { +private: + bool announceReady; + string announceUrl; + string peerId; +public: + MockBtAnnounce() {} + virtual ~MockBtAnnounce() {} + + virtual bool isAnnounceReady() { + return announceReady; + } + + void setAnnounceReady(bool flag) { + this->announceReady = flag; + } + + virtual string getAnnounceUrl() { + return announceUrl; + } + + void setAnnounceUrl(const string& url) { + this->announceUrl = url; + } + + virtual void announceStart() {} + + virtual void announceSuccess() {} + + virtual void announceFailure() {} + + virtual bool isAllAnnounceFailed() { + return false; + } + + virtual void resetAnnounce() {} + + virtual void processAnnounceResponse(const char* trackerResponse, + size_t trackerResponseLength) {} + + virtual bool noMoreAnnounce() { + return false; + } + + virtual void shuffleAnnounce() { + } + + virtual string getPeerId() { + return peerId; + } + + void setPeerId(const string& peerId) { + this->peerId = peerId; + } +}; + +#endif // _D_MOCK_BT_ANNOUNCE_H_ diff --git a/test/MockBtContext.h b/test/MockBtContext.h new file mode 100644 index 00000000..96139edc --- /dev/null +++ b/test/MockBtContext.h @@ -0,0 +1,105 @@ +#ifndef _D_MOCK_BT_CONTEXT_H_ +#define _D_MOCK_BT_CONTEXT_H_ + +#include "BtContext.h" +#include "Util.h" + +class MockBtContext : public BtContext { +private: + unsigned char infoHash[20]; + Strings pieceHashes; + long long int totalLength; + FILE_MODE fileMode; + string name; + int pieceLength; + int numPieces; + FileEntries fileEntries; + AnnounceTiers announceTiers; +public: + MockBtContext() {} + virtual ~MockBtContext() {} + + virtual const unsigned char* getInfoHash() const { + return infoHash; + } + + void setInfoHash(const unsigned char* infoHash) { + memcpy(this->infoHash, infoHash, sizeof(this->infoHash)); + } + + virtual int getInfoHashLength() const { + return sizeof(infoHash); + } + + virtual string getInfoHashAsString() const { + return Util::toHex(infoHash, sizeof(infoHash)); + } + + virtual string getPieceHash(int index) const { + return pieceHashes.at(index); + } + + void addPieceHash(const string pieceHash) { + pieceHashes.push_back(pieceHash); + } + + virtual long long int getTotalLength() const { + return totalLength; + } + + void setTotalLength(long long int length) { + this->totalLength = length; + } + + virtual FILE_MODE getFileMode() const { + return fileMode; + } + + void setFileMode(FILE_MODE fileMode) { + this->fileMode = fileMode; + } + + virtual FileEntries getFileEntries() const { + return fileEntries; + } + + void addFileEntry(const FileEntryHandle& fileEntry) { + fileEntries.push_back(fileEntry); + } + + virtual AnnounceTiers getAnnounceTiers() const { + return announceTiers; + } + + void addAnnounceTier(const AnnounceTierHandle& announceTier) { + announceTiers.push_back(announceTier); + } + + virtual void load(const string& torrentFile) {} + + virtual string getName() const { + return name; + } + + void setName(const string& name) { + this->name = name; + } + + virtual int getPieceLength() const { + return pieceLength; + } + + void setPieceLength(int pieceLength) { + this->pieceLength = pieceLength; + } + + virtual int getNumPieces() const { + return numPieces; + } + + void setNumPieces(int numPieces) { + this->numPieces = numPieces; + } +}; + +#endif // _D_MOCK_BT_CONTEXT_H_ diff --git a/test/MockBtProgressInfoFile.h b/test/MockBtProgressInfoFile.h new file mode 100644 index 00000000..7a651d0f --- /dev/null +++ b/test/MockBtProgressInfoFile.h @@ -0,0 +1,32 @@ +#ifndef _D_MOCK_BT_PROGRESS_INFO_FILE_H_ +#define _D_MOCK_BT_PROGRESS_INFO_FILE_H_ + +#include "BtProgressInfoFile.h" + +class MockBtProgressInfoFile : public BtProgressInfoFile { +private: + string filename; +public: + MockBtProgressInfoFile() {} + virtual ~MockBtProgressInfoFile() {} + + virtual string getFilename() { + return filename; + } + + virtual void setFilename(const string& filename) { + this->filename = filename; + } + + virtual bool exists() { + return false; + } + + virtual void save() {} + + virtual void load() {} + + virtual void removeFile() {} +}; + +#endif // _D_MOCK_BT_PROGRESS_INFO_FILE_H_ diff --git a/test/MockPeerStorage.h b/test/MockPeerStorage.h new file mode 100644 index 00000000..90796529 --- /dev/null +++ b/test/MockPeerStorage.h @@ -0,0 +1,49 @@ +#ifndef _D_MOCK_PEER_STORAGE_H_ +#define _D_MOCK_PEER_STORAGE_H_ + +#include "PeerStorage.h" + +class MockPeerStorage : public PeerStorage { +private: + TransferStat stat; + Peers peers; + Peers activePeers; +public: + MockPeerStorage() {} + virtual ~MockPeerStorage() {} + + virtual bool addPeer(const PeerHandle& peer) { + peers.push_back(peer); + return true; + } + + virtual void addPeer(const Peers& peers) { + copy(peers.begin(), peers.end(), back_inserter(this->peers)); + } + + virtual const Peers& getPeers() { + return peers; + } + + virtual PeerHandle getUnusedPeer() { + return 0; + } + + virtual bool isPeerAvailable() { + return false; + } + + virtual Peers getActivePeers() { + return activePeers; + } + + virtual TransferStat calculateStat() { + return stat; + } + + void setStat(const TransferStat& stat) { + this->stat = stat; + } +}; + +#endif // _D_MOCK_PEER_STORAGE_H_ diff --git a/test/MockPieceStorage.h b/test/MockPieceStorage.h new file mode 100644 index 00000000..2b1be23c --- /dev/null +++ b/test/MockPieceStorage.h @@ -0,0 +1,151 @@ +#ifndef _D_MOCK_PIECE_STORAGE_H_ +#define _D_MOCK_PIECE_STORAGE_H_ + +#include "PieceStorage.h" +#include "BitfieldMan.h" + +class MockPieceStorage : public PieceStorage { +private: + long long int totalLength; + long long int filteredTotalLength; + long long int completedLength; + long long int filteredCompletedLength; + BitfieldMan* bitfieldMan; + bool selectiveDownloadingMode; + bool endGame; + DiskAdaptor* diskAdaptor; + Integers pieceLengthList; +public: + MockPieceStorage() {} + virtual ~MockPieceStorage() {} + + virtual bool hasMissingPiece(const PeerHandle& peer) { + return false; + } + + virtual Piece getMissingPiece(const PeerHandle& peer) { + return Piece(); + } + + virtual Piece getMissingFastPiece(const PeerHandle& peer) { + return Piece(); + } + + virtual void completePiece(const Piece& piece) {} + + virtual void cancelPiece(const Piece& piece) {} + + virtual void updatePiece(const Piece& piece) {} + + virtual void syncPiece(Piece& piece) {} + + virtual bool hasPiece(int index) { + return false; + } + + virtual long long int getTotalLength() { + return totalLength; + } + + void setTotalLength(long long int totalLength) { + this->totalLength = totalLength; + } + + virtual long long int getFilteredTotalLength() { + return filteredTotalLength; + } + + void setFilteredTotalLength(long long int totalLength) { + this->filteredTotalLength = totalLength; + } + + virtual long long int getCompletedLength() { + return completedLength; + } + + void setCompletedLength(long long int completedLength) { + this->completedLength = completedLength; + } + + virtual long long int getFilteredCompletedLength() { + return filteredCompletedLength; + } + + void setFilteredCompletedLength(long long int completedLength) { + this->filteredCompletedLength = completedLength; + } + + virtual void setFileFilter(const Strings& filePaths) {} + + virtual void setFileFilter(const Integers& fileIndexes) {} + + virtual void clearFileFilter() {} + + virtual bool downloadFinished() { + return false; + } + + virtual void initStorage() {} + + virtual const unsigned char* getBitfield() { + return bitfieldMan->getBitfield(); + } + + virtual void setBitfield(const unsigned char* bitfield, + int bitfieldLength) { + bitfieldMan->setBitfield(bitfield, bitfieldLength); + } + + virtual int getBitfieldLength() { + return bitfieldMan->getBitfieldLength(); + } + + void setBitfield(BitfieldMan* bitfieldMan) { + this->bitfieldMan = bitfieldMan; + } + + virtual bool isSelectiveDownloadingMode() { + return selectiveDownloadingMode; + } + + void setSelectiveDownloadingMode(bool flag) { + this->selectiveDownloadingMode = flag; + } + + virtual void finishSelectiveDownloadingMode() {} + + virtual bool isEndGame() { + return endGame; + } + + void setEndGame(bool flag) { + this->endGame = flag; + } + + virtual DiskAdaptor* getDiskAdaptor() { + return diskAdaptor; + } + + void setDiskAdaptor(DiskAdaptor* adaptor) { + this->diskAdaptor = adaptor; + } + + virtual int getPieceLength(int index) { + return pieceLengthList.at(index); + } + + void addPieceLengthList(int length) { + pieceLengthList.push_back(length); + } + + virtual void advertisePiece(int cuid, int index) {} + + virtual Integers getAdvertisedPieceIndexes(int myCuid, + const Time& lastCheckTime) { + return Integers(); + } + + virtual void removeAdvertisedPiece(int elapsed) {} +}; + +#endif // _D_MOCK_PIECE_STORAGE_H_ diff --git a/test/MultiDiskWriterTest.cc b/test/MultiDiskWriterTest.cc index 6cca9cb5..80e9972c 100644 --- a/test/MultiDiskWriterTest.cc +++ b/test/MultiDiskWriterTest.cc @@ -26,9 +26,9 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION( MultiDiskWriterTest ); FileEntries createEntries() { - FileEntry entry1("file1.txt", 15, 0); - FileEntry entry2("file2.txt", 7, 15); - FileEntry entry3("file3.txt", 3, 22); + FileEntryHandle entry1(new FileEntry("file1.txt", 15, 0)); + FileEntryHandle entry2(new FileEntry("file2.txt", 7, 15)); + FileEntryHandle entry3(new FileEntry("file3.txt", 3, 22)); unlink("file1.txt"); unlink("file2.txt"); unlink("file3.txt"); @@ -94,9 +94,9 @@ void MultiDiskWriterTest::testWriteData() { } void MultiDiskWriterTest::testReadData() { - FileEntry entry1("file1r.txt", 15, 0); - FileEntry entry2("file2r.txt", 7, 15); - FileEntry entry3("file3r.txt", 3, 22); + FileEntryHandle entry1(new FileEntry("file1r.txt", 15, 0)); + FileEntryHandle entry2(new FileEntry("file2r.txt", 7, 15)); + FileEntryHandle entry3(new FileEntry("file3r.txt", 3, 22)); FileEntries entries; entries.push_back(entry1); entries.push_back(entry2); @@ -121,9 +121,9 @@ void MultiDiskWriterTest::testReadData() { } void MultiDiskWriterTest::testSha1Sum() { - FileEntry entry1("file1r.txt", 15, 0); - FileEntry entry2("file2r.txt", 7, 15); - FileEntry entry3("file3r.txt", 3, 22); + FileEntryHandle entry1(new FileEntry("file1r.txt", 15, 0)); + FileEntryHandle entry2(new FileEntry("file2r.txt", 7, 15)); + FileEntryHandle entry3(new FileEntry("file3r.txt", 3, 22)); FileEntries entries; entries.push_back(entry1); entries.push_back(entry2); diff --git a/test/ShaVisitorTest.cc b/test/ShaVisitorTest.cc index 6d735c88..ae5f910d 100644 --- a/test/ShaVisitorTest.cc +++ b/test/ShaVisitorTest.cc @@ -55,6 +55,6 @@ void ShaVisitorTest::testVisitCompound() { int len = 0; v.getHash(md, len); string hashHex = hexHash(md, len); - CPPUNIT_ASSERT_EQUAL(string("0815f9b8137fbca179c8f560e20849174e9ede8b"), + CPPUNIT_ASSERT_EQUAL(string("36a58c6ab3eb02caa952f4345f57fabb06a39511"), hashHex); } diff --git a/test/ShareRatioSeedCriteriaTest.cc b/test/ShareRatioSeedCriteriaTest.cc index f0ad36ca..88d55237 100644 --- a/test/ShareRatioSeedCriteriaTest.cc +++ b/test/ShareRatioSeedCriteriaTest.cc @@ -1,5 +1,6 @@ #include "ShareRatioSeedCriteria.h" - +#include "MockBtContext.h" +#include "MockPeerStorage.h" #include class ShareRatioSeedCriteriaTest:public CppUnit::TestFixture { @@ -16,16 +17,31 @@ public: CPPUNIT_TEST_SUITE_REGISTRATION(ShareRatioSeedCriteriaTest); void ShareRatioSeedCriteriaTest::testEvaluate() { - TorrentMan torrentMan; - torrentMan.setDownloadLength(4294967296LL); - torrentMan.setUploadLength(4294967296LL); + string infoHash = "01234567890123456789"; + string infoHashString = Util::toHex((const unsigned char*)infoHash.c_str(), infoHash.size()); + MockBtContext* mockBtContext = new MockBtContext(); + mockBtContext->setTotalLength(1000000); + mockBtContext->setInfoHash((const unsigned char*)infoHash.c_str()); + BtContextHandle btContext(mockBtContext); + + BtRuntimeHandle btRuntime(new BtRuntime()); + btRuntime->setUploadLengthAtStartup(500000); + BtRegistry::registerBtRuntime(infoHashString, btRuntime); + + MockPeerStorage* mockPeerStorage = new MockPeerStorage(); + TransferStat stat; + stat.setSessionDownloadLength(1000000); + stat.setSessionUploadLength(500000); + mockPeerStorage->setStat(stat); + PeerStorageHandle peerStorage(mockPeerStorage); + BtRegistry::registerPeerStorage(infoHashString, peerStorage); - ShareRatioSeedCriteria cri(1.0, &torrentMan); + ShareRatioSeedCriteria cri(1.0, btContext); CPPUNIT_ASSERT(cri.evaluate()); cri.setRatio(2.0); CPPUNIT_ASSERT(!cri.evaluate()); // check div by zero - torrentMan.setDownloadLength(0); + mockBtContext->setTotalLength(0); CPPUNIT_ASSERT(!cri.evaluate()); } diff --git a/test/TrackerWatcherCommandTest.cc b/test/TrackerWatcherCommandTest.cc index 73008d9e..b71a53af 100644 --- a/test/TrackerWatcherCommandTest.cc +++ b/test/TrackerWatcherCommandTest.cc @@ -5,6 +5,11 @@ #include "prefs.h" #include "HttpInitiateConnectionCommand.h" #include "ByteArrayDiskWriter.h" +#include "DefaultBtContext.h" +#include "DefaultBtAnnounce.h" +#include "DefaultPieceStorage.h" +#include "DefaultPeerStorage.h" +#include "BtRegistry.h" #include using namespace std; @@ -28,39 +33,52 @@ CPPUNIT_TEST_SUITE_REGISTRATION( TrackerWatcherCommandTest ); void TrackerWatcherCommandTest::testCreateCommand() { try { - Option* op = new Option(); - op->put(PREF_TRACKER_MAX_TRIES, "10"); + Option* op = new Option(); + op->put(PREF_TRACKER_MAX_TRIES, "10"); + + BtContextHandle btContext(new DefaultBtContext()); + btContext->load("test.torrent"); + + BtRuntimeHandle btRuntime; + BtRegistry::registerBtRuntime(btContext->getInfoHashAsString(), btRuntime); + + PieceStorageHandle pieceStorage(new DefaultPieceStorage(btContext, op)); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage); - TorrentConsoleDownloadEngine* te = new TorrentConsoleDownloadEngine(); - te->option = op; - te->segmentMan = new SegmentMan(); - te->segmentMan->option = op; - ByteArrayDiskWriter* byteArrayDiskWriter = new ByteArrayDiskWriter(); - te->segmentMan->diskWriter = byteArrayDiskWriter; - te->torrentMan = new TorrentMan(); - te->torrentMan->option = op; - te->torrentMan->setup("test.torrent", Strings()); + PeerStorageHandle peerStorage(new DefaultPeerStorage(btContext, op)); + BtRegistry::registerPeerStorage(btContext->getInfoHashAsString(), + peerStorage); - TrackerWatcherCommand command(1, te); + BtAnnounceHandle btAnnounce(new DefaultBtAnnounce(btContext, op)); + BtRegistry::registerBtAnnounce(btContext->getInfoHashAsString(), btAnnounce); + TorrentConsoleDownloadEngine* te = new TorrentConsoleDownloadEngine(); + te->option = op; + te->segmentMan = new SegmentMan(); + te->segmentMan->option = op; + ByteArrayDiskWriter* byteArrayDiskWriter = new ByteArrayDiskWriter(); + te->segmentMan->diskWriter = byteArrayDiskWriter; - CPPUNIT_ASSERT(dynamic_cast(command.createCommand())); - cerr << te->torrentMan->getAnnounceUrl() << endl; - - te->torrentMan->announceSuccess(); - te->torrentMan->resetAnnounce(); - te->segmentMan->init(); - - te->torrentMan->setHalt(true); - - CPPUNIT_ASSERT(dynamic_cast(command.createCommand())); - cerr << te->torrentMan->getAnnounceUrl() << endl; - - te->torrentMan->announceSuccess(); - te->torrentMan->resetAnnounce(); - te->segmentMan->init(); - - CPPUNIT_ASSERT(te->torrentMan->noMoreAnnounce()); + TrackerWatcherCommand command(1, te, btContext); + CPPUNIT_ASSERT(dynamic_cast(command.createCommand())); + //cerr << btAnnounce->getAnnounceUrl() << endl; + + btAnnounce->announceSuccess(); + btAnnounce->resetAnnounce(); + te->segmentMan->init(); + + btRuntime->setHalt(true); + + CPPUNIT_ASSERT(dynamic_cast(command.createCommand())); + //cerr << btAnnounce->getAnnounceUrl() << endl; + + btAnnounce->announceSuccess(); + btAnnounce->resetAnnounce(); + te->segmentMan->init(); + + CPPUNIT_ASSERT(btAnnounce->noMoreAnnounce()); + } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; diff --git a/test/UtilTest.cc b/test/UtilTest.cc index e05d8f2a..73fdff29 100644 --- a/test/UtilTest.cc +++ b/test/UtilTest.cc @@ -87,15 +87,24 @@ void UtilTest::testSplit() { void UtilTest::testSlice() { Strings v1; - Util::slice(v1, "name1=value1; name2=value2; name3=value3;", ';'); + Util::slice(v1, "name1=value1; name2=value2; name3=value3;", ';', true); CPPUNIT_ASSERT_EQUAL(3, (int)v1.size()); v1.clear(); - Util::slice(v1, "name1=value1; name2=value2; name3=value3", ';'); + Util::slice(v1, "name1=value1; name2=value2; name3=value3", ';', true); CPPUNIT_ASSERT_EQUAL(3, (int)v1.size()); Strings::iterator itr = v1.begin(); CPPUNIT_ASSERT_EQUAL(string("name1=value1"), *itr++); CPPUNIT_ASSERT_EQUAL(string("name2=value2"), *itr++); CPPUNIT_ASSERT_EQUAL(string("name3=value3"), *itr++); + + v1.clear(); + + Util::slice(v1, "name1=value1; name2=value2; name3=value3", ';', false); + CPPUNIT_ASSERT_EQUAL(3, (int)v1.size()); + itr = v1.begin(); + CPPUNIT_ASSERT_EQUAL(string("name1=value1"), *itr++); + CPPUNIT_ASSERT_EQUAL(string(" name2=value2"), *itr++); + CPPUNIT_ASSERT_EQUAL(string(" name3=value3"), *itr++); } void UtilTest::testEndsWith() { diff --git a/test/single.torrent b/test/single.torrent new file mode 100644 index 00000000..b9cd4b6e --- /dev/null +++ b/test/single.torrent @@ -0,0 +1 @@ +d8:announce36:http://aria.rednoah.com/announce.php7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod4:name19:aria2-0.8.2.tar.bz26:lengthi384e12:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee \ No newline at end of file