33 #include <libtorrent/bencode.hpp>
34 #include <libtorrent/entry.hpp>
36 #include <QHostAddress>
89 using RuntimeError::RuntimeError;
95 switch (addr.protocol())
97 case QAbstractSocket::IPv4Protocol:
98 case QAbstractSocket::AnyIPProtocol:
100 const quint32 ipv4 = addr.toIPv4Address();
102 ret.append(
static_cast<char>((ipv4 >> 24) & 0xFF))
103 .append(
static_cast<char>((ipv4 >> 16) & 0xFF))
104 .append(
static_cast<char>((ipv4 >> 8) & 0xFF))
105 .append(
static_cast<char>(ipv4 & 0xFF));
109 case QAbstractSocket::IPv6Protocol:
111 const Q_IPV6ADDR ipv6 = addr.toIPv6Address();
113 for (
const quint8 i : ipv6.c)
118 case QAbstractSocket::UnknownNetworkLayerProtocol:
130 return (QByteArray::fromStdString(
address) +
':' + QByteArray::number(
port));
140 return !(left == right);
183 const auto iter = peers.find(peer);
184 if (iter == peers.end())
202 const QHostAddress ip = QHostAddress::Any;
218 const bool listenSuccess =
m_server->listen(ip, port);
222 LogMsg(tr(
"Embedded Tracker: Now listening on IP: %1, port: %2")
223 .arg(ip.toString(), QString::number(port)),
Log::INFO);
227 LogMsg(tr(
"Embedded Tracker: Unable to bind to IP: %1, port: %2. Reason: %3")
228 .arg(ip.toString(), QString::number(port),
m_server->errorString())
232 return listenSuccess;
258 if (!error.
message().isEmpty())
261 catch (
const TrackerError &error)
266 const lt::entry::dictionary_type bencodedEntry =
271 lt::bencode(std::back_inserter(reply), bencodedEntry);
289 const qint32 decimalIPv4 = announceReq.
socketAddress.toIPv4Address(&ok);
295 if (infoHashIter == queryParams.end())
296 throw TrackerError(
"Missing \"info_hash\" parameter");
299 if (!torrentID.isValid())
300 throw TrackerError(
"Invalid \"info_hash\" parameter");
306 if (peerIdIter == queryParams.end())
307 throw TrackerError(
"Missing \"peer_id\" parameter");
310 throw TrackerError(
"Invalid \"peer_id\" parameter");
316 if (portIter == queryParams.end())
317 throw TrackerError(
"Missing \"port\" parameter");
319 const ushort portNum = portIter->toUShort();
321 throw TrackerError(
"Invalid \"port\" parameter");
327 if (numWantIter != queryParams.end())
329 const int num = numWantIter->toInt();
331 throw TrackerError(
"Invalid \"numwant\" parameter");
346 const QHostAddress claimedIPAddress {QString::fromLatin1(announceReq.
claimedAddress)};
348 .append(
static_cast<char>((announceReq.
peer.
port >> 8) & 0xFF))
349 .append(
static_cast<char>(announceReq.
peer.
port & 0xFF))
355 : announceReq.
socketAddress.toString().toLatin1().constData(),
360 if (announceReq.
event.isEmpty()
376 throw TrackerError(
"Invalid \"event\" parameter");
400 torrentStatsIter->removePeer(announceReq.
peer);
402 if (torrentStatsIter->peers.isEmpty())
410 lt::entry::dictionary_type replyDict
425 lt::entry::string_type peers;
426 lt::entry::string_type peers6;
433 if (counter++ >= announceReq.
numwant)
436 if (peer.endpoint.size() == 6)
437 peers.append(peer.endpoint);
438 else if (peer.endpoint.size() == 18)
439 peers6.append(peer.endpoint);
449 lt::entry::list_type peerList;
454 for (
const Peer &peer : torrentStats.
peers)
456 if (counter++ >= announceReq.
numwant)
459 lt::entry::dictionary_type peerDict =
468 peerList.emplace_back(peerDict);
477 lt::bencode(std::back_inserter(reply), replyDict);
static TorrentID fromString(const QString &hashString)
void prepareAnnounceResponse(const TrackerAnnounceRequest &announceReq)
void processAnnounceRequest()
Http::Response processRequest(const Http::Request &request, const Http::Environment &env) override
void registerPeer(const TrackerAnnounceRequest &announceReq)
QHash< TorrentID, TorrentStats > m_torrents
Tracker(QObject *parent=nullptr)
void unregisterPeer(const TrackerAnnounceRequest &announceReq)
QString message() const noexcept
QString statusText() const
Response response() const
void print(const QString &text, const QString &type=CONTENT_TYPE_HTML)
void status(uint code=200, const QString &text=QLatin1String("OK"))
static Preferences * instance()
int getTrackerPort() const
constexpr std::add_const_t< T > & asConst(T &t) noexcept
void LogMsg(const QString &message, const Log::MsgType &type)
uint qHash(const TorrentID &key, uint seed)
bool operator==(const CategoryOptions::DownloadPathOption &left, const CategoryOptions::DownloadPathOption &right)
bool operator!=(const InfoHash &left, const InfoHash &right)
const char HEADER_REQUEST_METHOD_GET[]
const char CONTENT_TYPE_TXT[]
const char ANNOUNCE_REQUEST_EVENT_STOPPED[]
const char ANNOUNCE_REQUEST_EVENT_COMPLETED[]
QByteArray toBigEndianByteArray(const QHostAddress &addr)
const char ANNOUNCE_REQUEST_NO_PEER_ID[]
const char ANNOUNCE_RESPONSE_PEERS6[]
const char ANNOUNCE_REQUEST_PATH[]
const char ANNOUNCE_REQUEST_EVENT_PAUSED[]
const char ANNOUNCE_REQUEST_NUM_WANT[]
const char ANNOUNCE_RESPONSE_INCOMPLETE[]
const int ANNOUNCE_INTERVAL
const char ANNOUNCE_RESPONSE_INTERVAL[]
const char ANNOUNCE_RESPONSE_PEERS_PEER_ID[]
const char ANNOUNCE_REQUEST_LEFT[]
const char ANNOUNCE_RESPONSE_PEERS_PORT[]
const char ANNOUNCE_REQUEST_EVENT_STARTED[]
const char ANNOUNCE_REQUEST_PEER_ID[]
const char ANNOUNCE_RESPONSE_COMPLETE[]
const char ANNOUNCE_REQUEST_IP[]
const char ANNOUNCE_RESPONSE_FAILURE_REASON[]
const char ANNOUNCE_REQUEST_EVENT_EMPTY[]
const char ANNOUNCE_REQUEST_EVENT[]
const char ANNOUNCE_REQUEST_COMPACT[]
const char ANNOUNCE_RESPONSE_EXTERNAL_IP[]
const char ANNOUNCE_REQUEST_PORT[]
const char ANNOUNCE_RESPONSE_PEERS[]
const int MAX_PEERS_PER_TORRENT
const char ANNOUNCE_RESPONSE_PEERS_IP[]
const char ANNOUNCE_REQUEST_INFO_HASH[]
lt::entry::string_type endpoint
lt::entry::string_type address
QByteArray uniqueID() const
void setPeer(const Peer &peer)
bool removePeer(const Peer &peer)
QHostAddress clientAddress
QHash< QString, QByteArray > query
QHostAddress socketAddress
QByteArray claimedAddress