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