Coverage Report

Created: 2026-03-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libtorrent/src/udp_tracker_connection.cpp
Line
Count
Source
1
/*
2
3
Copyright (c) 2015, Mikhail Titov
4
Copyright (c) 2004-2020, Arvid Norberg
5
Copyright (c) 2016-2018, 2020, Alden Torres
6
Copyright (c) 2016, Pavel Pimenov
7
Copyright (c) 2016-2017, Steven Siloti
8
All rights reserved.
9
10
Redistribution and use in source and binary forms, with or without
11
modification, are permitted provided that the following conditions
12
are met:
13
14
    * Redistributions of source code must retain the above copyright
15
      notice, this list of conditions and the following disclaimer.
16
    * Redistributions in binary form must reproduce the above copyright
17
      notice, this list of conditions and the following disclaimer in
18
      the documentation and/or other materials provided with the distribution.
19
    * Neither the name of the author nor the names of its
20
      contributors may be used to endorse or promote products derived
21
      from this software without specific prior written permission.
22
23
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
POSSIBILITY OF SUCH DAMAGE.
34
35
*/
36
37
#include <cctype>
38
#include <functional>
39
#include <tuple>
40
41
#include "libtorrent/parse_url.hpp"
42
#include "libtorrent/udp_tracker_connection.hpp"
43
#include "libtorrent/hex.hpp"
44
#include "libtorrent/random.hpp"
45
#include "libtorrent/aux_/session_settings.hpp"
46
#include "libtorrent/aux_/resolver_interface.hpp"
47
#include "libtorrent/ip_filter.hpp"
48
#include "libtorrent/aux_/time.hpp"
49
#include "libtorrent/aux_/io.hpp"
50
#include "libtorrent/aux_/ip_helpers.hpp" // for is_v6
51
#include "libtorrent/peer.hpp"
52
#include "libtorrent/error_code.hpp"
53
54
#ifndef TORRENT_DISABLE_LOGGING
55
#include "libtorrent/socket_io.hpp"
56
#endif
57
58
namespace libtorrent {
59
60
  std::map<address, udp_tracker_connection::connection_cache_entry>
61
    udp_tracker_connection::m_connection_cache;
62
63
  std::mutex udp_tracker_connection::m_cache_mutex;
64
65
  udp_tracker_connection::udp_tracker_connection(
66
    io_context& ios
67
    , tracker_manager& man
68
    , tracker_request const& req
69
    , std::weak_ptr<request_callback> c)
70
0
    : tracker_connection(man, req, ios, std::move(c))
71
0
    , m_transaction_id(0)
72
0
    , m_attempts(0)
73
0
    , m_state(action_t::error)
74
0
    , m_abort(false)
75
0
  {
76
0
    update_transaction_id();
77
0
  }
78
79
  void udp_tracker_connection::start()
80
0
  {
81
    // TODO: 2 support authentication here. tracker_req().auth
82
0
    std::string hostname;
83
0
    std::string protocol;
84
0
    int port;
85
0
    error_code ec;
86
87
0
    std::tie(protocol, std::ignore, hostname, port, std::ignore)
88
0
      = parse_url_components(tracker_req().url, ec);
89
0
    if (port == -1) port = protocol == "http" ? 80 : 443;
90
91
0
    if (ec)
92
0
    {
93
0
      tracker_connection::fail(ec, operation_t::parse_address);
94
0
      return;
95
0
    }
96
97
0
    aux::session_settings const& settings = m_man.settings();
98
99
0
    int const proxy_type = settings.get_int(settings_pack::proxy_type);
100
101
0
    if (settings.get_bool(settings_pack::proxy_hostnames)
102
0
      && (proxy_type == settings_pack::socks5
103
0
        || proxy_type == settings_pack::socks5_pw))
104
0
    {
105
0
      m_hostname = hostname;
106
0
      m_target.port(std::uint16_t(port));
107
0
      start_announce();
108
0
    }
109
0
    else
110
0
    {
111
0
      using namespace std::placeholders;
112
0
      ADD_OUTSTANDING_ASYNC("udp_tracker_connection::name_lookup");
113
      // when stopping, pass in the cache-only flag, because we
114
      // don't want to get stuck on DNS lookups when shutting down
115
0
      m_man.host_resolver().async_resolve(hostname
116
0
        , (tracker_req().event == event_t::stopped
117
0
          ? aux::resolver_interface::cache_only : aux::resolver_flags{})
118
0
          | aux::resolver_interface::abort_on_shutdown
119
0
        , std::bind(&udp_tracker_connection::name_lookup
120
0
          , shared_from_this(), _1, _2, port));
121
122
#ifndef TORRENT_DISABLE_LOGGING
123
      std::shared_ptr<request_callback> cb = requester();
124
      if (cb) cb->debug_log("*** UDP_TRACKER [ initiating name lookup: \"%s\" ]"
125
        , hostname.c_str());
126
#endif
127
0
    }
128
129
0
    set_timeout(tracker_req().event == event_t::stopped
130
0
      ? settings.get_int(settings_pack::stop_tracker_timeout)
131
0
      : settings.get_int(settings_pack::tracker_completion_timeout)
132
0
      , settings.get_int(settings_pack::tracker_receive_timeout));
133
0
  }
134
135
  void udp_tracker_connection::fail(error_code const& ec, operation_t const op
136
    , char const* msg, seconds32 const interval, seconds32 const min_interval)
137
0
  {
138
    // m_target failed. remove it from the endpoint list
139
0
    auto const i = std::find(m_endpoints.begin()
140
0
      , m_endpoints.end(), make_tcp(m_target));
141
142
0
    if (i != m_endpoints.end()) m_endpoints.erase(i);
143
144
    // if that was the last one, or the listen socket was closed
145
    // fail the whole announce
146
0
    if (m_endpoints.empty() || !tracker_req().outgoing_socket)
147
0
    {
148
0
      tracker_connection::fail(ec, op, msg, interval, min_interval);
149
0
      return;
150
0
    }
151
152
#ifndef TORRENT_DISABLE_LOGGING
153
    std::shared_ptr<request_callback> cb = requester();
154
    if (cb && cb->should_log())
155
    {
156
      cb->debug_log(R"(*** UDP_TRACKER [ host: "%s" ip: "%s" | ERROR: "%s" ])"
157
        , m_hostname.c_str(), print_endpoint(m_target).c_str(), ec.message().c_str());
158
    }
159
#endif
160
161
    // pick another target endpoint and try again
162
0
    m_target = make_udp(m_endpoints.front());
163
164
#ifndef TORRENT_DISABLE_LOGGING
165
    if (cb && cb->should_log())
166
    {
167
      cb->debug_log(R"(*** UDP_TRACKER trying next IP [ host: "%s" ip: "%s" ])"
168
        , m_hostname.c_str(), print_endpoint(m_target).c_str());
169
    }
170
#endif
171
0
    post(get_executor(), std::bind(
172
0
      &udp_tracker_connection::start_announce, shared_from_this()));
173
174
0
    aux::session_settings const& settings = m_man.settings();
175
0
    set_timeout(tracker_req().event == event_t::stopped
176
0
      ? settings.get_int(settings_pack::stop_tracker_timeout)
177
0
      : settings.get_int(settings_pack::tracker_completion_timeout)
178
0
      , settings.get_int(settings_pack::tracker_receive_timeout));
179
0
  }
180
181
  void udp_tracker_connection::name_lookup(error_code const& error
182
    , std::vector<address> const& addresses, int port)
183
0
  {
184
0
    COMPLETE_ASYNC("udp_tracker_connection::name_lookup");
185
0
    if (m_abort) return;
186
0
    if (error == boost::asio::error::operation_aborted) return;
187
0
    if (error || addresses.empty())
188
0
    {
189
0
      fail(error, operation_t::hostname_lookup);
190
0
      return;
191
0
    }
192
193
0
    std::shared_ptr<request_callback> cb = requester();
194
#ifndef TORRENT_DISABLE_LOGGING
195
    if (cb) cb->debug_log("*** UDP_TRACKER [ name lookup successful ]");
196
#endif
197
0
    if (cancelled())
198
0
    {
199
0
      fail(error_code(errors::torrent_aborted), operation_t::hostname_lookup);
200
0
      return;
201
0
    }
202
203
0
    restart_read_timeout();
204
205
0
    if (!tracker_req().outgoing_socket)
206
0
    {
207
0
      fail(error_code(errors::invalid_listen_socket), operation_t::hostname_lookup);
208
0
      return;
209
0
    }
210
211
0
    auto const listen_socket = bind_socket();
212
213
    // filter all endpoints we cannot reach from this listen socket, which may
214
    // be all of them, in which case we should not announce this listen socket
215
    // to this tracker
216
0
    for (auto const& addr : addresses)
217
0
    {
218
0
      if (!listen_socket.can_route(addr)) continue;
219
0
      m_endpoints.emplace_back(addr, std::uint16_t(port));
220
0
    }
221
222
0
    if (m_endpoints.empty())
223
0
    {
224
0
      fail(lt::errors::announce_skipped, operation_t::hostname_lookup);
225
0
      return;
226
0
    }
227
228
0
    if (tracker_req().filter)
229
0
    {
230
      // remove endpoints that are filtered by the IP filter
231
0
      for (auto k = m_endpoints.begin(); k != m_endpoints.end();)
232
0
      {
233
0
        if (tracker_req().filter->access(k->address()) == ip_filter::blocked)
234
0
        {
235
#ifndef TORRENT_DISABLE_LOGGING
236
          if (cb && cb->should_log())
237
          {
238
            cb->debug_log("*** UDP_TRACKER [ IP blocked by filter: %s ]"
239
              , print_address(k->address()).c_str());
240
          }
241
#endif
242
0
          k = m_endpoints.erase(k);
243
0
        }
244
0
        else
245
0
          ++k;
246
0
      }
247
0
    }
248
249
    // if all endpoints were filtered by the IP filter, we can't connect
250
0
    if (m_endpoints.empty())
251
0
    {
252
0
      fail(error_code(errors::banned_by_ip_filter), operation_t::hostname_lookup);
253
0
      return;
254
0
    }
255
256
0
    m_target = make_udp(m_endpoints.front());
257
258
0
    start_announce();
259
0
  }
260
261
  void udp_tracker_connection::start_announce()
262
0
  {
263
0
    std::unique_lock<std::mutex> l(m_cache_mutex);
264
0
    auto const cc = m_connection_cache.find(m_target.address());
265
0
    if (cc != m_connection_cache.end())
266
0
    {
267
      // we found a cached entry! Now, we can only
268
      // use if if it hasn't expired
269
0
      if (aux::time_now() < cc->second.expires)
270
0
      {
271
0
        if (tracker_req().kind & tracker_request::scrape_request)
272
0
          send_udp_scrape();
273
0
        else
274
0
          send_udp_announce();
275
0
        return;
276
0
      }
277
      // if it expired, remove it from the cache
278
0
      m_connection_cache.erase(cc);
279
0
    }
280
0
    l.unlock();
281
282
0
    send_udp_connect();
283
0
  }
284
285
  void udp_tracker_connection::on_timeout(error_code const& ec)
286
0
  {
287
0
    if (ec)
288
0
    {
289
0
      fail(ec, operation_t::timer);
290
0
      return;
291
0
    }
292
293
#ifndef TORRENT_DISABLE_LOGGING
294
    std::shared_ptr<request_callback> cb = requester();
295
    if (cb) cb->debug_log("*** UDP_TRACKER [ timed out url: %s ]", tracker_req().url.c_str());
296
#endif
297
0
    fail(error_code(errors::timed_out), operation_t::timer);
298
0
  }
299
300
  void udp_tracker_connection::close()
301
0
  {
302
0
    cancel();
303
0
    m_man.remove_request(this);
304
0
  }
305
306
  bool udp_tracker_connection::on_receive_hostname(string_view const hostname
307
    , span<char const> buf)
308
0
  {
309
0
    TORRENT_UNUSED(hostname);
310
    // just ignore the hostname this came from, pretend that
311
    // it's from the same endpoint we sent it to (i.e. the same
312
    // port). We have so many other ways of confirming this packet
313
    // comes from the tracker anyway, so it's not a big deal
314
0
    return on_receive(m_target, buf);
315
0
  }
316
317
  bool udp_tracker_connection::on_receive(udp::endpoint const& ep
318
    , span<char const> const buf)
319
0
  {
320
#ifndef TORRENT_DISABLE_LOGGING
321
    std::shared_ptr<request_callback> cb = requester();
322
#endif
323
324
    // ignore responses before we've sent any requests
325
0
    if (m_state == action_t::error)
326
0
    {
327
#ifndef TORRENT_DISABLE_LOGGING
328
      if (cb) cb->debug_log("<== UDP_TRACKER [ m_action == error ]");
329
#endif
330
0
      return false;
331
0
    }
332
333
0
    if (m_abort)
334
0
    {
335
#ifndef TORRENT_DISABLE_LOGGING
336
      if (cb) cb->debug_log("<== UDP_TRACKER [ aborted]");
337
#endif
338
0
      return false;
339
0
    }
340
341
    // ignore packet not sent from the tracker
342
    // if m_target is inaddr_any, it suggests that we
343
    // sent the packet through a proxy only knowing
344
    // the hostname, in which case this packet might be for us
345
0
    if (!m_target.address().is_unspecified() && m_target != ep)
346
0
    {
347
#ifndef TORRENT_DISABLE_LOGGING
348
      if (cb && cb->should_log())
349
      {
350
        cb->debug_log("<== UDP_TRACKER [ unexpected source IP: %s "
351
          "expected: %s ]"
352
          , print_endpoint(ep).c_str()
353
          , print_endpoint(m_target).c_str());
354
      }
355
#endif
356
0
      return false;
357
0
    }
358
359
#ifndef TORRENT_DISABLE_LOGGING
360
    if (cb) cb->debug_log("<== UDP_TRACKER_PACKET [ size: %d ]"
361
      , int(buf.size()));
362
#endif
363
364
    // ignore packets smaller than 8 bytes
365
0
    if (buf.size() < 8) return false;
366
367
0
    span<const char> ptr = buf;
368
0
    auto const action = static_cast<action_t>(aux::read_int32(ptr));
369
0
    std::uint32_t const transaction = aux::read_uint32(ptr);
370
371
#ifndef TORRENT_DISABLE_LOGGING
372
    if (cb) cb->debug_log("*** UDP_TRACKER_PACKET [ action: %d ]"
373
      , static_cast<int>(action));
374
#endif
375
376
    // ignore packets with incorrect transaction id
377
0
    if (m_transaction_id != transaction)
378
0
    {
379
#ifndef TORRENT_DISABLE_LOGGING
380
    if (cb) cb->debug_log("*** UDP_TRACKER_PACKET [ tid: %x ]", transaction);
381
#endif
382
0
      return false;
383
0
    }
384
385
0
    if (action == action_t::error)
386
0
    {
387
0
      fail(error_code(errors::tracker_failure), operation_t::bittorrent
388
0
        , std::string(buf.data(), static_cast<std::size_t>(buf.size())).c_str());
389
0
      return true;
390
0
    }
391
392
    // ignore packets that's not a response to our message
393
0
    if (action != m_state)
394
0
    {
395
#ifndef TORRENT_DISABLE_LOGGING
396
      if (cb) cb->debug_log("*** UDP_TRACKER_PACKET [ unexpected action: %d "
397
        " expected: %d ]", static_cast<int>(action), static_cast<int>(m_state));
398
#endif
399
0
      return false;
400
0
    }
401
402
0
    restart_read_timeout();
403
404
#ifndef TORRENT_DISABLE_LOGGING
405
    if (cb)
406
      cb->debug_log("*** UDP_TRACKER_RESPONSE [ tid: %x ]", transaction);
407
#endif
408
409
0
    switch (m_state)
410
0
    {
411
0
      case action_t::connect:
412
0
        return on_connect_response(buf);
413
0
      case action_t::announce:
414
0
        return on_announce_response(buf);
415
0
      case action_t::scrape:
416
0
        return on_scrape_response(buf);
417
0
      case action_t::error:
418
0
        return false;
419
0
    }
420
0
    return false;
421
0
  }
422
423
  void udp_tracker_connection::update_transaction_id()
424
0
  {
425
    // don't use 0, because that has special meaning (uninitialized)
426
0
    std::uint32_t const new_tid = random(0xfffffffe) + 1;
427
428
0
    if (m_transaction_id != 0)
429
0
      m_man.update_transaction_id(shared_from_this(), new_tid);
430
0
    m_transaction_id = new_tid;
431
0
  }
432
433
  bool udp_tracker_connection::on_connect_response(span<char const> buf)
434
0
  {
435
    // ignore packets smaller than 16 bytes
436
0
    if (buf.size() < 16) return false;
437
438
0
    restart_read_timeout();
439
440
    // skip header
441
0
    buf = buf.subspan(8);
442
443
    // reset transaction
444
0
    update_transaction_id();
445
0
    std::int64_t const connection_id = aux::read_int64(buf);
446
447
0
    std::lock_guard<std::mutex> l(m_cache_mutex);
448
0
    connection_cache_entry& cce = m_connection_cache[m_target.address()];
449
0
    cce.connection_id = connection_id;
450
0
    cce.expires = aux::time_now() + seconds(m_man.settings().get_int(settings_pack::udp_tracker_token_expiry));
451
452
0
    if (!(tracker_req().kind & tracker_request::scrape_request))
453
0
      send_udp_announce();
454
0
    else if (tracker_req().kind & tracker_request::scrape_request)
455
0
      send_udp_scrape();
456
0
    return true;
457
0
  }
458
459
  void udp_tracker_connection::send_udp_connect()
460
0
  {
461
#ifndef TORRENT_DISABLE_LOGGING
462
    std::shared_ptr<request_callback> cb = requester();
463
#endif
464
465
0
    if (m_abort)
466
0
    {
467
#ifndef TORRENT_DISABLE_LOGGING
468
      if (cb) cb->debug_log("==> UDP_TRACKER_CONNECT [ skipped, m_abort ]");
469
#endif
470
0
      return;
471
0
    }
472
473
0
    std::size_t const connect_packet_size = 16;
474
0
    std::array<char, connect_packet_size> buf;
475
0
    span<char> view = buf;
476
477
0
    TORRENT_ASSERT(m_transaction_id != 0);
478
479
0
    aux::write_uint32(0x417, view);
480
0
    aux::write_uint32(0x27101980, view); // connection_id
481
0
    aux::write_int32(action_t::connect, view); // action (connect)
482
0
    aux::write_int32(m_transaction_id, view); // transaction_id
483
0
    TORRENT_ASSERT(view.empty());
484
485
0
    error_code ec;
486
0
    if (!m_hostname.empty())
487
0
    {
488
0
      m_man.send_hostname(bind_socket(), m_hostname.c_str()
489
0
        , m_target.port(), buf, ec
490
0
        , udp_socket::tracker_connection);
491
0
    }
492
0
    else
493
0
    {
494
0
      m_man.send(bind_socket(), m_target, buf, ec
495
0
        , udp_socket::tracker_connection);
496
0
    }
497
498
0
    ++m_attempts;
499
0
    if (ec)
500
0
    {
501
#ifndef TORRENT_DISABLE_LOGGING
502
      if (cb && cb->should_log())
503
      {
504
        cb->debug_log("==> UDP_TRACKER_CONNECT [ failed: %s ]"
505
          , ec.message().c_str());
506
      }
507
#endif
508
0
      fail(ec, operation_t::sock_write);
509
0
      return;
510
0
    }
511
512
#ifndef TORRENT_DISABLE_LOGGING
513
    if (cb && cb->should_log())
514
    {
515
      cb->debug_log("==> UDP_TRACKER_CONNECT [ to: %s ih: %s ]"
516
        , m_hostname.empty()
517
          ? print_endpoint(m_target).c_str()
518
          : (m_hostname + ":" + to_string(m_target.port()).data()).c_str()
519
        , aux::to_hex(tracker_req().info_hash).c_str());
520
    }
521
#endif
522
523
0
    m_state = action_t::connect;
524
0
    sent_bytes(16 + 28); // assuming UDP/IP header
525
0
  }
526
527
  void udp_tracker_connection::send_udp_scrape()
528
0
  {
529
0
    if (m_abort) return;
530
531
0
    auto const i = m_connection_cache.find(m_target.address());
532
    // this isn't really supposed to happen
533
0
    TORRENT_ASSERT(i != m_connection_cache.end());
534
0
    if (i == m_connection_cache.end()) return;
535
536
0
    char buf[8 + 4 + 4 + 20];
537
0
    span<char> view = buf;
538
539
0
    aux::write_int64(i->second.connection_id, view); // connection_id
540
0
    aux::write_int32(action_t::scrape, view); // action (scrape)
541
0
    aux::write_int32(m_transaction_id, view); // transaction_id
542
    // info_hash
543
0
    std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
544
0
      , view.data());
545
0
#if TORRENT_USE_ASSERTS
546
0
    TORRENT_ASSERT(view.size() == 20);
547
0
#endif
548
549
0
    error_code ec;
550
0
    if (!m_hostname.empty())
551
0
    {
552
0
      m_man.send_hostname(bind_socket(), m_hostname.c_str(), m_target.port()
553
0
        , buf, ec, udp_socket::tracker_connection);
554
0
    }
555
0
    else
556
0
    {
557
0
      m_man.send(bind_socket(), m_target, buf, ec
558
0
        , udp_socket::tracker_connection);
559
0
    }
560
0
    m_state = action_t::scrape;
561
0
    sent_bytes(sizeof(buf) + 28); // assuming UDP/IP header
562
0
    ++m_attempts;
563
0
    if (ec)
564
0
    {
565
0
      fail(ec, operation_t::sock_write);
566
0
      return;
567
0
    }
568
0
  }
