1 /*
2     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 #include "udptracker.h"
7 #include "udptrackersocket.h"
8 #include <arpa/inet.h>
9 #include <interfaces/torrentinterface.h>
10 #include <klocalizedstring.h>
11 #include <net/addressresolver.h>
12 #include <peer/peermanager.h>
13 #include <stdlib.h>
14 #include <torrent/globals.h>
15 #include <torrent/server.h>
16 #include <util/functions.h>
17 #include <util/log.h>
18 
19 namespace bt
20 {
21 UDPTrackerSocket *UDPTracker::socket = nullptr;
22 Uint32 UDPTracker::num_instances = 0;
23 
UDPTracker(const QUrl & url,TrackerDataSource * tds,const PeerID & id,int tier)24 UDPTracker::UDPTracker(const QUrl &url, TrackerDataSource *tds, const PeerID &id, int tier)
25     : Tracker(url, tds, id, tier)
26     , connection_id(0)
27     , transaction_id(0)
28     , scrape_transaction_id(0)
29     , data_read(0)
30     , failures(0)
31     , resolved(false)
32     , todo(NOTHING)
33     , event(NONE)
34 {
35     num_instances++;
36     if (!socket)
37         socket = new UDPTrackerSocket();
38 
39     interval = 0;
40 
41     conn_timer.setSingleShot(true);
42     connect(&conn_timer, &QTimer::timeout, this, &UDPTracker::onConnTimeout);
43     connect(socket, &UDPTrackerSocket::announceReceived, this, &UDPTracker::announceReceived);
44     connect(socket, &UDPTrackerSocket::connectReceived, this, &UDPTracker::connectReceived);
45     connect(socket, &UDPTrackerSocket::error, this, &UDPTracker::onError);
46     connect(socket, &UDPTrackerSocket::scrapeReceived, this, &UDPTracker::scrapeReceived);
47 }
48 
~UDPTracker()49 UDPTracker::~UDPTracker()
50 {
51     num_instances--;
52     if (num_instances == 0) {
53         delete socket;
54         socket = nullptr;
55     }
56 }
57 
start()58 void UDPTracker::start()
59 {
60     event = STARTED;
61     resetTrackerStats();
62     conn_timer.stop();
63     doRequest();
64 }
65 
stop(WaitJob *)66 void UDPTracker::stop(WaitJob *)
67 {
68     if (!started) {
69         if (transaction_id) {
70             socket->cancelTransaction(transaction_id);
71             transaction_id = 0;
72             status = TRACKER_IDLE;
73             requestOK();
74         }
75         reannounce_timer.stop();
76     } else {
77         event = STOPPED;
78         reannounce_timer.stop();
79         conn_timer.stop();
80         doRequest();
81         started = false;
82     }
83 }
84 
completed()85 void UDPTracker::completed()
86 {
87     event = COMPLETED;
88     conn_timer.stop();
89     doRequest();
90 }
91 
manualUpdate()92 void UDPTracker::manualUpdate()
93 {
94     conn_timer.stop();
95     if (!started)
96         start();
97     else
98         doRequest();
99 }
100 
connectReceived(Int32 tid,Int64 cid)101 void UDPTracker::connectReceived(Int32 tid, Int64 cid)
102 {
103     if (tid != transaction_id)
104         return;
105 
106     connection_id = cid;
107     failures = 0;
108     if (todo & ANNOUNCE_REQUEST)
109         sendAnnounce();
110     if (todo & SCRAPE_REQUEST)
111         sendScrape();
112 }
113 
announceReceived(Int32 tid,const bt::Uint8 * buf,bt::Uint32 size)114 void UDPTracker::announceReceived(Int32 tid, const bt::Uint8 *buf, bt::Uint32 size)
115 {
116     if (tid != transaction_id || size < 20)
117         return;
118 
119     /*
120     0  32-bit integer  action  1
121     4  32-bit integer  transaction_id
122     8  32-bit integer  interval
123     12  32-bit integer  leechers
124     16  32-bit integer  seeders
125     20 + 6 * n  32-bit integer  IP address
126     24 + 6 * n  16-bit integer  TCP port
127     20 + 6 * N
128     */
129     interval = ReadInt32(buf, 8);
130     leechers = ReadInt32(buf, 12);
131     seeders = ReadInt32(buf, 16);
132 
133     Uint32 nip = leechers + seeders;
134     Uint32 j = 0;
135     for (Uint32 i = 20; i < size && j < nip; i += 6, j++) {
136         Uint32 ip = ReadUint32(buf, i);
137         addPeer(net::Address(ip, ReadUint16(buf, i + 4)), false);
138     }
139 
140     peersReady(this);
141     connection_id = 0;
142     conn_timer.stop();
143     if (event != STOPPED) {
144         if (event == STARTED)
145             started = true;
146         event = NONE;
147         status = TRACKER_OK;
148         requestOK();
149         if (started)
150             reannounce_timer.start(interval * 1000);
151     } else {
152         stopDone();
153         status = TRACKER_IDLE;
154         requestOK();
155     }
156     request_time = QDateTime::currentDateTime();
157 }
158 
onError(Int32 tid,const QString & error_string)159 void UDPTracker::onError(Int32 tid, const QString &error_string)
160 {
161     if (tid != transaction_id)
162         return;
163 
164     Out(SYS_TRK | LOG_IMPORTANT) << "UDPTracker::error : " << error_string << endl;
165     failed(error_string);
166 }
167 
doRequest()168 bool UDPTracker::doRequest()
169 {
170     Out(SYS_TRK | LOG_NOTICE) << "Doing tracker request to url : " << url << endl;
171     if (!resolved) {
172         todo |= ANNOUNCE_REQUEST;
173         net::AddressResolver::resolve(url.host(), url.port(80), this, SLOT(onResolverResults(net::AddressResolver *)));
174     } else if (connection_id == 0) {
175         todo |= ANNOUNCE_REQUEST;
176         failures = 0;
177         sendConnect();
178     } else {
179         sendAnnounce();
180     }
181 
182     status = TRACKER_ANNOUNCING;
183     requestPending();
184     return true;
185 }
186 
scrape()187 void UDPTracker::scrape()
188 {
189     Out(SYS_TRK | LOG_NOTICE) << "Doing scrape request to url : " << url << endl;
190     if (!resolved) {
191         todo |= SCRAPE_REQUEST;
192         net::AddressResolver::resolve(url.host(), url.port(80), this, SLOT(onResolverResults(net::AddressResolver *)));
193     } else if (connection_id == 0) {
194         todo |= SCRAPE_REQUEST;
195         failures = 0;
196         sendConnect();
197     } else {
198         sendScrape();
199     }
200 }
201 
scrapeReceived(Int32 tid,const Uint8 * buf,Uint32 size)202 void UDPTracker::scrapeReceived(Int32 tid, const Uint8 *buf, Uint32 size)
203 {
204     /*
205     0               32-bit integer  action  2
206     4               32-bit integer  transaction_id
207     8 + 12 * n      32-bit integer  seeders
208     12 + 12 * n     32-bit integer  completed
209     16 + 12 * n     32-bit integer  leechers
210     8 + 12 * N
211     */
212     if (tid != scrape_transaction_id || size < 20)
213         return;
214 
215     seeders = ReadInt32(buf, 8);
216     total_downloaded = ReadInt32(buf, 12);
217     leechers = ReadInt32(buf, 16);
218     Out(SYS_TRK | LOG_DEBUG) << "Scrape : leechers = " << leechers << ", seeders = " << seeders << ", downloaded = " << total_downloaded << endl;
219 }
220 
sendConnect()221 void UDPTracker::sendConnect()
222 {
223     transaction_id = socket->newTransactionID();
224     socket->sendConnect(transaction_id, address);
225     int tn = 1;
226     for (int i = 0; i < failures; i++)
227         tn *= 2;
228     time_out = false;
229     conn_timer.start(60000 * tn);
230 }
231 
sendAnnounce()232 void UDPTracker::sendAnnounce()
233 {
234     todo &= ~ANNOUNCE_REQUEST;
235     //  Out(SYS_TRK|LOG_NOTICE) << "UDPTracker::sendAnnounce()" << endl;
236     transaction_id = socket->newTransactionID();
237     /*
238     0  64-bit integer  connection_id
239     8  32-bit integer  action  1
240     12  32-bit integer  transaction_id
241     16  20-byte string  info_hash
242     36  20-byte string  peer_id
243     56  64-bit integer  downloaded
244     64  64-bit integer  left
245     72  64-bit integer  uploaded
246     80  32-bit integer  event
247     84  32-bit integer  IP address  0
248     88  32-bit integer  key
249     92  32-bit integer  num_want  -1
250     96  16-bit integer  port
251     98
252     */
253 
254     Uint32 ev = event;
255     Uint16 port = ServerInterface::getPort();
256     Uint8 buf[98];
257     WriteInt64(buf, 0, connection_id);
258     WriteInt32(buf, 8, UDPTrackerSocket::ANNOUNCE);
259     WriteInt32(buf, 12, transaction_id);
260     const SHA1Hash &info_hash = tds->infoHash();
261     memcpy(buf + 16, info_hash.getData(), 20);
262     memcpy(buf + 36, peer_id.data(), 20);
263     WriteInt64(buf, 56, bytesDownloaded());
264     if (ev == COMPLETED)
265         WriteInt64(buf, 64, 0);
266     else
267         WriteInt64(buf, 64, tds->bytesLeft());
268     WriteInt64(buf, 72, bytesUploaded());
269     WriteInt32(buf, 80, ev);
270     QString cip = Tracker::getCustomIP();
271     if (cip.isNull()) {
272         WriteUint32(buf, 84, 0);
273     } else {
274         net::Address addr(cip, 999);
275         WriteUint32(buf, 84, addr.toIPv4Address());
276     }
277     WriteUint32(buf, 88, key);
278     if (ev != STOPPED)
279         WriteInt32(buf, 92, 100);
280     else
281         WriteInt32(buf, 92, 0);
282     WriteUint16(buf, 96, port);
283 
284     socket->sendAnnounce(transaction_id, buf, address);
285 }
286 
sendScrape()287 void UDPTracker::sendScrape()
288 {
289     todo &= ~SCRAPE_REQUEST;
290     /*
291     0               64-bit integer  connection_id
292     8               32-bit integer  action  2
293     12              32-bit integer  transaction_id
294     16 + 20 * n     20-byte string  info_hash
295     16 + 20 * N
296     */
297     scrape_transaction_id = socket->newTransactionID();
298     Uint8 buf[36];
299     WriteInt64(buf, 0, connection_id);
300     WriteInt32(buf, 8, UDPTrackerSocket::SCRAPE);
301     WriteInt32(buf, 12, scrape_transaction_id);
302     const SHA1Hash &info_hash = tds->infoHash();
303     memcpy(buf + 16, info_hash.getData(), 20);
304 
305     socket->sendScrape(scrape_transaction_id, buf, address);
306 }
307 
onConnTimeout()308 void UDPTracker::onConnTimeout()
309 {
310     time_out = true;
311     if (connection_id) {
312         connection_id = 0;
313         failures++;
314         if (event != STOPPED)
315             onError(transaction_id, i18n("Timeout contacting tracker %1", url.toDisplayString()));
316         else {
317             status = TRACKER_IDLE;
318             stopDone();
319         }
320     } else {
321         failures++;
322         onError(transaction_id, i18n("Timeout contacting tracker %1", url.toDisplayString()));
323     }
324 }
325 
onResolverResults(net::AddressResolver * ar)326 void UDPTracker::onResolverResults(net::AddressResolver *ar)
327 {
328     if (ar->succeeded()) {
329         address = ar->address();
330         resolved = true;
331         // continue doing request
332         if (connection_id == 0) {
333             failures = 0;
334             sendConnect();
335         } else {
336             if (todo & ANNOUNCE_REQUEST)
337                 sendAnnounce();
338             if (todo & SCRAPE_REQUEST)
339                 sendScrape();
340         }
341     } else {
342         failures++;
343         failed(i18n("Unable to resolve hostname %1", url.host()));
344     }
345 }
346 
347 }
348