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
56static const int PendingRequestTimeout = 60 * 1000;
57static const int ClientTimeout = 120 * 1000;
58static const int ConnectTimeout = 60 * 1000;
59static const int KeepAliveInterval = 30 * 1000;
60static const int RateControlTimerDelay = 2000;
61static const int MinimalHeaderSize = 48;
62static const char ProtocolId[] = "BitTorrent protocol";
63static const char ProtocolIdSize = 19;
64
65// Reads a 32bit unsigned int from data in network order.
66static 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.
76static 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.
86PeerWireClient::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.
121void PeerWireClient::initialize(const QByteArray &infoHash, int pieceCount)
122{
123 this->infoHash = infoHash;
124 peerPieces.resize(size: pieceCount);
125 if (!sentHandShake)
126 sendHandShake();
127}
128
129void PeerWireClient::setPeer(TorrentPeer *peer)
130{
131 torrentPeer = peer;
132}
133
134TorrentPeer *PeerWireClient::peer() const
135{
136 return torrentPeer;
137}
138
139QBitArray PeerWireClient::availablePieces() const
140{
141 return peerPieces;
142}
143
144QList<TorrentBlock> PeerWireClient::incomingBlocks() const
145{
146 return incoming;
147}
148
149// Sends a "choke" message, asking the peer to stop requesting blocks.
150void 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.
164void 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
176void 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.
184void 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.
200void 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.
209void 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.
220void 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.
250void 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.
273void 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.
289void 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.
323qint64 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.
346qint64 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.
371qint64 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.
381qint64 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
389void PeerWireClient::setReadBufferSize(qint64 size)
390{
391 socket.setReadBufferSize(size);
392}
393
394bool PeerWireClient::canTransferMore() const
395{
396 return bytesAvailable() > 0 || socket.bytesAvailable() > 0
397 || !outgoingBuffer.isEmpty() || !pendingBlocks.isEmpty();
398}
399
400void PeerWireClient::connectToHost(const QHostAddress &address,
401 quint16 port, OpenMode openMode)
402
403{
404 setOpenMode(openMode);
405 socket.connectToHost(address, port, mode: openMode);
406}
407
408void PeerWireClient::diconnectFromHost()
409{
410 socket.disconnectFromHost();
411}
412
413void 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.
441void 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
458void 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
645void 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
655qint64 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
663qint64 PeerWireClient::readLineData(char *data, qint64 maxlen)
664{
665 return QIODevice::readLineData(data, maxlen);
666}
667
668qint64 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

source code of qtbase/examples/network/torrent/peerwireclient.cpp