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#ifndef PEERWIRECLIENT_H
52#define PEERWIRECLIENT_H
53
54#include <QBitArray>
55#include <QList>
56#include <QTcpSocket>
57
58QT_BEGIN_NAMESPACE
59class QHostAddress;
60class QTimerEvent;
61QT_END_NAMESPACE
62class TorrentPeer;
63
64struct TorrentBlock
65{
66 inline TorrentBlock(int p, int o, int l)
67 : pieceIndex(p), offset(o), length(l)
68 {
69 }
70 inline bool operator==(const TorrentBlock &other) const
71 {
72 return pieceIndex == other.pieceIndex
73 && offset == other.offset
74 && length == other.length;
75 }
76
77 int pieceIndex;
78 int offset;
79 int length;
80};
81
82class PeerWireClient : public QTcpSocket
83{
84 Q_OBJECT
85
86public:
87 enum PeerWireStateFlag {
88 ChokingPeer = 0x1,
89 InterestedInPeer = 0x2,
90 ChokedByPeer = 0x4,
91 PeerIsInterested = 0x8
92 };
93 Q_DECLARE_FLAGS(PeerWireState, PeerWireStateFlag)
94
95 explicit PeerWireClient(const QByteArray &peerId, QObject *parent = nullptr);
96 void initialize(const QByteArray &infoHash, int pieceCount);
97
98 void setPeer(TorrentPeer *peer);
99 TorrentPeer *peer() const;
100
101 // State
102 inline PeerWireState peerWireState() const { return pwState; }
103 QBitArray availablePieces() const;
104 QList<TorrentBlock> incomingBlocks() const;
105
106 // Protocol
107 void chokePeer();
108 void unchokePeer();
109 void sendInterested();
110 void sendKeepAlive();
111 void sendNotInterested();
112 void sendPieceNotification(int piece);
113 void sendPieceList(const QBitArray &bitField);
114 void requestBlock(int piece, int offset, int length);
115 void cancelRequest(int piece, int offset, int length);
116 void sendBlock(int piece, int offset, const QByteArray &data);
117
118 // Rate control
119 qint64 writeToSocket(qint64 bytes);
120 qint64 readFromSocket(qint64 bytes);
121 qint64 downloadSpeed() const;
122 qint64 uploadSpeed() const;
123
124 bool canTransferMore() const;
125 qint64 bytesAvailable() const override { return incomingBuffer.size() + QTcpSocket::bytesAvailable(); }
126 qint64 socketBytesAvailable() const { return socket.bytesAvailable(); }
127 qint64 socketBytesToWrite() const { return socket.bytesToWrite(); }
128
129 void setReadBufferSize(qint64 size) override;
130
131 void connectToHost(const QHostAddress &address,
132 quint16 port, OpenMode openMode = ReadWrite) override;
133 void diconnectFromHost();
134
135signals:
136 void infoHashReceived(const QByteArray &infoHash);
137 void readyToTransfer();
138
139 void choked();
140 void unchoked();
141 void interested();
142 void notInterested();
143
144 void piecesAvailable(const QBitArray &pieces);
145 void blockRequested(int pieceIndex, int begin, int length);
146 void blockReceived(int pieceIndex, int begin, const QByteArray &data);
147
148 void bytesReceived(qint64 size);
149
150protected:
151 void timerEvent(QTimerEvent *event) override;
152
153 qint64 readData(char *data, qint64 maxlen) override;
154 qint64 readLineData(char *data, qint64 maxlen) override;
155 qint64 writeData(const char *data, qint64 len) override;
156
157private slots:
158 void sendHandShake();
159 void processIncomingData();
160 void socketStateChanged(QAbstractSocket::SocketState state);
161
162private:
163 // Data waiting to be read/written
164 QByteArray incomingBuffer;
165 QByteArray outgoingBuffer;
166
167 struct BlockInfo {
168 int pieceIndex;
169 int offset;
170 int length;
171 QByteArray block;
172 };
173 QList<BlockInfo> pendingBlocks;
174 int pendingBlockSizes;
175 QList<TorrentBlock> incoming;
176
177 enum PacketType {
178 ChokePacket = 0,
179 UnchokePacket = 1,
180 InterestedPacket = 2,
181 NotInterestedPacket = 3,
182 HavePacket = 4,
183 BitFieldPacket = 5,
184 RequestPacket = 6,
185 PiecePacket = 7,
186 CancelPacket = 8
187 };
188
189 // State
190 PeerWireState pwState;
191 bool receivedHandShake;
192 bool gotPeerId;
193 bool sentHandShake;
194 int nextPacketLength;
195
196 // Upload/download speed records
197 qint64 uploadSpeedData[8];
198 qint64 downloadSpeedData[8];
199 int transferSpeedTimer;
200
201 // Timeout handling
202 int timeoutTimer;
203 int pendingRequestTimer;
204 bool invalidateTimeout;
205 int keepAliveTimer;
206
207 // Checksum, peer ID and set of available pieces
208 QByteArray infoHash;
209 QByteArray peerIdString;
210 QBitArray peerPieces;
211 TorrentPeer *torrentPeer;
212
213 QTcpSocket socket;
214};
215
216Q_DECLARE_OPERATORS_FOR_FLAGS(PeerWireClient::PeerWireState)
217
218#endif
219

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