File indexing completed on 2025-01-05 04:37:22
0001 /* 0002 SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "peerdownloader.h" 0007 0008 #include "peer.h" 0009 #include <download/piece.h> 0010 #include <math.h> 0011 #include <util/functions.h> 0012 #include <util/log.h> 0013 0014 namespace bt 0015 { 0016 TimeStampedRequest::TimeStampedRequest() 0017 { 0018 time_stamp = bt::CurrentTime(); 0019 } 0020 0021 TimeStampedRequest::TimeStampedRequest(const Request &r) 0022 : req(r) 0023 { 0024 time_stamp = bt::CurrentTime(); 0025 } 0026 0027 TimeStampedRequest::TimeStampedRequest(const TimeStampedRequest &t) 0028 : req(t.req) 0029 , time_stamp(t.time_stamp) 0030 { 0031 } 0032 0033 TimeStampedRequest::~TimeStampedRequest() 0034 { 0035 } 0036 0037 bool TimeStampedRequest::operator==(const Request &r) const 0038 { 0039 return r == req; 0040 } 0041 0042 bool TimeStampedRequest::operator==(const TimeStampedRequest &r) const 0043 { 0044 return r.req == req; 0045 } 0046 0047 TimeStampedRequest &TimeStampedRequest::operator=(const Request &r) 0048 { 0049 time_stamp = bt::CurrentTime(); 0050 req = r; 0051 return *this; 0052 } 0053 0054 TimeStampedRequest &TimeStampedRequest::operator=(const TimeStampedRequest &r) 0055 { 0056 time_stamp = r.time_stamp; 0057 req = r.req; 0058 return *this; 0059 } 0060 0061 PeerDownloader::PeerDownloader(Peer *peer, Uint32 chunk_size) 0062 : peer(peer) 0063 , chunk_size(chunk_size / MAX_PIECE_LEN) 0064 { 0065 connect(peer, &Peer::destroyed, this, &PeerDownloader::peerDestroyed); 0066 max_wait_queue_size = 25; 0067 } 0068 0069 PeerDownloader::~PeerDownloader() 0070 { 0071 } 0072 0073 QString PeerDownloader::getName() const 0074 { 0075 return peer->getPeerID().identifyClient(); 0076 } 0077 0078 bool PeerDownloader::canAddRequest() const 0079 { 0080 return (Uint32)wait_queue.count() < max_wait_queue_size; 0081 } 0082 0083 bool PeerDownloader::canDownloadChunk() const 0084 { 0085 return !isNull() && (getNumGrabbed() < (int)getMaxChunkDownloads() || isNearlyDone()) && canAddRequest(); 0086 } 0087 0088 Uint32 PeerDownloader::getNumRequests() const 0089 { 0090 return reqs.count() /*+ wait_queue.count() */; 0091 } 0092 0093 void PeerDownloader::download(const Request &req) 0094 { 0095 if (!peer) 0096 return; 0097 0098 wait_queue.append(req); 0099 update(); 0100 } 0101 0102 void PeerDownloader::cancel(const Request &req) 0103 { 0104 if (!peer) 0105 return; 0106 0107 if (!wait_queue.removeAll(req)) { 0108 reqs.removeAll(req); 0109 peer->sendCancel(req); 0110 } 0111 } 0112 0113 void PeerDownloader::onRejected(const Request &req) 0114 { 0115 if (!peer) 0116 return; 0117 0118 if (reqs.removeAll(req)) 0119 rejected(req); 0120 } 0121 0122 void PeerDownloader::cancelAll() 0123 { 0124 if (peer) { 0125 QList<TimeStampedRequest>::iterator i = reqs.begin(); 0126 while (i != reqs.end()) { 0127 TimeStampedRequest &tr = *i; 0128 peer->sendCancel(tr.req); 0129 ++i; 0130 } 0131 } 0132 0133 wait_queue.clear(); 0134 reqs.clear(); 0135 } 0136 0137 void PeerDownloader::piece(const Piece &p) 0138 { 0139 Request r(p); 0140 if (!reqs.removeOne(r)) 0141 wait_queue.removeAll(r); 0142 } 0143 0144 void PeerDownloader::peerDestroyed() 0145 { 0146 peer = nullptr; 0147 } 0148 0149 bool PeerDownloader::isChoked() const 0150 { 0151 if (peer) 0152 return peer->isChoked(); 0153 else 0154 return true; 0155 } 0156 0157 bool PeerDownloader::hasChunk(Uint32 idx) const 0158 { 0159 if (peer) 0160 return peer->getBitSet().get(idx); 0161 else 0162 return false; 0163 } 0164 0165 Uint32 PeerDownloader::getDownloadRate() const 0166 { 0167 if (peer) 0168 return peer->getDownloadRate(); 0169 else 0170 return 0; 0171 } 0172 0173 void PeerDownloader::checkTimeouts() 0174 { 0175 TimeStamp now = bt::CurrentTime(); 0176 // we use a 60 second interval 0177 const Uint32 MAX_INTERVAL = 60 * 1000; 0178 0179 // expire any timed-out requests: the list is sorted with the 0180 // oldest requests at the front, so we simply pop off requests 0181 // until we find one that shouldn't be expired 0182 while (!reqs.isEmpty() && (now - reqs.first().time_stamp > MAX_INTERVAL)) 0183 timedout(reqs.takeFirst().req); 0184 } 0185 0186 Uint32 PeerDownloader::getMaxChunkDownloads() const 0187 { 0188 // get the download rate in KB/sec 0189 Uint32 rate_kbs = peer->getDownloadRate(); 0190 rate_kbs = rate_kbs / 1024; 0191 Uint32 num_extra = rate_kbs / 25; 0192 0193 if (chunk_size >= 16) { 0194 return 1 + 16 * num_extra / chunk_size; 0195 } else { 0196 return 1 + (16 / chunk_size) * num_extra; 0197 } 0198 } 0199 0200 void PeerDownloader::choked() 0201 { 0202 // when the peers supports the fast extensions, choke does not mean that all 0203 // requests are rejected, so lets do nothing 0204 if (peer->getStats().fast_extensions) 0205 return; 0206 0207 QList<TimeStampedRequest>::iterator i = reqs.begin(); 0208 while (i != reqs.end()) { 0209 TimeStampedRequest &tr = *i; 0210 rejected(tr.req); 0211 ++i; 0212 } 0213 reqs.clear(); 0214 0215 QList<Request>::iterator j = wait_queue.begin(); 0216 while (j != wait_queue.end()) { 0217 Request &req = *j; 0218 rejected(req); 0219 ++j; 0220 } 0221 wait_queue.clear(); 0222 } 0223 0224 void PeerDownloader::update() 0225 { 0226 // modify the interval if necessary 0227 double pieces_per_sec = (double)peer->getDownloadRate() / MAX_PIECE_LEN; 0228 int max_reqs = 1 + (int)ceil(10 * pieces_per_sec); 0229 // cap if client has supplied a reqq in extended protocol handshake 0230 if (max_reqs > (int)peer->getStats().max_request_queue && peer->getStats().max_request_queue != 0) 0231 max_reqs = peer->getStats().max_request_queue; 0232 0233 while (wait_queue.count() > 0 && reqs.count() < max_reqs) { 0234 // get a request from the wait queue and send that 0235 Request req = wait_queue.front(); 0236 wait_queue.pop_front(); 0237 TimeStampedRequest r = TimeStampedRequest(req); 0238 reqs.append(r); 0239 peer->sendRequest(req); 0240 } 0241 0242 max_wait_queue_size = 2 * max_reqs; 0243 if (max_wait_queue_size < 10) 0244 max_wait_queue_size = 10; 0245 } 0246 } 0247 0248 #include "moc_peerdownloader.cpp"