569
570
  bool udp_tracker_connection::on_announce_response(span<char const> buf)
571
0
  {
572
0
    if (buf.size() < 20) return false;
573
574
0
    buf = buf.subspan(8);
575
0
    restart_read_timeout();
576
577
0
    tracker_response resp;
578
579
0
    resp.interval = seconds32(aux::read_int32(buf));
580
0
    resp.min_interval = seconds32(60);
581
0
    resp.incomplete = aux::read_int32(buf);
582
0
    resp.complete = aux::read_int32(buf);
583
584
0
    int const ip_stride = aux::is_v6(m_target) ? 18 : 6;
585
0
    auto const num_peers = buf.size() / ip_stride;
586
0
    if (buf.size() % ip_stride != 0)
587
0
    {
588
0
      fail(error_code(errors::invalid_tracker_response_length), operation_t::bittorrent);
589
0
      return false;
590
0
    }
591
592
0
    std::shared_ptr<request_callback> cb = requester();
593
#ifndef TORRENT_DISABLE_LOGGING
594
    if (cb)
595
    {
596
      cb->debug_log("<== UDP_TRACKER_RESPONSE [ url: %s ]", tracker_req().url.c_str());
597
    }
598
#endif
599
600
0
    if (!cb)
601
0
    {
602
0
      close();
603
0
      return true;
604
0
    }
605
606
0
    if (aux::is_v6(m_target))
607
0
    {
608
0
      resp.peers6.reserve(static_cast<std::size_t>(num_peers));
609
0
      for (int i = 0; i < num_peers; ++i)
610
0
      {
611
0
        ipv6_peer_entry e{};
612
0
        std::memcpy(e.ip.data(), buf.data(), 16);
613
0
        buf = buf.subspan(16);
614
0
        e.port = aux::read_uint16(buf);
615
0
        resp.peers6.push_back(e);
616
0
      }
617
0
    }
618
0
    else
619
0
    {
620
0
      resp.peers4.reserve(static_cast<std::size_t>(num_peers));
621
0
      for (int i = 0; i < num_peers; ++i)
622
0
      {
623
0
        ipv4_peer_entry e{};
624
0
        std::memcpy(e.ip.data(), buf.data(), 4);
625
0
        buf = buf.subspan(4);
626
0
        e.port = aux::read_uint16(buf);
627
0
        resp.peers4.push_back(e);
628
0
      }
629
0
    }
630
631
    // TODO: why is this a linked list?
632
0
    std::list<address> ip_list;
633
0
    std::transform(m_endpoints.begin(), m_endpoints.end(), std::back_inserter(ip_list)
634
0
      , [](tcp::endpoint const& ep) { return ep.address(); } );
635
636
0
    cb->tracker_response(tracker_req(), m_target.address(), ip_list, resp);
637
638
0
    close();
639
0
    return true;
640
0
  }
