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