/* */ #ifndef _D_SEGMENT_MAN_H_ #define _D_SEGMENT_MAN_H_ #include "common.h" #include "Logger.h" #include "Segment.h" #include "Option.h" #include "DiskWriter.h" #include "Request.h" #include "BitfieldMan.h" #include "PeerStat.h" using namespace std; #define SEGMENT_FILE_EXTENSION ".aria2" class SegmentEntry { public: int cuid; Segment segment; public: SegmentEntry(int cuid, const Segment& segment) :cuid(cuid), segment(segment) {} ~SegmentEntry() {} }; typedef SharedHandle SegmentEntryHandle; typedef deque SegmentEntries; typedef deque PeerStats; /** * This class holds the download progress of the one download entry. */ class SegmentMan { private: const Logger* logger; BitfieldMan* bitfield; SegmentEntries usedSegmentEntries; PeerStats peerStats; void read(FILE* file); FILE* openSegFile(const string& segFilename, const string& mode) const; bool onNullBitfield(Segment& segment, int cuid); Segment checkoutSegment(int cuid, int index); SegmentEntryHandle findSlowerSegmentEntry(const PeerStatHandle& peerStat) const; SegmentEntryHandle getSegmentEntryByIndex(int index) { for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); itr != usedSegmentEntries.end(); ++itr) { const SegmentEntryHandle& segmentEntry = *itr; if(segmentEntry->segment.index == index) { return segmentEntry; } } return 0; } SegmentEntryHandle getSegmentEntryByCuid(int cuid) { for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin(); itr != usedSegmentEntries.end(); ++itr) { const SegmentEntryHandle& segmentEntry = *itr; if(segmentEntry->cuid == cuid) { return segmentEntry; } } return 0; } SegmentEntries::iterator getSegmentEntryIteratorByCuid(int cuid) { for(SegmentEntries::iterator itr = usedSegmentEntries.begin(); itr != usedSegmentEntries.end(); ++itr) { const SegmentEntryHandle& segmentEntry = *itr; if(segmentEntry->cuid == cuid) { return itr; } } return usedSegmentEntries.end(); } public: /** * The total number of bytes to download. * If Transfer-Encoding is Chunked or Content-Length header is not provided, * then this value is set to be 0. */ long long int totalSize; /** * Represents whether this download is splittable. * In Split download(or segmented download), http client establishes * more than one connections to the server, and downloads sevral parts of * a file at the same time. This boosts download speed. * This value is true by default. If total number of bytes is not known or * Chunked transfer encoding is used, then this value is set to be 0 by * DownloadCommand class. */ bool isSplittable; /** * Represents whether the download is start or not. * The default value is false. */ bool downloadStarted; /** * Respresents the file name of the downloaded file. * If the URL does not contain file name part(http://www.rednoah.com/, for * example), this value may be 0 length string. * The default value is 0 length string. */ string filename; /** * directory to store a file */ string dir; /** * User defined file name for downloaded content */ string ufilename; /** * Represents the number of failures(usually, DlAbortEx) in downloads. */ int errors; const Option* option; DiskWriterHandle diskWriter; Requests reserved; #ifdef ENABLE_MESSAGE_DIGEST Strings pieceHashes; int32_t chunkHashLength; MessageDigestContext::DigestAlgo digestAlgo; #endif // ENABLE_MESSAGE_DIGEST SegmentMan(); ~SegmentMan(); // Initializes totalSize, isSplittable, downloadStarted, errors. // Clears command queue. Also, closes diskWriter. void init(); /** * Returns dir+"/"+filename. * If filename is empty, then returns dir+"/"+"inex.html"; */ string getFilePath() const { return (dir == "" ? "." : dir)+"/"+ (ufilename == "" ? (filename == "" ? "index.html" : filename) : ufilename); } string getSegmentFilePath() const { return getFilePath()+SEGMENT_FILE_EXTENSION; } /** * Returns true only if the segment data file exists. * The file name of the segment data is filename appended by ".aria2". * If isSplittable is false, then returns simply false without any operation. */ bool segmentFileExists() const; /** * Loads the segment data file. * If isSplittable is false, then returns without any operation. */ void load(); /** * Saves the segment data file. * If isSplittable is false, then returns without any operation. */ void save() const; /** * Removes the segment data file. * If isSplittable is false, then returns without any operation. */ void remove() const; /** * Returs true when the download has finished. * If downloadStarted is false or the number of the segments of this object * holds is 0, then returns false. */ bool finished() const; /** * if finished() is true, then call remove() */ void removeIfFinished() const; /** * Returns a vacant segment. * If there is no vacant segment, then returns a segment instance whose * isNull call is true. */ bool getSegment(Segment& segment, int cuid); /** * Returns a segment whose index is index. * If it has already assigned * to another cuid or has been downloaded, then returns a segment instance * whose isNull call is true. */ bool getSegment(Segment& segment, int cuid, int index); /** * Updates download status. */ bool updateSegment(int cuid, const Segment& segment); /** * Cancels all the segment which the command having given cuid * uses. */ void cancelSegment(int cuid); /** * Tells SegmentMan that the segment has been downloaded successfully. */ bool completeSegment(int cuid, const Segment& segment); /** * Initializes bitfield with the provided length parameters. */ void initBitfield(int segmentLength, long long int totalLength); /** * Returns true if the segment whose index is index has been downloaded. */ bool hasSegment(int index) const; /** * Returns the length of bytes downloaded. */ long long int getDownloadLength() const; /** * Registers given peerStat if it has not been registerd. * Otherwise does nothing. */ void registerPeerStat(const PeerStatHandle& peerStat); /** * Returns peerStat whose cuid is given cuid. If it is not found, returns * 0. */ PeerStatHandle getPeerStat(int cuid) const { for(PeerStats::const_iterator itr = peerStats.begin(); itr != peerStats.end(); ++itr) { const PeerStatHandle& peerStat = *itr; if(peerStat->getCuid() == cuid) { return peerStat; } } return 0; } /** * Returns current download speed in bytes per sec. */ int32_t calculateDownloadSpeed() const; bool fileExists(); bool shouldCancelDownloadForSafety(); void markAllPiecesDone(); #ifdef ENABLE_MESSAGE_DIGEST void checkIntegrity(); void tryChunkChecksumValidation(const Segment& segment); bool isChunkChecksumValidationReady() const; #endif // ENABLE_MESSAGE_DIGEST }; #endif // _D_SEGMENT_MAN_H_