641
642
  bool udp_tracker_connection::on_scrape_response(span<char const> buf)
643
0
  {
644
0
    restart_read_timeout();
645
0
    auto const action = static_cast<action_t>(aux::read_int32(buf));
646
0
    std::uint32_t const transaction = aux::read_uint32(buf);
647
648
0
    if (transaction != m_transaction_id)
649
0
    {
650
0
      fail(error_code(errors::invalid_tracker_transaction_id), operation_t::bittorrent);
651
0
      return false;
652
0
    }
653
654
0
    if (action == action_t::error)
655
0
    {
656
0
      fail(error_code(errors::tracker_failure), operation_t::bittorrent
657
0
        , std::string(buf.data(), static_cast<std::size_t>(buf.size())).c_str());
658
0
      return true;
659
0
    }
660
661
0
    if (action != action_t::scrape)
662
0
    {
663
0
      fail(error_code(errors::invalid_tracker_action), operation_t::bittorrent);
664
0
      return true;
665
0
    }
666
667
0
    if (buf.size() < 12)
668
0
    {
669
0
      fail(error_code(errors::invalid_tracker_response_length), operation_t::bittorrent);
670
0
      return true;
671
0
    }
672
673
0
    int const complete = aux::read_int32(buf);
674
0
    int const downloaded = aux::read_int32(buf);
675
0
    int const incomplete = aux::read_int32(buf);
676
677
0
    std::shared_ptr<request_callback> cb = requester();
678
0
    if (!cb)
679
0
    {
680
0
      close();
681
0
      return true;
682
0
    }
683
684
0
    cb->tracker_scrape_response(tracker_req()
685
0
      , complete, incomplete, downloaded, -1);
686
687
0
    close();
688
0
    return true;
689
0
  }
