qBittorrent
peerinfo.cpp
Go to the documentation of this file.
1 /*
2  * Bittorrent Client using Qt and libtorrent.
3  * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * In addition, as a special exception, the copyright holders give permission to
20  * link this program with the OpenSSL project's "OpenSSL" library (or with
21  * modified versions of it that use the same license as the "OpenSSL" library),
22  * and distribute the linked executables. You must obey the GNU General Public
23  * License in all respects for all of the code used other than "OpenSSL". If you
24  * modify file(s), you may extend this exception to your version of the file(s),
25  * but you are not obligated to do so. If you do not wish to do so, delete this
26  * exception statement from your version.
27  */
28 
29 #include "peerinfo.h"
30 
31 #include <QBitArray>
32 
34 #include "base/net/geoipmanager.h"
35 #include "base/unicodestrings.h"
36 #include "peeraddress.h"
37 
38 using namespace BitTorrent;
39 
40 PeerInfo::PeerInfo(const Torrent *torrent, const lt::peer_info &nativeInfo)
41  : m_nativeInfo(nativeInfo)
42 {
43  calcRelevance(torrent);
45 }
46 
47 bool PeerInfo::fromDHT() const
48 {
49  return static_cast<bool>(m_nativeInfo.source & lt::peer_info::dht);
50 }
51 
52 bool PeerInfo::fromPeX() const
53 {
54  return static_cast<bool>(m_nativeInfo.source & lt::peer_info::pex);
55 }
56 
57 bool PeerInfo::fromLSD() const
58 {
59  return static_cast<bool>(m_nativeInfo.source & lt::peer_info::lsd);
60 }
61 
62 QString PeerInfo::country() const
63 {
64  if (m_country.isEmpty())
66  return m_country;
67 }
68 
70 {
71  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::interesting);
72 }
73 
74 bool PeerInfo::isChocked() const
75 {
76  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::choked);
77 }
78 
80 {
81  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::remote_interested);
82 }
83 
85 {
86  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::remote_choked);
87 }
88 
90 {
91  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::supports_extensions);
92 }
93 
95 {
96  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::local_connection);
97 }
98 
100 {
101  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::handshake);
102 }
103 
105 {
106  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::connecting);
107 }
108 
110 {
111  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::on_parole);
112 }
113 
114 bool PeerInfo::isSeed() const
115 {
116  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::seed);
117 }
118 
120 {
121  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::optimistic_unchoke);
122 }
123 
125 {
126  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::snubbed);
127 }
128 
130 {
131  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::upload_only);
132 }
133 
135 {
136  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::endgame_mode);
137 }
138 
140 {
141  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::holepunched);
142 }
143 
145 {
146  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::i2p_socket);
147 }
148 
150 {
151  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::utp_socket);
152 }
153 
155 {
156  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::ssl_socket);
157 }
158 
160 {
161  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::rc4_encrypted);
162 }
163 
165 {
166  return static_cast<bool>(m_nativeInfo.flags & lt::peer_info::plaintext_encrypted);
167 }
168 
170 {
171  // fast path for platforms which boost.asio internal struct maps to `sockaddr`
172  return {QHostAddress(m_nativeInfo.ip.data()), m_nativeInfo.ip.port()};
173  // slow path for the others
174  //return {QHostAddress(QString::fromStdString(m_nativeInfo.ip.address().to_string()))
175  // , m_nativeInfo.ip.port()};
176 }
177 
178 QString PeerInfo::client() const
179 {
180  return QString::fromStdString(m_nativeInfo.client);
181 }
182 
183 qreal PeerInfo::progress() const
184 {
185  return m_nativeInfo.progress;
186 }
187 
189 {
190  return m_nativeInfo.payload_up_speed;
191 }
192 
194 {
195  return m_nativeInfo.payload_down_speed;
196 }
197 
198 qlonglong PeerInfo::totalUpload() const
199 {
200  return m_nativeInfo.total_upload;
201 }
202 
203 qlonglong PeerInfo::totalDownload() const
204 {
205  return m_nativeInfo.total_download;
206 }
207 
208 QBitArray PeerInfo::pieces() const
209 {
210  QBitArray result(m_nativeInfo.pieces.size());
211  for (int i = 0; i < result.size(); ++i)
212  {
213  if (m_nativeInfo.pieces[lt::piece_index_t {i}])
214  result.setBit(i, true);
215  }
216  return result;
217 }
218 
220 {
221  if (m_nativeInfo.flags & lt::peer_info::utp_socket)
222  return QString::fromUtf8(C_UTP);
223 
224  return (m_nativeInfo.connection_type == lt::peer_info::standard_bittorrent)
225  ? QLatin1String {"BT"}
226  : QLatin1String {"Web"};
227 }
228 
229 void PeerInfo::calcRelevance(const Torrent *torrent)
230 {
231  const QBitArray allPieces = torrent->pieces();
232  const QBitArray peerPieces = pieces();
233 
234  int localMissing = 0;
235  int remoteHaves = 0;
236 
237  for (int i = 0; i < allPieces.size(); ++i)
238  {
239  if (!allPieces[i])
240  {
241  ++localMissing;
242  if (peerPieces[i])
243  ++remoteHaves;
244  }
245  }
246 
247  if (localMissing == 0)
248  m_relevance = 0.0;
249  else
250  m_relevance = static_cast<qreal>(remoteHaves) / localMissing;
251 }
252 
253 qreal PeerInfo::relevance() const
254 {
255  return m_relevance;
256 }
257 
259 {
260  const auto updateFlags = [this](const QChar specifier, const QString &explanation)
261  {
262  m_flags += (specifier + QLatin1Char(' '));
263  m_flagsDescription += QString::fromLatin1("%1 = %2\n").arg(specifier, explanation);
264  };
265 
266  if (isInteresting())
267  {
268  if (isRemoteChocked())
269  {
270  // d = Your client wants to download, but peer doesn't want to send (interested and choked)
271  updateFlags(QLatin1Char('d'), tr("Interested (local) and choked (peer)"));
272  }
273  else
274  {
275  // D = Currently downloading (interested and not choked)
276  updateFlags(QLatin1Char('D'), tr("Interested (local) and unchoked (peer)"));
277  }
278  }
279 
280  if (isRemoteInterested())
281  {
282  if (isChocked())
283  {
284  // u = Peer wants your client to upload, but your client doesn't want to (interested and choked)
285  updateFlags(QLatin1Char('u'), tr("Interested (peer) and choked (local)"));
286  }
287  else
288  {
289  // U = Currently uploading (interested and not choked)
290  updateFlags(QLatin1Char('U'), tr("Interested (peer) and unchoked (local)"));
291  }
292  }
293 
294  // K = Peer is unchoking your client, but your client is not interested
295  if (!isRemoteChocked() && !isInteresting())
296  updateFlags(QLatin1Char('K'), tr("Not interested (local) and unchoked (peer)"));
297 
298  // ? = Your client unchoked the peer but the peer is not interested
299  if (!isChocked() && !isRemoteInterested())
300  updateFlags(QLatin1Char('?'), tr("Not interested (peer) and unchoked (local)"));
301 
302  // O = Optimistic unchoke
303  if (optimisticUnchoke())
304  updateFlags(QLatin1Char('O'), tr("Optimistic unchoke"));
305 
306  // S = Peer is snubbed
307  if (isSnubbed())
308  updateFlags(QLatin1Char('S'), tr("Peer snubbed"));
309 
310  // I = Peer is an incoming connection
311  if (!isLocalConnection())
312  updateFlags(QLatin1Char('I'), tr("Incoming connection"));
313 
314  // H = Peer was obtained through DHT
315  if (fromDHT())
316  updateFlags(QLatin1Char('H'), tr("Peer from DHT"));
317 
318  // X = Peer was included in peerlists obtained through Peer Exchange (PEX)
319  if (fromPeX())
320  updateFlags(QLatin1Char('X'), tr("Peer from PEX"));
321 
322  // L = Peer is local
323  if (fromLSD())
324  updateFlags(QLatin1Char('L'), tr("Peer from LSD"));
325 
326  // E = Peer is using Protocol Encryption (all traffic)
327  if (isRC4Encrypted())
328  updateFlags(QLatin1Char('E'), tr("Encrypted traffic"));
329 
330  // e = Peer is using Protocol Encryption (handshake)
331  if (isPlaintextEncrypted())
332  updateFlags(QLatin1Char('e'), tr("Encrypted handshake"));
333 
334  // P = Peer is using uTorrent uTP
335  if (useUTPSocket())
336  updateFlags(QLatin1Char('P'), QString::fromUtf8(C_UTP));
337 
338  m_flags.chop(1);
339  m_flagsDescription.chop(1);
340 }
341 
342 QString PeerInfo::flags() const
343 {
344  return m_flags;
345 }
346 
348 {
349  return m_flagsDescription;
350 }
351 
353 {
354  return static_cast<int>(m_nativeInfo.downloading_piece_index);
355 }
lt::peer_info m_nativeInfo
Definition: peerinfo.h:98
bool useUTPSocket() const
Definition: peerinfo.cpp:149
bool isHandshake() const
Definition: peerinfo.cpp:99
bool isHolepunched() const
Definition: peerinfo.cpp:139
qlonglong totalUpload() const
Definition: peerinfo.cpp:198
qlonglong totalDownload() const
Definition: peerinfo.cpp:203
QString flagsDescription() const
Definition: peerinfo.cpp:347
int payloadUpSpeed() const
Definition: peerinfo.cpp:188
bool isSupportsExtensions() const
Definition: peerinfo.cpp:89
int payloadDownSpeed() const
Definition: peerinfo.cpp:193
QString flags() const
Definition: peerinfo.cpp:342
bool isRemoteInterested() const
Definition: peerinfo.cpp:79
bool isLocalConnection() const
Definition: peerinfo.cpp:94
QString client() const
Definition: peerinfo.cpp:178
QBitArray pieces() const
Definition: peerinfo.cpp:208
bool isConnecting() const
Definition: peerinfo.cpp:104
bool isOnParole() const
Definition: peerinfo.cpp:109
bool fromPeX() const
Definition: peerinfo.cpp:52
bool isUploadOnly() const
Definition: peerinfo.cpp:129
bool isInteresting() const
Definition: peerinfo.cpp:69
QString connectionType() const
Definition: peerinfo.cpp:219
bool isRC4Encrypted() const
Definition: peerinfo.cpp:159
bool isSnubbed() const
Definition: peerinfo.cpp:124
PeerAddress address() const
Definition: peerinfo.cpp:169
bool useI2PSocket() const
Definition: peerinfo.cpp:144
bool fromLSD() const
Definition: peerinfo.cpp:57
qreal relevance() const
Definition: peerinfo.cpp:253
int downloadingPieceIndex() const
Definition: peerinfo.cpp:352
bool isPlaintextEncrypted() const
Definition: peerinfo.cpp:164
bool isEndgameMode() const
Definition: peerinfo.cpp:134
bool fromDHT() const
Definition: peerinfo.cpp:47
QString country() const
Definition: peerinfo.cpp:62
bool isRemoteChocked() const
Definition: peerinfo.cpp:84
void calcRelevance(const Torrent *torrent)
Definition: peerinfo.cpp:229
bool isSeed() const
Definition: peerinfo.cpp:114
bool optimisticUnchoke() const
Definition: peerinfo.cpp:119
qreal progress() const
Definition: peerinfo.cpp:183
bool isChocked() const
Definition: peerinfo.cpp:74
QString m_flagsDescription
Definition: peerinfo.h:101
bool useSSLSocket() const
Definition: peerinfo.cpp:154
virtual QBitArray pieces() const =0
static GeoIPManager * instance()
QString lookup(const QHostAddress &hostAddr) const
const char C_UTP[]