2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
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.
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.
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.
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.
33 #include "base/bittorrent/torrent.h"
34 #include "base/net/geoipmanager.h"
35 #include "base/unicodestrings.h"
36 #include "peeraddress.h"
38 using namespace BitTorrent
;
40 PeerInfo::PeerInfo(const Torrent
*torrent
, const lt::peer_info
&nativeInfo
)
41 : m_nativeInfo(nativeInfo
)
43 calcRelevance(torrent
);
47 bool PeerInfo::fromDHT() const
49 return static_cast<bool>(m_nativeInfo
.source
& lt::peer_info::dht
);
52 bool PeerInfo::fromPeX() const
54 return static_cast<bool>(m_nativeInfo
.source
& lt::peer_info::pex
);
57 bool PeerInfo::fromLSD() const
59 return static_cast<bool>(m_nativeInfo
.source
& lt::peer_info::lsd
);
62 QString
PeerInfo::country() const
64 if (m_country
.isEmpty())
65 m_country
= Net::GeoIPManager::instance()->lookup(address().ip
);
69 bool PeerInfo::isInteresting() const
71 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::interesting
);
74 bool PeerInfo::isChocked() const
76 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::choked
);
79 bool PeerInfo::isRemoteInterested() const
81 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::remote_interested
);
84 bool PeerInfo::isRemoteChocked() const
86 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::remote_choked
);
89 bool PeerInfo::isSupportsExtensions() const
91 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::supports_extensions
);
94 bool PeerInfo::isLocalConnection() const
96 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::local_connection
);
99 bool PeerInfo::isHandshake() const
101 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::handshake
);
104 bool PeerInfo::isConnecting() const
106 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::connecting
);
109 bool PeerInfo::isOnParole() const
111 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::on_parole
);
114 bool PeerInfo::isSeed() const
116 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::seed
);
119 bool PeerInfo::optimisticUnchoke() const
121 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::optimistic_unchoke
);
124 bool PeerInfo::isSnubbed() const
126 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::snubbed
);
129 bool PeerInfo::isUploadOnly() const
131 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::upload_only
);
134 bool PeerInfo::isEndgameMode() const
136 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::endgame_mode
);
139 bool PeerInfo::isHolepunched() const
141 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::holepunched
);
144 bool PeerInfo::useI2PSocket() const
146 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::i2p_socket
);
149 bool PeerInfo::useUTPSocket() const
151 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::utp_socket
);
154 bool PeerInfo::useSSLSocket() const
156 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::ssl_socket
);
159 bool PeerInfo::isRC4Encrypted() const
161 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::rc4_encrypted
);
164 bool PeerInfo::isPlaintextEncrypted() const
166 return static_cast<bool>(m_nativeInfo
.flags
& lt::peer_info::plaintext_encrypted
);
169 PeerAddress
PeerInfo::address() const
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()};
178 QString
PeerInfo::client() const
180 return QString::fromStdString(m_nativeInfo
.client
);
183 qreal
PeerInfo::progress() const
185 return m_nativeInfo
.progress
;
188 int PeerInfo::payloadUpSpeed() const
190 return m_nativeInfo
.payload_up_speed
;
193 int PeerInfo::payloadDownSpeed() const
195 return m_nativeInfo
.payload_down_speed
;
198 qlonglong
PeerInfo::totalUpload() const
200 return m_nativeInfo
.total_upload
;
203 qlonglong
PeerInfo::totalDownload() const
205 return m_nativeInfo
.total_download
;
208 QBitArray
PeerInfo::pieces() const
210 QBitArray
result(m_nativeInfo
.pieces
.size());
211 for (int i
= 0; i
< result
.size(); ++i
)
213 if (m_nativeInfo
.pieces
[lt::piece_index_t
{i
}])
214 result
.setBit(i
, true);
219 QString
PeerInfo::connectionType() const
221 if (m_nativeInfo
.flags
& lt::peer_info::utp_socket
)
222 return QString::fromUtf8(C_UTP
);
224 return (m_nativeInfo
.connection_type
== lt::peer_info::standard_bittorrent
)
225 ? QLatin1String
{"BT"}
226 : QLatin1String
{"Web"};
229 void PeerInfo::calcRelevance(const Torrent
*torrent
)
231 const QBitArray allPieces
= torrent
->pieces();
232 const QBitArray peerPieces
= pieces();
234 int localMissing
= 0;
237 for (int i
= 0; i
< allPieces
.size(); ++i
)
247 if (localMissing
== 0)
250 m_relevance
= static_cast<qreal
>(remoteHaves
) / localMissing
;
253 qreal
PeerInfo::relevance() const
258 void PeerInfo::determineFlags()
260 const auto updateFlags
= [this](const QChar specifier
, const QString
&explanation
)
262 m_flags
+= (specifier
+ QLatin1Char(' '));
263 m_flagsDescription
+= QString::fromLatin1("%1 = %2\n").arg(specifier
, explanation
);
268 if (isRemoteChocked())
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)"));
275 // D = Currently downloading (interested and not choked)
276 updateFlags(QLatin1Char('D'), tr("Interested (local) and unchoked (peer)"));
280 if (isRemoteInterested())
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)"));
289 // U = Currently uploading (interested and not choked)
290 updateFlags(QLatin1Char('U'), tr("Interested (peer) and unchoked (local)"));
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)"));
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)"));
302 // O = Optimistic unchoke
303 if (optimisticUnchoke())
304 updateFlags(QLatin1Char('O'), tr("Optimistic unchoke"));
306 // S = Peer is snubbed
308 updateFlags(QLatin1Char('S'), tr("Peer snubbed"));
310 // I = Peer is an incoming connection
311 if (!isLocalConnection())
312 updateFlags(QLatin1Char('I'), tr("Incoming connection"));
314 // H = Peer was obtained through DHT
316 updateFlags(QLatin1Char('H'), tr("Peer from DHT"));
318 // X = Peer was included in peerlists obtained through Peer Exchange (PEX)
320 updateFlags(QLatin1Char('X'), tr("Peer from PEX"));
324 updateFlags(QLatin1Char('L'), tr("Peer from LSD"));
326 // E = Peer is using Protocol Encryption (all traffic)
327 if (isRC4Encrypted())
328 updateFlags(QLatin1Char('E'), tr("Encrypted traffic"));
330 // e = Peer is using Protocol Encryption (handshake)
331 if (isPlaintextEncrypted())
332 updateFlags(QLatin1Char('e'), tr("Encrypted handshake"));
334 // P = Peer is using uTorrent uTP
336 updateFlags(QLatin1Char('P'), QString::fromUtf8(C_UTP
));
339 m_flagsDescription
.chop(1);
342 QString
PeerInfo::flags() const
347 QString
PeerInfo::flagsDescription() const
349 return m_flagsDescription
;
352 int PeerInfo::downloadingPieceIndex() const
354 return static_cast<int>(m_nativeInfo
.downloading_piece_index
);