File indexing completed on 2025-02-16 04:37:32

0001 /*
0002     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #ifndef BTCHUNKDOWNLOAD_H
0007 #define BTCHUNKDOWNLOAD_H
0008 
0009 #include <QList>
0010 #include <QObject>
0011 #include <QSet>
0012 #include <diskio/piecedata.h>
0013 #include <interfaces/chunkdownloadinterface.h>
0014 #include <util/bitset.h>
0015 #include <util/ptrmap.h>
0016 #include <util/sha1hashgen.h>
0017 #include <util/timer.h>
0018 
0019 namespace bt
0020 {
0021 class File;
0022 class Chunk;
0023 class Piece;
0024 class Peer;
0025 class Request;
0026 class PieceDownloader;
0027 
0028 struct ChunkDownloadHeader {
0029     Uint32 index;
0030     Uint32 num_bits;
0031     Uint32 buffered;
0032 };
0033 
0034 struct PieceHeader {
0035     Uint32 piece;
0036     Uint32 size;
0037     Uint32 mapped;
0038 };
0039 
0040 class DownloadStatus
0041 {
0042 public:
0043     DownloadStatus();
0044     ~DownloadStatus();
0045 
0046     void add(Uint32 p);
0047     void remove(Uint32 p);
0048     bool contains(Uint32 p);
0049     void clear();
0050 
0051     void timeout()
0052     {
0053         timeouts++;
0054     }
0055     Uint32 numTimeouts() const
0056     {
0057         return timeouts;
0058     }
0059 
0060     typedef QSet<Uint32>::iterator iterator;
0061     iterator begin()
0062     {
0063         return status.begin();
0064     }
0065     iterator end()
0066     {
0067         return status.end();
0068     }
0069 
0070 private:
0071     Uint32 timeouts;
0072     QSet<Uint32> status;
0073 };
0074 
0075 /**
0076  * @author Joris Guisson
0077  * @brief Handles the download off one Chunk off a Peer
0078  *
0079  * This class handles the download of one Chunk.
0080  */
0081 class KTORRENT_EXPORT ChunkDownload : public QObject, public ChunkDownloadInterface
0082 {
0083 public:
0084     /**
0085      * Constructor, set the chunk and the PeerManager.
0086      * @param chunk The Chunk
0087      */
0088     ChunkDownload(Chunk *chunk);
0089 
0090     ~ChunkDownload() override;
0091 
0092     /// Get the chunk
0093     Chunk *getChunk()
0094     {
0095         return chunk;
0096     }
0097 
0098     /// Get the total number of pieces
0099     Uint32 getTotalPieces() const
0100     {
0101         return num;
0102     }
0103 
0104     /// Get the number of pieces downloaded
0105     Uint32 getPiecesDownloaded() const
0106     {
0107         return num_downloaded;
0108     }
0109 
0110     /// Get the number of bytes downloaded.
0111     Uint32 bytesDownloaded() const;
0112 
0113     /// Get the index of the chunk
0114     Uint32 getChunkIndex() const;
0115 
0116     /// Get the PeerID of the current peer
0117     QString getPieceDownloaderName() const;
0118 
0119     /// Get the download speed
0120     Uint32 getDownloadSpeed() const;
0121 
0122     /// Get download stats
0123     void getStats(Stats &s) override;
0124 
0125     /// See if a chunkdownload is idle (i.e. has no downloaders)
0126     bool isIdle() const
0127     {
0128         return pdown.count() == 0;
0129     }
0130 
0131     /**
0132      * A Piece has arived.
0133      * @param p The Piece
0134      * @param ok Whether or not the piece was needed
0135      * @return true If Chunk is complete
0136      */
0137     bool piece(const Piece &p, bool &ok);
0138 
0139     /**
0140      * Assign the downloader to download from.
0141      * @param pd The downloader
0142      * @return true if the peer was asigned, false if not
0143      */
0144     bool assign(PieceDownloader *pd);
0145 
0146     /**
0147      * Release a downloader
0148      * @param pd The downloader
0149      */
0150     void release(PieceDownloader *pd);
0151 
0152     /**
0153      * A PieceDownloader has been killed. We need to remove it.
0154      * @param pd The PieceDownloader
0155      */
0156     void killed(PieceDownloader *pd);
0157 
0158     /**
0159      * Save to a File
0160      * @param file The File
0161      */
0162     void save(File &file);
0163 
0164     /**
0165      * Load from a File
0166      * @param file The File
0167      * @param hdr Header for the chunk
0168      * @param update_hash Whether or not to update the hash
0169      */
0170     bool load(File &file, ChunkDownloadHeader &hdr, bool update_hash = true);
0171 
0172     /**
0173      * Cancel all requests.
0174      */
0175     void cancelAll();
0176 
0177     /**
0178      * When a Chunk is downloaded, this function checks if all
0179      * pieces are delivered by the same peer and if so returns it.
0180      * @return The PieceDownloader or 0 if there is no only peer
0181      */
0182     PieceDownloader *getOnlyDownloader();
0183 
0184     /// See if a PieceDownloader is assigned to this chunk
0185     bool containsPeer(PieceDownloader *pd)
0186     {
0187         return pdown.contains(pd);
0188     }
0189 
0190     /// See if the download is choked (i.e. all downloaders are choked)
0191     bool isChoked() const;
0192 
0193     /// Release all PD's and clear the requested chunks
0194     void releaseAllPDs();
0195 
0196     /// Send requests to peers
0197     void update();
0198 
0199     /// See if this CD hasn't been active in the last update
0200     bool needsToBeUpdated() const
0201     {
0202         return timer.getElapsedSinceUpdate() > 60 * 1000;
0203     }
0204 
0205     /// Get the SHA1 hash of the downloaded chunk
0206     SHA1Hash getHash() const
0207     {
0208         return hash_gen.get();
0209     }
0210 
0211     /// Get the number of downloaders
0212     Uint32 getNumDownloaders() const
0213     {
0214         return pdown.count();
0215     }
0216 
0217 private:
0218     void onTimeout(const bt::Request &r);
0219     void onRejected(const bt::Request &r);
0220 
0221     void notDownloaded(const Request &r, bool reject);
0222     void updateHash();
0223     void sendRequests();
0224     bool sendRequest(PieceDownloader *pd);
0225     void sendCancels(PieceDownloader *pd);
0226     void endgameCancel(const Piece &p);
0227     Uint32 bestPiece(PieceDownloader *pd);
0228 
0229     BitSet pieces;
0230     Chunk *chunk;
0231     Uint32 num;
0232     Uint32 num_downloaded;
0233     Uint32 last_size;
0234     Timer timer;
0235     QList<PieceDownloader *> pdown;
0236     PtrMap<PieceDownloader *, DownloadStatus> dstatus;
0237     QSet<PieceDownloader *> piece_providers;
0238     PieceData::Ptr *piece_data;
0239     SHA1HashGen hash_gen;
0240     Uint32 num_pieces_in_hash;
0241 
0242     friend File &operator<<(File &out, const ChunkDownload &cd);
0243     friend File &operator>>(File &in, ChunkDownload &cd);
0244 };
0245 }
0246 
0247 #endif