690
691
  void udp_tracker_connection::send_udp_announce()
692
0
  {
693
0
    if (m_abort) return;
694
695
0
    char buf[800];
696
0
    span<char> out = buf;
697
698
0
    tracker_request const& req = tracker_req();
699
0
    aux::session_settings const& settings = m_man.settings();
700
701
0
    auto const i = m_connection_cache.find(m_target.address());
702
    // this isn't really supposed to happen
703
0
    TORRENT_ASSERT(i != m_connection_cache.end());
704
0
    if (i == m_connection_cache.end()) return;
705
706
0
    aux::write_int64(i->second.connection_id, out); // connection_id
707
0
    aux::write_int32(action_t::announce, out); // action (announce)
708
0
    aux::write_int32(m_transaction_id, out); // transaction_id
709
0
    std::copy(req.info_hash.begin(), req.info_hash.end(), out.data()); // info_hash
710
0
    out = out.subspan(20);
711
0
    std::copy(req.pid.begin(), req.pid.end(), out.data()); // peer_id
712
0
    out = out.subspan(20);
713
0
    aux::write_int64(req.downloaded, out); // downloaded
714
0
    aux::write_int64(req.left, out); // left
715
0
    aux::write_int64(req.uploaded, out); // uploaded
716
0
    aux::write_int32(req.event, out); // event
717
    // ip address
718
0
    address_v4 announce_ip;
719
720
0
    if (!settings.get_bool(settings_pack::anonymous_mode)
721
0
      && !settings.get_str(settings_pack::announce_ip).empty())
722
0
    {
723
0
      error_code ec;
724
0
      address ip = make_address(settings.get_str(settings_pack::announce_ip).c_str(), ec);
725
0
      if (!ec && ip.is_v4()) announce_ip = ip.to_v4();
726
0
    }
727
0
    aux::write_uint32(announce_ip.to_uint(), out);
728
0
    aux::write_int32(req.key, out); // key
729
0
    aux::write_int32(req.num_want, out); // num_want
730
0
    aux::write_uint16(req.listen_port, out); // port
731
732
0
    std::string request_string;
733
0
    error_code ec;
734
0
    using std::ignore;
735
0
    std::tie(ignore, ignore, ignore, ignore, request_string)
736
0
      = parse_url_components(req.url, ec);
737
0
    if (ec) request_string.clear();
738
739
0
    if (!request_string.empty())
740
0
    {
741
0
      std::size_t str_len = std::min(request_string.size(), std::size_t(255));
742
0
      request_string.resize(str_len);
743
744
0
      aux::write_uint8(2, out);
745
0
      aux::write_uint8(str_len, out);
746
0
      aux::write_string(request_string, out);
747
0
    }
748
749
#ifndef TORRENT_DISABLE_LOGGING
750
    std::shared_ptr<request_callback> cb = requester();
751
    if (cb && cb->should_log())
752
    {
753
      cb->debug_log("==> UDP_TRACKER_ANNOUNCE [%s]", aux::to_hex(req.info_hash).c_str());
754
    }
755
#endif
756
757
0
    if (!m_hostname.empty())
758
0
    {
759
0
      m_man.send_hostname(bind_socket(), m_hostname.c_str()
760
0
        , m_target.port(), {buf, int(sizeof(buf)) - out.size()}, ec
761
0
        , udp_socket::tracker_connection);
762
0
    }
763
0
    else
764
0
    {
765
0
      m_man.send(bind_socket(), m_target, {buf, int(sizeof(buf)) - out.size()}, ec
766
0
        , udp_socket::tracker_connection);
767
0
    }
768
0
    m_state = action_t::announce;
769
0
    sent_bytes(int(sizeof(buf)) - int(out.size()) + 28); // assuming UDP/IP header
770
0
    ++m_attempts;
771
0
    if (ec)
772
0
    {
773
0
      fail(ec, operation_t::sock_write);
774
0
      return;
775
0
    }
776
0
  }
777
778
}