1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the examples of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include "peerwireclient.h" |
52 | |
53 | #include <QHostAddress> |
54 | #include <QTimerEvent> |
55 | |
56 | static const int PendingRequestTimeout = 60 * 1000; |
57 | static const int ClientTimeout = 120 * 1000; |
58 | static const int ConnectTimeout = 60 * 1000; |
59 | static const int KeepAliveInterval = 30 * 1000; |
60 | static const int RateControlTimerDelay = 2000; |
61 | static const int = 48; |
62 | static const char ProtocolId[] = "BitTorrent protocol" ; |
63 | static const char ProtocolIdSize = 19; |
64 | |
65 | // Reads a 32bit unsigned int from data in network order. |
66 | static inline quint32 fromNetworkData(const char *data) |
67 | { |
68 | const unsigned char *udata = (const unsigned char *)data; |
69 | return (quint32(udata[0]) << 24) |
70 | | (quint32(udata[1]) << 16) |
71 | | (quint32(udata[2]) << 8) |
72 | | (quint32(udata[3])); |
73 | } |
74 | |
75 | // Writes a 32bit unsigned int from num to data in network order. |
76 | static inline void toNetworkData(quint32 num, char *data) |
77 | { |
78 | unsigned char *udata = (unsigned char *)data; |
79 | udata[3] = (num & 0xff); |
80 | udata[2] = (num & 0xff00) >> 8; |
81 | udata[1] = (num & 0xff0000) >> 16; |
82 | udata[0] = (num & 0xff000000) >> 24; |
83 | } |
84 | |
85 | // Constructs an unconnected PeerWire client and starts the connect timer. |
86 | PeerWireClient::PeerWireClient(const QByteArray &peerId, QObject *parent) |
87 | : QTcpSocket(parent), pendingBlockSizes(0), |
88 | pwState(ChokingPeer | ChokedByPeer), receivedHandShake(false), gotPeerId(false), |
89 | sentHandShake(false), nextPacketLength(-1), pendingRequestTimer(0), invalidateTimeout(false), |
90 | keepAliveTimer(0), torrentPeer(nullptr) |
91 | { |
92 | memset(s: uploadSpeedData, c: 0, n: sizeof(uploadSpeedData)); |
93 | memset(s: downloadSpeedData, c: 0, n: sizeof(downloadSpeedData)); |
94 | |
95 | transferSpeedTimer = startTimer(interval: RateControlTimerDelay); |
96 | timeoutTimer = startTimer(interval: ConnectTimeout); |
97 | peerIdString = peerId; |
98 | |
99 | connect(sender: this, signal: &PeerWireClient::readyRead, |
100 | receiver: this, slot: &PeerWireClient::readyToTransfer); |
101 | connect(sender: this, signal: &PeerWireClient::connected, |
102 | receiver: this, slot: &PeerWireClient::readyToTransfer); |
103 | |
104 | connect(sender: &socket, signal: &QTcpSocket::connected, |
105 | receiver: this, slot: &PeerWireClient::connected); |
106 | connect(sender: &socket, signal: &QTcpSocket::readyRead, |
107 | receiver: this, slot: &PeerWireClient::readyRead); |
108 | connect(sender: &socket, signal: &QTcpSocket::disconnected, |
109 | receiver: this, slot: &PeerWireClient::disconnected); |
110 | connect(sender: &socket, signal: &QTcpSocket::errorOccurred, |
111 | receiver: this, slot: &PeerWireClient::errorOccurred); |
112 | connect(sender: &socket, signal: &QTcpSocket::bytesWritten, |
113 | receiver: this, slot: &PeerWireClient::bytesWritten); |
114 | connect(sender: &socket, signal: &QTcpSocket::stateChanged, |
115 | receiver: this, slot: &PeerWireClient::socketStateChanged); |
116 | |
117 | } |
118 | |
119 | // Registers the peer ID and SHA1 sum of the torrent, and initiates |
120 | // the handshake. |
121 | void PeerWireClient::initialize(const QByteArray &infoHash, int pieceCount) |
122 | { |
123 | this->infoHash = infoHash; |
124 | peerPieces.resize(size: pieceCount); |
125 | if (!sentHandShake) |
126 | sendHandShake(); |
127 | } |
128 | |
129 | void PeerWireClient::setPeer(TorrentPeer *peer) |
130 | { |
131 | torrentPeer = peer; |
132 | } |
133 | |
134 | TorrentPeer *PeerWireClient::peer() const |
135 | { |
136 | return torrentPeer; |
137 | } |
138 | |
139 | QBitArray PeerWireClient::availablePieces() const |
140 | { |
141 | return peerPieces; |
142 | } |
143 | |
144 | QList<TorrentBlock> PeerWireClient::incomingBlocks() const |
145 | { |
146 | return incoming; |
147 | } |
148 | |
149 | // Sends a "choke" message, asking the peer to stop requesting blocks. |
150 | void PeerWireClient::chokePeer() |
151 | { |
152 | const char message[] = {0, 0, 0, 1, 0}; |
153 | write(data: message, len: sizeof(message)); |
154 | pwState |= ChokingPeer; |
155 | |
156 | // After receiving a choke message, the peer will assume all |
157 | // pending requests are lost. |
158 | pendingBlocks.clear(); |
159 | pendingBlockSizes = 0; |
160 | } |
161 | |
162 | // Sends an "unchoke" message, allowing the peer to start/resume |
163 | // requesting blocks. |
164 | void PeerWireClient::unchokePeer() |
165 | { |
166 | const char message[] = {0, 0, 0, 1, 1}; |
167 | write(data: message, len: sizeof(message)); |
168 | pwState &= ~ChokingPeer; |
169 | |
170 | if (pendingRequestTimer) |
171 | killTimer(id: pendingRequestTimer); |
172 | } |
173 | |
174 | // Sends a "keep-alive" message to prevent the peer from closing |
175 | // the connection when there's no activity |
176 | void PeerWireClient::sendKeepAlive() |
177 | { |
178 | const char message[] = {0, 0, 0, 0}; |
179 | write(data: message, len: sizeof(message)); |
180 | } |
181 | |
182 | // Sends an "interested" message, informing the peer that it has got |
183 | // pieces that we'd like to download. |
184 | void PeerWireClient::sendInterested() |
185 | { |
186 | const char message[] = {0, 0, 0, 1, 2}; |
187 | write(data: message, len: sizeof(message)); |
188 | pwState |= InterestedInPeer; |
189 | |
190 | // After telling the peer that we're interested, we expect to get |
191 | // unchoked within a certain timeframe; otherwise we'll drop the |
192 | // connection. |
193 | if (pendingRequestTimer) |
194 | killTimer(id: pendingRequestTimer); |
195 | pendingRequestTimer = startTimer(interval: PendingRequestTimeout); |
196 | } |
197 | |
198 | // Sends a "not interested" message, informing the peer that it does |
199 | // not have any pieces that we'd like to download. |
200 | void PeerWireClient::sendNotInterested() |
201 | { |
202 | const char message[] = {0, 0, 0, 1, 3}; |
203 | write(data: message, len: sizeof(message)); |
204 | pwState &= ~InterestedInPeer; |
205 | } |
206 | |
207 | // Sends a piece notification / a "have" message, informing the peer |
208 | // that we have just downloaded a new piece. |
209 | void PeerWireClient::sendPieceNotification(int piece) |
210 | { |
211 | if (!sentHandShake) |
212 | sendHandShake(); |
213 | |
214 | char message[] = {0, 0, 0, 5, 4, 0, 0, 0, 0}; |
215 | toNetworkData(num: piece, data: &message[5]); |
216 | write(data: message, len: sizeof(message)); |
217 | } |
218 | |
219 | // Sends the complete list of pieces that we have downloaded. |
220 | void PeerWireClient::sendPieceList(const QBitArray &bitField) |
221 | { |
222 | // The bitfield message may only be sent immediately after the |
223 | // handshaking sequence is completed, and before any other |
224 | // messages are sent. |
225 | if (!sentHandShake) |
226 | sendHandShake(); |
227 | |
228 | // Don't send the bitfield if it's all zeros. |
229 | if (bitField.count(on: true) == 0) |
230 | return; |
231 | |
232 | int bitFieldSize = bitField.size(); |
233 | int size = (bitFieldSize + 7) / 8; |
234 | QByteArray bits(size, '\0'); |
235 | for (int i = 0; i < bitFieldSize; ++i) { |
236 | if (bitField.testBit(i)) { |
237 | quint32 byte = quint32(i) / 8; |
238 | quint32 bit = quint32(i) % 8; |
239 | bits[byte] = uchar(bits.at(i: byte)) | (1 << (7 - bit)); |
240 | } |
241 | } |
242 | |
243 | char message[] = {0, 0, 0, 1, 5}; |
244 | toNetworkData(num: bits.size() + 1, data: &message[0]); |
245 | write(data: message, len: sizeof(message)); |
246 | write(data: bits); |
247 | } |
248 | |
249 | // Sends a request for a block. |
250 | void PeerWireClient::requestBlock(int piece, int offset, int length) |
251 | { |
252 | char message[] = {0, 0, 0, 1, 6}; |
253 | toNetworkData(num: 13, data: &message[0]); |
254 | write(data: message, len: sizeof(message)); |
255 | |
256 | char numbers[4 * 3]; |
257 | toNetworkData(num: piece, data: &numbers[0]); |
258 | toNetworkData(num: offset, data: &numbers[4]); |
259 | toNetworkData(num: length, data: &numbers[8]); |
260 | write(data: numbers, len: sizeof(numbers)); |
261 | |
262 | incoming << TorrentBlock(piece, offset, length); |
263 | |
264 | // After requesting a block, we expect the block to be sent by the |
265 | // other peer within a certain number of seconds. Otherwise, we |
266 | // drop the connection. |
267 | if (pendingRequestTimer) |
268 | killTimer(id: pendingRequestTimer); |
269 | pendingRequestTimer = startTimer(interval: PendingRequestTimeout); |
270 | } |
271 | |
272 | // Cancels a request for a block. |
273 | void PeerWireClient::cancelRequest(int piece, int offset, int length) |
274 | { |
275 | char message[] = {0, 0, 0, 1, 8}; |
276 | toNetworkData(num: 13, data: &message[0]); |
277 | write(data: message, len: sizeof(message)); |
278 | |
279 | char numbers[4 * 3]; |
280 | toNetworkData(num: piece, data: &numbers[0]); |
281 | toNetworkData(num: offset, data: &numbers[4]); |
282 | toNetworkData(num: length, data: &numbers[8]); |
283 | write(data: numbers, len: sizeof(numbers)); |
284 | |
285 | incoming.removeAll(t: TorrentBlock(piece, offset, length)); |
286 | } |
287 | |
288 | // Sends a block to the peer. |
289 | void PeerWireClient::sendBlock(int piece, int offset, const QByteArray &data) |
290 | { |
291 | QByteArray block; |
292 | |
293 | char message[] = {0, 0, 0, 1, 7}; |
294 | toNetworkData(num: 9 + data.size(), data: &message[0]); |
295 | block += QByteArray(message, sizeof(message)); |
296 | |
297 | char numbers[4 * 2]; |
298 | toNetworkData(num: piece, data: &numbers[0]); |
299 | toNetworkData(num: offset, data: &numbers[4]); |
300 | block += QByteArray(numbers, sizeof(numbers)); |
301 | block += data; |
302 | |
303 | BlockInfo blockInfo; |
304 | blockInfo.pieceIndex = piece; |
305 | blockInfo.offset = offset; |
306 | blockInfo.length = data.size(); |
307 | blockInfo.block = block; |
308 | |
309 | pendingBlocks << blockInfo; |
310 | pendingBlockSizes += block.size(); |
311 | |
312 | if (pendingBlockSizes > 32 * 16384) { |
313 | chokePeer(); |
314 | unchokePeer(); |
315 | return; |
316 | } |
317 | emit readyToTransfer(); |
318 | } |
319 | |
320 | // Attempts to write 'bytes' bytes to the socket from the buffer. |
321 | // This is used by RateController, which precisely controls how much |
322 | // each client can write. |
323 | qint64 PeerWireClient::writeToSocket(qint64 bytes) |
324 | { |
325 | qint64 totalWritten = 0; |
326 | do { |
327 | if (outgoingBuffer.isEmpty() && !pendingBlocks.isEmpty()) { |
328 | BlockInfo block = pendingBlocks.takeFirst(); |
329 | pendingBlockSizes -= block.length; |
330 | outgoingBuffer += block.block; |
331 | } |
332 | qint64 written = socket.write(data: outgoingBuffer.constData(), |
333 | len: qMin<qint64>(a: bytes - totalWritten, b: outgoingBuffer.size())); |
334 | if (written <= 0) |
335 | return totalWritten ? totalWritten : written; |
336 | |
337 | totalWritten += written; |
338 | uploadSpeedData[0] += written; |
339 | outgoingBuffer.remove(index: 0, len: written); |
340 | } while (totalWritten < bytes && (!outgoingBuffer.isEmpty() || !pendingBlocks.isEmpty())); |
341 | |
342 | return totalWritten; |
343 | } |
344 | |
345 | // Attempts to read at most 'bytes' bytes from the socket. |
346 | qint64 PeerWireClient::readFromSocket(qint64 bytes) |
347 | { |
348 | char buffer[1024]; |
349 | qint64 totalRead = 0; |
350 | do { |
351 | qint64 bytesRead = socket.read(data: buffer, maxlen: qMin<qint64>(a: sizeof(buffer), b: bytes - totalRead)); |
352 | if (bytesRead <= 0) |
353 | break; |
354 | qint64 oldSize = incomingBuffer.size(); |
355 | incomingBuffer.resize(size: oldSize + bytesRead); |
356 | memcpy(dest: incomingBuffer.data() + oldSize, src: buffer, n: bytesRead); |
357 | |
358 | totalRead += bytesRead; |
359 | } while (totalRead < bytes); |
360 | |
361 | if (totalRead > 0) { |
362 | downloadSpeedData[0] += totalRead; |
363 | emit bytesReceived(size: totalRead); |
364 | processIncomingData(); |
365 | } |
366 | return totalRead; |
367 | } |
368 | |
369 | // Returns the average number of bytes per second this client is |
370 | // downloading. |
371 | qint64 PeerWireClient::downloadSpeed() const |
372 | { |
373 | qint64 sum = 0; |
374 | for (unsigned int i = 0; i < sizeof(downloadSpeedData) / sizeof(qint64); ++i) |
375 | sum += downloadSpeedData[i]; |
376 | return sum / (8 * 2); |
377 | } |
378 | |
379 | // Returns the average number of bytes per second this client is |
380 | // uploading. |
381 | qint64 PeerWireClient::uploadSpeed() const |
382 | { |
383 | qint64 sum = 0; |
384 | for (unsigned int i = 0; i < sizeof(uploadSpeedData) / sizeof(qint64); ++i) |
385 | sum += uploadSpeedData[i]; |
386 | return sum / (8 * 2); |
387 | } |
388 | |
389 | void PeerWireClient::setReadBufferSize(qint64 size) |
390 | { |
391 | socket.setReadBufferSize(size); |
392 | } |
393 | |
394 | bool PeerWireClient::canTransferMore() const |
395 | { |
396 | return bytesAvailable() > 0 || socket.bytesAvailable() > 0 |
397 | || !outgoingBuffer.isEmpty() || !pendingBlocks.isEmpty(); |
398 | } |
399 | |
400 | void PeerWireClient::connectToHost(const QHostAddress &address, |
401 | quint16 port, OpenMode openMode) |
402 | |
403 | { |
404 | setOpenMode(openMode); |
405 | socket.connectToHost(address, port, mode: openMode); |
406 | } |
407 | |
408 | void PeerWireClient::diconnectFromHost() |
409 | { |
410 | socket.disconnectFromHost(); |
411 | } |
412 | |
413 | void PeerWireClient::timerEvent(QTimerEvent *event) |
414 | { |
415 | if (event->timerId() == transferSpeedTimer) { |
416 | // Rotate the upload / download records. |
417 | for (int i = 6; i >= 0; --i) { |
418 | uploadSpeedData[i + 1] = uploadSpeedData[i]; |
419 | downloadSpeedData[i + 1] = downloadSpeedData[i]; |
420 | } |
421 | uploadSpeedData[0] = 0; |
422 | downloadSpeedData[0] = 0; |
423 | } else if (event->timerId() == timeoutTimer) { |
424 | // Disconnect if we timed out; otherwise the timeout is |
425 | // restarted. |
426 | if (invalidateTimeout) { |
427 | invalidateTimeout = false; |
428 | } else { |
429 | abort(); |
430 | emit infoHashReceived(infoHash: QByteArray()); |
431 | } |
432 | } else if (event->timerId() == pendingRequestTimer) { |
433 | abort(); |
434 | } else if (event->timerId() == keepAliveTimer) { |
435 | sendKeepAlive(); |
436 | } |
437 | QTcpSocket::timerEvent(event); |
438 | } |
439 | |
440 | // Sends the handshake to the peer. |
441 | void PeerWireClient::sendHandShake() |
442 | { |
443 | sentHandShake = true; |
444 | |
445 | // Restart the timeout |
446 | if (timeoutTimer) |
447 | killTimer(id: timeoutTimer); |
448 | timeoutTimer = startTimer(interval: ClientTimeout); |
449 | |
450 | // Write the 68 byte PeerWire handshake. |
451 | write(data: &ProtocolIdSize, len: 1); |
452 | write(data: ProtocolId, len: ProtocolIdSize); |
453 | write(data: QByteArray(8, '\0')); |
454 | write(data: infoHash); |
455 | write(data: peerIdString); |
456 | } |
457 | |
458 | void PeerWireClient::processIncomingData() |
459 | { |
460 | invalidateTimeout = true; |
461 | if (!receivedHandShake) { |
462 | // Check that we received enough data |
463 | if (bytesAvailable() < MinimalHeaderSize) |
464 | return; |
465 | |
466 | // Sanity check the protocol ID |
467 | QByteArray id = read(maxlen: ProtocolIdSize + 1); |
468 | if (id.at(i: 0) != ProtocolIdSize || !id.mid(index: 1).startsWith(c: ProtocolId)) { |
469 | abort(); |
470 | return; |
471 | } |
472 | |
473 | // Discard 8 reserved bytes, then read the info hash and peer ID |
474 | (void) read(maxlen: 8); |
475 | |
476 | // Read infoHash |
477 | QByteArray peerInfoHash = read(maxlen: 20); |
478 | if (!infoHash.isEmpty() && peerInfoHash != infoHash) { |
479 | abort(); |
480 | return; |
481 | } |
482 | |
483 | emit infoHashReceived(infoHash: peerInfoHash); |
484 | if (infoHash.isEmpty()) { |
485 | abort(); |
486 | return; |
487 | } |
488 | |
489 | // Send handshake |
490 | if (!sentHandShake) |
491 | sendHandShake(); |
492 | receivedHandShake = true; |
493 | } |
494 | |
495 | // Handle delayed peer id arrival |
496 | if (!gotPeerId) { |
497 | if (bytesAvailable() < 20) |
498 | return; |
499 | gotPeerId = true; |
500 | if (read(maxlen: 20) == peerIdString) { |
501 | // We connected to ourself |
502 | abort(); |
503 | return; |
504 | } |
505 | } |
506 | |
507 | // Initialize keep-alive timer |
508 | if (!keepAliveTimer) |
509 | keepAliveTimer = startTimer(interval: KeepAliveInterval); |
510 | |
511 | do { |
512 | // Find the packet length |
513 | if (nextPacketLength == -1) { |
514 | if (bytesAvailable() < 4) |
515 | return; |
516 | |
517 | char tmp[4]; |
518 | read(data: tmp, maxlen: sizeof(tmp)); |
519 | nextPacketLength = fromNetworkData(data: tmp); |
520 | |
521 | if (nextPacketLength < 0 || nextPacketLength > 200000) { |
522 | // Prevent DoS |
523 | abort(); |
524 | return; |
525 | } |
526 | } |
527 | |
528 | // KeepAlive |
529 | if (nextPacketLength == 0) { |
530 | nextPacketLength = -1; |
531 | continue; |
532 | } |
533 | |
534 | // Wait with parsing until the whole packet has been received |
535 | if (bytesAvailable() < nextPacketLength) |
536 | return; |
537 | |
538 | // Read the packet |
539 | QByteArray packet = read(maxlen: nextPacketLength); |
540 | if (packet.size() != nextPacketLength) { |
541 | abort(); |
542 | return; |
543 | } |
544 | |
545 | switch (packet.at(i: 0)) { |
546 | case ChokePacket: |
547 | // We have been choked. |
548 | pwState |= ChokedByPeer; |
549 | incoming.clear(); |
550 | if (pendingRequestTimer) |
551 | killTimer(id: pendingRequestTimer); |
552 | emit choked(); |
553 | break; |
554 | case UnchokePacket: |
555 | // We have been unchoked. |
556 | pwState &= ~ChokedByPeer; |
557 | emit unchoked(); |
558 | break; |
559 | case InterestedPacket: |
560 | // The peer is interested in downloading. |
561 | pwState |= PeerIsInterested; |
562 | emit interested(); |
563 | break; |
564 | case NotInterestedPacket: |
565 | // The peer is not interested in downloading. |
566 | pwState &= ~PeerIsInterested; |
567 | emit notInterested(); |
568 | break; |
569 | case HavePacket: { |
570 | // The peer has a new piece available. |
571 | quint32 index = fromNetworkData(data: &packet.data()[1]); |
572 | if (index < quint32(peerPieces.size())) { |
573 | // Only accept indexes within the valid range. |
574 | peerPieces.setBit(int(index)); |
575 | } |
576 | emit piecesAvailable(pieces: availablePieces()); |
577 | break; |
578 | } |
579 | case BitFieldPacket: |
580 | // The peer has the following pieces available. |
581 | for (int i = 1; i < packet.size(); ++i) { |
582 | for (int bit = 0; bit < 8; ++bit) { |
583 | if (packet.at(i) & (1 << (7 - bit))) { |
584 | int bitIndex = int(((i - 1) * 8) + bit); |
585 | if (bitIndex >= 0 && bitIndex < peerPieces.size()) { |
586 | // Occasionally, broken clients claim to have |
587 | // pieces whose index is outside the valid range. |
588 | // The most common mistake is the index == size |
589 | // case. |
590 | peerPieces.setBit(bitIndex); |
591 | } |
592 | } |
593 | } |
594 | } |
595 | emit piecesAvailable(pieces: availablePieces()); |
596 | break; |
597 | case RequestPacket: { |
598 | // The peer requests a block. |
599 | quint32 index = fromNetworkData(data: &packet.data()[1]); |
600 | quint32 begin = fromNetworkData(data: &packet.data()[5]); |
601 | quint32 length = fromNetworkData(data: &packet.data()[9]); |
602 | emit blockRequested(pieceIndex: int(index), begin: int(begin), length: int(length)); |
603 | break; |
604 | } |
605 | case PiecePacket: { |
606 | int index = int(fromNetworkData(data: &packet.data()[1])); |
607 | int begin = int(fromNetworkData(data: &packet.data()[5])); |
608 | |
609 | incoming.removeAll(t: TorrentBlock(index, begin, packet.size() - 9)); |
610 | |
611 | // The peer sends a block. |
612 | emit blockReceived(pieceIndex: index, begin, data: packet.mid(index: 9)); |
613 | |
614 | // Kill the pending block timer. |
615 | if (pendingRequestTimer) { |
616 | killTimer(id: pendingRequestTimer); |
617 | pendingRequestTimer = 0; |
618 | } |
619 | break; |
620 | } |
621 | case CancelPacket: { |
622 | // The peer cancels a block request. |
623 | quint32 index = fromNetworkData(data: &packet.data()[1]); |
624 | quint32 begin = fromNetworkData(data: &packet.data()[5]); |
625 | quint32 length = fromNetworkData(data: &packet.data()[9]); |
626 | for (int i = 0; i < pendingBlocks.size(); ++i) { |
627 | const BlockInfo &blockInfo = pendingBlocks.at(i); |
628 | if (blockInfo.pieceIndex == int(index) |
629 | && blockInfo.offset == int(begin) |
630 | && blockInfo.length == int(length)) { |
631 | pendingBlocks.removeAt(i); |
632 | break; |
633 | } |
634 | } |
635 | break; |
636 | } |
637 | default: |
638 | // Unsupported packet type; just ignore it. |
639 | break; |
640 | } |
641 | nextPacketLength = -1; |
642 | } while (bytesAvailable() > 0); |
643 | } |
644 | |
645 | void PeerWireClient::socketStateChanged(QAbstractSocket::SocketState state) |
646 | { |
647 | setLocalAddress(socket.localAddress()); |
648 | setLocalPort(socket.localPort()); |
649 | setPeerName(socket.peerName()); |
650 | setPeerAddress(socket.peerAddress()); |
651 | setPeerPort(socket.peerPort()); |
652 | setSocketState(state); |
653 | } |
654 | |
655 | qint64 PeerWireClient::readData(char *data, qint64 size) |
656 | { |
657 | int n = qMin<int>(a: size, b: incomingBuffer.size()); |
658 | memcpy(dest: data, src: incomingBuffer.constData(), n: n); |
659 | incomingBuffer.remove(index: 0, len: n); |
660 | return n; |
661 | } |
662 | |
663 | qint64 PeerWireClient::readLineData(char *data, qint64 maxlen) |
664 | { |
665 | return QIODevice::readLineData(data, maxlen); |
666 | } |
667 | |
668 | qint64 PeerWireClient::writeData(const char *data, qint64 size) |
669 | { |
670 | int oldSize = outgoingBuffer.size(); |
671 | outgoingBuffer.resize(size: oldSize + size); |
672 | memcpy(dest: outgoingBuffer.data() + oldSize, src: data, n: size); |
673 | emit readyToTransfer(); |
674 | return size; |
675 | } |
676 | |