1 /* 2 SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 #ifndef BTCHUNKDOWNLOAD_H 7 #define BTCHUNKDOWNLOAD_H 8 9 #include <QList> 10 #include <QObject> 11 #include <QSet> 12 #include <diskio/piecedata.h> 13 #include <interfaces/chunkdownloadinterface.h> 14 #include <util/bitset.h> 15 #include <util/ptrmap.h> 16 #include <util/sha1hashgen.h> 17 #include <util/timer.h> 18 19 namespace bt 20 { 21 class File; 22 class Chunk; 23 class Piece; 24 class Peer; 25 class Request; 26 class PieceDownloader; 27 28 struct ChunkDownloadHeader { 29 Uint32 index; 30 Uint32 num_bits; 31 Uint32 buffered; 32 }; 33 34 struct PieceHeader { 35 Uint32 piece; 36 Uint32 size; 37 Uint32 mapped; 38 }; 39 40 class DownloadStatus 41 { 42 public: 43 DownloadStatus(); 44 ~DownloadStatus(); 45 46 void add(Uint32 p); 47 void remove(Uint32 p); 48 bool contains(Uint32 p); 49 void clear(); 50 timeout()51 void timeout() 52 { 53 timeouts++; 54 } numTimeouts()55 Uint32 numTimeouts() const 56 { 57 return timeouts; 58 } 59 60 typedef QSet<Uint32>::iterator iterator; begin()61 iterator begin() 62 { 63 return status.begin(); 64 } end()65 iterator end() 66 { 67 return status.end(); 68 } 69 70 private: 71 Uint32 timeouts; 72 QSet<Uint32> status; 73 }; 74 75 /** 76 * @author Joris Guisson 77 * @brief Handles the download off one Chunk off a Peer 78 * 79 * This class handles the download of one Chunk. 80 */ 81 class KTORRENT_EXPORT ChunkDownload : public QObject, public ChunkDownloadInterface 82 { 83 public: 84 /** 85 * Constructor, set the chunk and the PeerManager. 86 * @param chunk The Chunk 87 */ 88 ChunkDownload(Chunk *chunk); 89 90 ~ChunkDownload() override; 91 92 /// Get the chunk getChunk()93 Chunk *getChunk() 94 { 95 return chunk; 96 } 97 98 /// Get the total number of pieces getTotalPieces()99 Uint32 getTotalPieces() const 100 { 101 return num; 102 } 103 104 /// Get the number of pieces downloaded getPiecesDownloaded()105 Uint32 getPiecesDownloaded() const 106 { 107 return num_downloaded; 108 } 109 110 /// Get the number of bytes downloaded. 111 Uint32 bytesDownloaded() const; 112 113 /// Get the index of the chunk 114 Uint32 getChunkIndex() const; 115 116 /// Get the PeerID of the current peer 117 QString getPieceDownloaderName() const; 118 119 /// Get the download speed 120 Uint32 getDownloadSpeed() const; 121 122 /// Get download stats 123 void getStats(Stats &s) override; 124 125 /// See if a chunkdownload is idle (i.e. has no downloaders) isIdle()126 bool isIdle() const 127 { 128 return pdown.count() == 0; 129 } 130 131 /** 132 * A Piece has arived. 133 * @param p The Piece 134 * @param ok Whether or not the piece was needed 135 * @return true If Chunk is complete 136 */ 137 bool piece(const Piece &p, bool &ok); 138 139 /** 140 * Assign the downloader to download from. 141 * @param pd The downloader 142 * @return true if the peer was asigned, false if not 143 */ 144 bool assign(PieceDownloader *pd); 145 146 /** 147 * Release a downloader 148 * @param pd The downloader 149 */ 150 void release(PieceDownloader *pd); 151 152 /** 153 * A PieceDownloader has been killed. We need to remove it. 154 * @param pd The PieceDownloader 155 */ 156 void killed(PieceDownloader *pd); 157 158 /** 159 * Save to a File 160 * @param file The File 161 */ 162 void save(File &file); 163 164 /** 165 * Load from a File 166 * @param file The File 167 * @param hdr Header for the chunk 168 * @param update_hash Whether or not to update the hash 169 */ 170 bool load(File &file, ChunkDownloadHeader &hdr, bool update_hash = true); 171 172 /** 173 * Cancel all requests. 174 */ 175 void cancelAll(); 176 177 /** 178 * When a Chunk is downloaded, this function checks if all 179 * pieces are delivered by the same peer and if so returns it. 180 * @return The PieceDownloader or 0 if there is no only peer 181 */ 182 PieceDownloader *getOnlyDownloader(); 183 184 /// See if a PieceDownloader is assigned to this chunk containsPeer(PieceDownloader * pd)185 bool containsPeer(PieceDownloader *pd) 186 { 187 return pdown.contains(pd); 188 } 189 190 /// See if the download is choked (i.e. all downloaders are choked) 191 bool isChoked() const; 192 193 /// Release all PD's and clear the requested chunks 194 void releaseAllPDs(); 195 196 /// Send requests to peers 197 void update(); 198 199 /// See if this CD hasn't been active in the last update needsToBeUpdated()200 bool needsToBeUpdated() const 201 { 202 return timer.getElapsedSinceUpdate() > 60 * 1000; 203 } 204 205 /// Get the SHA1 hash of the downloaded chunk getHash()206 SHA1Hash getHash() const 207 { 208 return hash_gen.get(); 209 } 210 211 /// Get the number of downloaders getNumDownloaders()212 Uint32 getNumDownloaders() const 213 { 214 return pdown.count(); 215 } 216 217 private: 218 void onTimeout(const bt::Request &r); 219 void onRejected(const bt::Request &r); 220 221 void notDownloaded(const Request &r, bool reject); 222 void updateHash(); 223 void sendRequests(); 224 bool sendRequest(PieceDownloader *pd); 225 void sendCancels(PieceDownloader *pd); 226 void endgameCancel(const Piece &p); 227 Uint32 bestPiece(PieceDownloader *pd); 228 229 BitSet pieces; 230 Chunk *chunk; 231 Uint32 num; 232 Uint32 num_downloaded; 233 Uint32 last_size; 234 Timer timer; 235 QList<PieceDownloader *> pdown; 236 PtrMap<PieceDownloader *, DownloadStatus> dstatus; 237 QSet<PieceDownloader *> piece_providers; 238 PieceData::Ptr *piece_data; 239 SHA1HashGen hash_gen; 240 Uint32 num_pieces_in_hash; 241 242 friend File &operator<<(File &out, const ChunkDownload &cd); 243 friend File &operator>>(File &in, ChunkDownload &cd); 244 }; 245 } 246 247 #endif 248